Animating container view controllers - ios

I have 2 container view controllers on my main screen, one which acts as a global toolbar at the top. This is great most of the time, but I need to animate this off screen, to give more room for the user to see lots of information on the screen. Is this possible? I've been looking at the documentation, but I'm not sure if I need to use the transformation animation, or change the frame/bounds. Any suggestions would be grateful.

You should just be able to change the frame/bounds in a standard UIView animation (block or otherwise). No need to reference the "contained" views.
Update: Here's a block animation example.
[UIView animateWithDuration:1.0f
animations:^{
view1.frame = CGRectMake(blah...);
}
completion:^(BOOL finished){
// do something here if you wish.
}];

Related

iOS Restart animation after switching tab

In this post the author said that we could restart animation after switching tab in viewWillAppear.
I called my startAnimation in both viewWillAppear and viewDidAppear, but still failed.
Below is part of my code.
- (void)startAnimation {
[UIView setAnimationsEnabled:YES];
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat
animations:^(void){
self.foreground.transform = CGAffineTransformMakeTranslation(0.0f, 5.0f);
}
completion:nil];
}
The animation works perfectly when first shown by calling startAnimation in viewDidLoad, but it never works after switching to other tabs.
Neither does it work after the application restarts from the background, even if I've registered an observer of UIApplicationWillEnterForegroundNotification for startAnimation.
Please help me, I'm new to iOS development, thanks very much.
The method viewDidLoad only gets called when your view controller is first loaded.
If you want your animation to run when you return from other view controllers to this one, you should call the animation method in viewWillAppear, not viewDidLoad.
To make the animation go back to it's previous value and then animate again, you would first set your view's transform to identity (setting it to the starting point) and then invoke your animationWithDuration method.
You might find it easier to animate your view's frame.origin or center property rather than changing the transform. Changing the transform gets complicated when you combine translations with rotations, scale changes, etc. Also, the frame property is no longer valid when the transform property is not == the identity transform.

Basic Animation (Swipe to turn)

