How to do "pushviewcontroller" animation WITHOUT using pushviewcontroller? - ios

I want to do animation like NavigationController pushviewcontroller's animation.
but I don't have a NavigationController, I don't want to make it.
So I want to ask is it possible to do it's animation in UIViewController? thanks!
oh forgot to say, I'm trying to switch view after clicking button.
Using presentModalViewController now, but I don't like it's animation..

You could animate the origin property of your sub view, make it decreasing along the x axis just after adding it to the main view.
EDIT :
Use something like this :
// retrieve the screen bounds
CGRect sBounds = [[UIScreen mainScreen] bounds];
// the origin point is just on the right of the screen
CGRect newFrame = CGRectMake(sBounds.size.width,
0.0,
sBounds.size.width,
sBounds.size.height);
// set your view frame
[mySecondView setFrame:newFrame];
// add it to the main view
[mainView addSubview:mySecondView];
// then animate your view
[UIView animateWithDuration:0.5 // set the interval you want
animations:^{
mySecondView.frame.origin = sBounds.origin;
}
];

I would use a navigation controller and hide the navigation bar, but as you don't want to do that you can switch between views using [UIView beginAnimantion: #"myAnimation" withContext: nil]; and changing the frame or the origin.

Related

UIViewController changes dimension after modal presentation

I have a UIViewController which is presented using a custom transition, and by design it only fills 90% of the screen's height.
This appears fine, and I've never had any issues with it. Let's call it View A. Now I am trying to present a full screen modal view on top of this, let's call that View B. This appearance works, but when View B is dismissed, View A reappears, but has been expanded to fill the entire bounds of the screen.
Here's the presentation code I'm using:
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
...
// Presentation
const CGFloat viewHeight = (screenBounds.size.height * 0.9);
const CGRect beginFrame = CGRectMake(0, screenBounds.size.height, screenBounds.size.width, viewHeight);
const CGRect finalFrame = CGRectMake(0, (screenBounds.size.height - viewHeight), screenBounds.size.width, viewHeight);
// Dim
self.dimmedView.alpha = 0.0;
[transitionContext.containerView addSubview:self.dimmedView];
[transitionContext.containerView addConstraints:[NSLayoutConstraint allConstraintsFromViewToSuperview:self.dimmedView inset:UIOffsetZero]];
// Prepare
UIView * const toView = toVC.view;
toView.frame = beginFrame;
[transitionContext.containerView addSubview:toView];
// Animate
[UIView animateWithDuration:kAnimationDuration delay:0.0 usingSpringWithDamping:0.8 initialSpringVelocity:0.25 options:0 animations:^{
toView.frame = finalFrame;
self.dimmedView.alpha = 0.6;
self.tabBarController.view.layer.cornerRadius = 8.0;
self.tabBarController.view.transform = CGAffineTransformMakeScale(0.95, 0.95);
} completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
[offshootView removeFromSuperview];
}];
...
}
Has anyone seen this before, and know how to stop the system from resizing View A?
I think the problem is that you modify the size of the view controller's root view, although it is handled by the view controller. The documentation for UIViewController says:
A view controller’s root view is always sized to fit its assigned
space.
Why not add another (fully transparent) view as a child to the root view, where you place all your content? Doing so let's you keep the root view at 100% while changing the new view's size to 90% when you want to. If I understand you correctly this will accomplish the same thing without touching the root view.
For this to work you should set the view controllers Presentation property in the Storyboard attribute inspector to Over Full Screen. If you want to set it by code you set the view controller's .modalPresentationStyle = UIModalPresentationOverFullScreen. By setting this the underlying view controller will stay on screen after you have presented your view controller and continue to be visible where you have transparency in your view.
Documentation for UIViewController
Documentation for UIModalPresentationOverFullScreen

UINavigationBar frame animation not possible?

UINavigationBars within a UINavigationController. . . they don't participate in frame animations. Useful, but exactly not what I want right now. Is there a way to turn this off?
I know I could set the showsNagitationBar property to hidden, and add my own to the view, put am looking at possible alterntives.
What I'm Trying to Achieve:
I've put my UINavigationController into a (screen-sized) container view, and want to slide it across to reveal a side menu. . last time that I did this I had custom push/pop methods on the RootVC, and my own navigation bar - worked fine, though a fair amount of boiler-plate code to set up.
This time I've got the same kind of requirement - main content is push/pop based, and some auxiliary VCs that can be revealed from the side. And so for another approach, and considering that this app's look and feel is very standard, I just included a UINavigationController within the RootVC and expected it to work the same.
However the UINavigationBar stays anchored in place, while the rest of the content within the container view moves.
I am not entirely sure what you are trying to achieve, but when using a navigation controller, the entirety of what you see on screen (your top view controller's view PLUS your navigation bar) is rooted in the Navigation Controller's view.
This means that if you do something like:
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.navigationController.view.frame;
frame.size.width -= 30;
self.navigationController.view.frame = frame;
}];
You will get your view AND the navigation bar to shrink.
EDIT: You can add/remove the sliding-in views to the navigation controller's view where it is appropriate (for example the nav controller is your root view controller, you could do it in your appdelegate's didFinishLaunch: method). The following code would show an entirely red view sliding in from the left. In your case, this view would be the one from your side view controller.
UIView *left = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
left.backgroundColor = [UIColor redColor];
CGRect ff = left.frame;
ff.origin.x = -ff.size.width;
left.frame = ff;
[self.navigationController.view addSubview:left];
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.navigationController.view.frame;
frame.origin.x += 50;
self.navigationController.view.frame = frame;
}];
Is something like this what you were looking for?

Custom transition between UIViewControllers