I am thinking of adding a animation to my Table View. This should work as following: The User swipes over a table view Cell horizontal and the content of the cell turns, so that "the other side of the card" is visible. How could i do that? I have no idea if I e.g. try to do that by making everything by myself with a opengl view in every row, or if i could use CoreAnimation? Are there maybe better ways to do that? How do the professionals realize such animations (e.g. Flipboard)? I don't need source code, a short description or a keyword would help very much!
Apple has build in functionality. I am currently using it and it works great.
Let's say you have 2 views A and B that you want to flip between. The flip animates the entire area of the parent, so if you only want the flip to be all of A, make sure A and its parent are the same size.
Here is what I like to do to flip back and forth:
if(B.superview == nil)
[UIView transitionFromView:A toView:B duration:1.f options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
else
[UIView transitionFromView:B toView:A duration:1.f options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
After the flip, the FromView will be removed from its parent (superview) and the ToView will be added to that parent. You can put the above code in a gesture recognizer for swipe or tap. I only needed tap so I put a clear button inside A and B, and in its button event I called the above code.
I would put a UISwipeGestureRecognizer on your cell and then when swiped use a UIView transition animation. (See UIView Documentation). Should do what you want.

UIViewAnimationOptionTransitionCurlUp

using the following UIView class method on iPad to animate the swapping of different images inside a UIImageView:
[UIView transitionWithView:self.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^{[imageView setImage:foregroundImage];}
completion:nil];
However, the animation does not seem to be taking notice of the current interface orientation. In other words, "up" is always up relative to Portrait orientation. So, for example, if the device is in Landscape Left orientation, the page curls from left to right (rather than "up"). If I'm in Upside Down orientation, the page curls from top to bottom, etc.
Any idea how I can get it to curl "up" relative to the current interface orientation rather than only curling up relative to Portrait orientation?
I encountered the same problem. I've found a workaround but not sure why your code(the same approach I took) didn't work.
My walk-around is to create a wrapper(UIView) for all UI elements in the page to be purled. I've make the wrapper the only subview of the view controller's view and all other views subview of the wrapper. And modify the target to wrapper as below
[UIView transitionWithView:self.wrapperView
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^{[imageView setImage:foregroundImage];}
completion:nil];
In your specific case, if you only need 'imageView' to be curled up, you can try set the target to imageView, namely
[UIView transitionWithView:self.imageView
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^{[imageView setImage:foregroundImage];}
completion:nil];
it worked in my project. So it seems if the animation target is the root view of VC, this problem will occur, otherwise the curling animation works find. Anyone knows why?

pushViewController with scaling animation, that shows background

I have finding way to call pushViewController with scaling animation,
like facebook iPhone app main menu icon click animation.
(new viewController is popup from center, and it scales to original size.)
I searched several way to change animation of pushViewController.
First, I tried this:
viewController.view.transform = CGAffineTransformMakeScale(0.5f, 0.5f);
[UIView animateWithDuration:0.5f animations:^{
viewController.view.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
}];
[self.navigationController pushViewController:viewController animated:NO];
but there is problem,
old viewController is disappeared when animation starts, there's only white background.
If I use CATransition to change animation,
I can show both old & new viewController both,
but there's no scaling animation, only move in, push in, fade in animations.
I want to show both new & old view controller like CATransition animations,
and need the way to implement my custom animation.
Here is my last suggestion, dirty way:
[self.view addSubview:viewController.view];
viewController.view.transform = CGAffineTransformMakeScale(0.5f, 0.5f);
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationCurveEaseInOut
animations:^{
viewController.view.alpha = 1.0f;
viewController.view.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
} completion:^(BOOL finished) {
[self.navigationController pushViewController:viewController animated:NO];
[viewController release];
}];
First, I added new viewController.view as subview, I can show animation with new & old view both.
When animation is ended, pushViewController later.
this way I can implement what I thought,
but I think it is dirty way, and there's remain problem:
Navigation bar items are not change immediately, It is changed after animation ends.
Is there any simple, clear way to implement this animation?
I think it is impossible to do that without change original implentation of pushViewController, should I do subclassing pushViewController?
Thanks to read, and your help.
In answer to the original question, I'm not sure if you consider this an improvement or not, but I think you might be able to include the navigator bar in the view that's being transformed (a) in IB, add a navigationBar to your view being transitioned to, (b) animate the hiding of the root navigation controller's navigation bar before you start your animation (so it slides off as your new view is sliding in), and (c) in your completion block of your animation, hide your new view's added navigation bar and unhide the root navigation controller's navigation bar. Maybe this renders something closer to what you intended, though probably different than you originally conceived. It's not perfect, though. The code, might look something like:
MyViewController *newController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
newController.view.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
[self.navigationController setNavigationBarHidden:YES animated:YES];
[self.view addSubview:newController.view];
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationCurveEaseInOut
animations:^{
newController.view.alpha = 1.0f;
newController.view.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
} completion:^(BOOL finished) {
[newController.view removeFromSuperview];
[self.navigationController pushViewController:newController animated:NO];
[newController.tempBar setHidden:YES];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}];
It's adding a little more "dirt" to your "dirty way", but it might render the effect that you're looking for. You just want to make the temporary navigation bar in your new view to look as much like what the eventual root navigation controller's navigation bar will look like, and the user should be none the wiser. If this still doesn't quite achieve what you're looking for, you can just hide the root navigation controller's bar altogether, and always put your navigation on your views themselves, in which case the effect will be entirely seamless as you transition to your new view.
Alternatively, you could stay with your existing code and just set the title of the current view before you transition, that way it might look like the title change happened up front. But then you probably have to do stuff about resetting it when you return, setting the back button, etc., so it might not be worth it.
As an aside, and this is a little tangential to the original question (so I apologize in advance), but in response to the other suggestion that you shouldn't animate the view controller, but rather only views, I would like to voice a word of caution. Yes, technically that's right, but I'm nervous whether this will encourage people to adopt the bad practice of adding new views by (a) creating a new view controller; (b) animate the adding of that view controller's view to be a subview of the current view; but (c) not doing anything with that new view controller to add it to your view controller hierarchy (such as pushViewController or presentViewController).
If that's what was intended to the other answer, I have to say that I think this is a very bad idea. (If that's not what was intended, then my apologies, but I think it's easy for people to misconstrue the suggestion.) Bottom line, I have recently seen people do things like:
MyViewController *newController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
// do some animation around adding the new view as a subview of your current view
// but neglect to ever invoke pushViewController or presentViewController
[self.view addSubview:newController.view];
This is not recommended for a couple of reasons. First, if it's an ARC project, your view controller will be discarded when newController falls out of scope. (There seem to be a spate of these sorts of questions being posted on SO resulting from exceptions being thrown as people transition to ARC.) Sure, you can fix this by making newController an ivar of your main controller so it won't fall out of scope, but be careful to remember to set it to nil when the main controller is eventually dealloc'ed or as you remove your subview, or else you can get a leak. And if you're in a non-ARC project, it's even easier to leak, so make sure to release the view controller when the subview is removed to prevent leaks.
Second, and probably more importantly, while the above code seems to work (or at least if you make the controller an ivar), but you end up with a disconnect between your hierarchy of your view controllers and that of your views. (In session 102 of WWDC 2011 about a different topic, view controller containment, it includes a lengthy, yet relevant, discussion of the importance of keeping view controller hierarchies and view hierarchies coordinated, e.g. rotation events may not be properly sent to your new view's controller because the controller isn't in the controller hierarchy, so iOS won't know to send them to your controller.) Bottom line, if you use another view controller's view to add as a subview of your current view, it is fragile, is susceptible to breaking on iOS upgrades, and things like rotation events will not be passed to your new view's view controller properly. If you do so, at least be aware that this is not good practice and make your own risk-assessment as to whether you want to do that. It's not necessary to bypass the proper view controller hierarchy, and I personally would like to dissuade people inclined to do so.
Bottom line, if you're transitioning to a view of a different view controller, you really want to stick to pushViewController or presentViewController, and do your animation around the new controller's view (and usually it's nowhere near as complicated as this animation ... generally it's incredibly simple and I've done all sorts of fade and flip animations with much greater ease ... it's the use of the transform that is making this complicated).
Alternative, if you want to animate a new UIView subview and not deal with view controllers at all, just make sure it's not another view controller's view, but rather, for example, a view you create programmatically that uses the same view controller as your originating view. And if you decide to use another view controller's view as a subview of your existing controller, just do so with the knowledge that it's a little fragile and some events may not be transmitted to your new view controller as you expect and it might not be as "future proof" as you may want.
I don't think that animation is done with a view controller. You can just keep the existing view controller. Create a new UIView that is supposed to zoom in. Add that new UIView to the existing view controller and apply animation to it.

ipad page/form modal view's are no longer transparent in 4.2.1

In my app I have been using page and form modal view controllers like the following:
quickTemplateViewer.modalPresentationStyle = UIModalPresentationPageSheet;
quickTemplateViewer.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[parent presentModalViewController:myView animated:YES];
I have an offset close button that hangs over the view on the top left (the view is slightly smaller than the designated modal view size), and it has been working well as the background of hte modal view is partially transparent.
I upgraded to 4.2.1 and suddenly instead of a semi-transparent black background with a drop shadow I have a white background with rounded corners. Is there a new setting to turn it back to transparent?
Thanks
I spent all day searching for a solution on this, and eventually gave up and made my own solution.
Basically what I did was instead of loading my 'modal' with presentModalViewController, I just added a full size view with a black backgroundColor that had 80% opacity so that it shows the view underneath a little dimmed.
Inside of this view, I added the view that I usually loaded with presentModalViewController with the appropiate X & Y coordinates. this way, you mimic the behavior of the UIModalPresentationPageSheet: you get a dimmed background, and the user can't use any UIControl that's underneath.
it's probably not the best implementation, but it's the best I could come up with. Hope something similar works for you guys.
-- UPDATE
Mike asked how did I implement the animations that usually come with the modal. Basically, what I used was a UIView animationTransition:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:
UIViewAnimationTransitionFlipFromLeft forView:anotherView cache:YES];
[mainContainer addSubview:modal.view];
[UIView commitAnimations];

Resources