I've just changed my app from being TabView driven to CollectionView driven, as there are too many sections of my app to be feasible for a TabView. When you start the app you are presented with several items in a CollectionView and selecting any of these items will take you to the relevant section of the app.
In XCode, the collection view lives in its own storyboard and each section of the app has its own storyboard.
In the CollectionView's didSelectItemAtIndexPath, I launch the relevant starboard as follows;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"relevant_storyboard" bundle:nil];
UIViewController* vc = [storyboard instantiateInitialViewController];
[self presentViewController:vc animated:YES completion:nil];
Now, none of the built-in transition animations really suit launching from a CollectionView, so I'd really like a custom effect, such as zoom in. However, I'm struggling to find any decent examples that work for me to create any kind of custom transition. I've tried [UIView transitionFromView], but I don't think that suits transitioning between UIViewControllers. I've tried transitionFromViewController:toViewController: but don't think I have the view hierarchy set up correctly. I've also tried using CATransition without success.
I've thought about doing it with a custom segue but, as my CollectionView is in it's own storyboard and have separate storyboards for each section of my app, I can't see how I can do this. At least not without having all sections of the app inside one storyboard, which would make the storyboard huge and difficult to manage.
So, can anyone give me any code examples or pointers on how I can solve this?
In my app I used a similar effect to zoom in from a thumbnail in a collection view cell to a child view controller that took up the entire screen. You could conceivably do the same thing for a navigation controller push as well.
In my code, I had a scoreView property on the cell subclass that I wanted to zoom up into the full screen. In your case, you may want to use a UIImageView with a screenshot of your new view. Alternatively, you could present the new view controller with a screenshot of the old view controller and then animate from there.
//Instantiate the view controller to be animated in...
//If the cell is not completely inside the collection view's frame, a dissolve animation might be more graceful.
BOOL dissolveAnimation = !CGRectContainsRect(CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height), cellRect);
//Get the frame of the cell in self.view coordinates, then the frame of the thumbnail view
CGRect cellRect = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
cellRect = CGRectOffset(cellRect, 0.0, -self.collectionView.contentOffset.y);
VSScoreCell *scoreCell = (VSScoreCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
CGRect scoreRect = dissolveAnimation ? CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height) : CGRectMake(cellRect.origin.x + scoreCell.scoreView.frame.origin.x, cellRect.origin.y + scoreCell.scoreView.frame.origin.y, scoreCell.scoreView.frame.size.width, scoreCell.scoreView.frame.size.height);
VSScoreView *scoreView = [[VSScoreView alloc] initWithFrame:scoreRect];
//Initialize the view that will be animated up (in this case scoreView)...
if (dissolveAnimation)
scoreView.alpha = 0.0;
[self.view addSubview:scoreView];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
if (dissolveAnimation)
scoreView.alpha = 1.0;
else
scoreView.frame = CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height);
} completion:^(BOOL finished) {
if (finished)
{
//Add scoreDisplayController as a child view controller or present it without animation
[scoreView removeFromSuperview];
}
}];
Of course, the new iOS might make this easier (my lips are sealed), but I hope this is somewhat helpful for your situation!
Have you tried the UIView animation block?
[UIView animationWithDuration:1.0 animation^ {
// do custom animation with the view
}completion:^(BOOL finished) {
if(finished) {
NSLog(#"Finished");
}
}];
It allows you to do custom animations when dealing with UIView(s), and even with UIViewControllers. I use it alot when dealing with custom animation actions.
EDIT:
for example, if you'd like to make the view of the current controller to move up the screen, and the second view controller to slide down in place of it, just do
[UIView animationWithDuration:1.0 animation^ {
// do custom animation with the view
// make sure CoreGraphics.framework is imported
// sliding current view to the top of the screen
self.view.transform = CGAffineTransformMakeTranslation(0,0);
// sliding 2nd view down..
// uncomment the following line, and one of the options for translation
//SecondView *sv = [[SecondView alloc] init];
// just edit the x,y in CGAffineTransformMakeTranslation to set where it will go
//sv.view.transform = CGAffineTransformMakeTranslation(320, 480) // iphone 4
//sv.view.transform = CGAffineTransformMakeTranslation(768, 1024) // ipad 1
}completion:^(BOOL finished) {
if(finished) {
NSLog(#"Finished");
}
}];
Hope this helps!

Present a view with animation

Instead of doing self.view = view; like I am currently I want to present this view with animation. It is not an entire view controller but just a view, I am just replacing the current view with this view on a button click.
Is there anyway to do this animated?
Thanks in advance.
Try something like:
UIView *newView = ...;
// new view is added as a subview somewhere
newView.alpha = 0;
[UIView animateWithDuration:1
animations:^{
newView.alpha = 1;
}];
Which will fade the view in. You could also look at animateWithDuration:delay:options:animations:completion: which provides other animation options. Or transitionFromView:toView:duration:options:completion:.

How to do a horizontal cover segue using storyboards?

There is a vertical cover transition. I have been looking around the web for how to do a horizontal cover with no success. Any suggestions?
There's no horizontal cover transition provided in iOS. You'll have to create your own UIStoryboardSegue subclass and implement your own transition animation.
One way to animate the kind of transition I think you're looking for is something like this (warning: untested code):
// add newView to window
[oldView.window insertSubview:newView aboveSubview:oldView];
// assuming newView and oldView both sized to fill screen,
// position newView just to the right of oldView
newView.center = oldView.center + oldView.frame.size.width;
// slide newView over oldView, then remove oldView
[UIView animateWithDuration:0.3
animations:^{ newView.center = oldView.center; }
completion:^(BOOL finished){ [oldView removeFromSuperview]; }];
When you use a navigation controller and then push and pop views from it the effect is a horizontal cover.
As answered by T.J. above, use a navigation controller and it will default to horizontal cover automatically.

Resources