I have read apple documentation: http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6-SW1
For iOS3.0 and earlier, using this:
Method1:
[UIView beginAnimations:#"ShowHideView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
...
The new one, iOS4, can do this:
Method2:
[UIView animateWithDuration:1.0 animations:^{
firstView.alpha = 0.0;
secondView.alpha = 1.0;
}];
Q1. What I want to know is, in earlier method, they have this "ShowHideView" in beginAnimations, is that method a built-in one?
Q2. Are there any others built-in methods for animation in beginAnimations? If yes, where can I find all those methods?
Q3. And lastly, can I use those methods in latter method(method2) call?
You can get all the answers to your questions in the UIView Class Reference.
Q1: ShowHideView, as you have it, is not a method at all. It is simply an "application-supplied identifier for the animations". In reality, you don't need it. When I use this method, I just use NULL instead of supplying an identifier there.
Q2: You don't set animations in the beginAnimations:context: call. You even illustrate it there by calling setAnimationCurve. You can set the animations from this typedef.
Q3: Again, you don't declare animation types in animateWithDuration:animations: call either. Utilize setAnimationCurve: to do that in that example as well.
Blocks have the benefit of being able to nest the animations (in a queue almost) using the [UIView animateWithDuration:animations:completion:] selector. You can nest another call to this method inside the finished block like so:
[UIView animateWithDuration:1.0 animations:^{
// your first animations
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
// more animations
} completion:^(BOOL finished) {
// ... maybe even more
}]
}]
I abuse this in my code and find it much easier than using the beginAnimations/commitAnimations code. And, with iOS 5 approaching, the days of needing to support iOS 3.x are slipping away.
Related
I have a subView that I want to toggle between hidden and not hidden by a button. How do I fade in the subview and fade it out? For now it just appears immediately and disappear immediately when I toggle the button.
I am wondering what is the easiest way to do this animation.
Thanks
On iOS 4.0+ Apple recommends you use their new, block-based animation methods. Using these, the code would look something like this:
[UIView animateWithDuration:2.0
animations:^{myView.alpha = 0.0;}];
The properties you are animating go inside the block (the ^{...} part). Blocks are sort of like functions, so you can put multiple lines of code inside of them, if you want to animate multiple properties. For example:
[UIView animateWithDuration:0.2
animations:^{
view.alpha = 0.0;
view.backgroundColor = [UIColor redColor];
}];
If you need to perform an action after the animation is complete, use the +animateWithDuration:animations:completion: method (which also uses blocks), for example:
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];
For more info, check out the UIView Class Reference 'Animations' section and 'Animating Views with Blocks' section.
This is the old pre-4.0 way:
http://objcolumnist.com/2009/07/18/simple-uiview-based-animations-on-the-iphone/
... which has the advantage of being conceptually simple and easy to implement.
float alpha = 1.0; // or 0.0 if it's already visible and you want to fade out
[UIView beginAnimations:#"" context:NULL];
[UIView setAnimationDuration:2.0]; // seconds, not ms. guess how i know?
[mySubView setAlpha:alpha];
[UIView commitAnimations];
One simple question:
This is an example of an old fashion animation:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[base setTransform:rotate];
[base setCenter:newCenter];
[UIView commitAnimations];
this can be written like
[UIView animateWithDuration:0.5 animations:^{
[base setTransform:rotate];
[base setCenter:newCenter];
}];
is there any advantage in rewriting the animation using this new form?
There should be some kind of gain, or Apple would not make this new function.
What do you guys say?
Apple made the change not for performance, but because blocks are an easier way to express this kind of thing. Previously you'd have to use selectors to be triggered when an animation finished, etc.
So - why to use animateWithDuration: because blocks save time, make code cleaner, and are just generally very useful.
And why to use beginAnimation: because you want to support versions of iOS prior to 4.0, where that code isn't available. Apple still need to provide both methods because they need to remain backwards compatible - but the documentation strongly recommends you use the blocks version of methods where available and appropriate.
I think animateWithDuration is newer and look better. I use it more than beginAnimation. It is more clear code. beginAnimation use when you need compatible for iOS version less than 4.0.
But in some case, beginAnimation has more advantage, make easier when you write a function with a parameter animated. Example:
- (void)moveSomethingWithAnimated:(BOOL)animated {
// Do other task 1
if( animated ) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2];
someView.frame = newFrame;
otherView.frame = newFrame;
}
if( animated ) {
[UIView commitAnimations];
}
// Do other task 2
}
Instead of:
- (void)moveSomethingWithAnimated:(BOOL)animated {
// Do other task 1
if( animated ) {
[UIView animateWithDuration:0.2 animations:^{
someView.frame = newFrame;
otherView.frame = newFrame;
}];
}
else {
// duplicate code, or you have to write another function for these two line bellow
someView.frame = newFrame;
otherView.frame = newFrame;
}
// Do other task 2
}
Hi
I have looked without success for the answer to this.
Am trying to flip views on iphone app. Rather than using the usual iOS3 methods I want to use block methods to animate the transition.
Can anyone suggest a snippet of code to help please?
I tried the animateWithDuration method suggested above, and it didn't work. I couldn't get it working until I used the following:
[UIView transitionFromView:viewOld
toView:viewNew
duration:.75
options:UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationCurveEaseIn
completion:^(BOOL finished)
{
// cleanup viewOld
}
];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
// Exchange the views here
[view1 removeFromSuperview];
[mySuperview addSubview:view2];
}
completion:NULL];
It appears to me these two class methods are not interchangeable. I have a subview of UIView with the following code in the touchesBegan method:
if (!highlightView) {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Highlight"]];
self.highlightView = tempImageView;
[tempImageView release];
[self addSubview:highlightView];
}
highlightView.alpha = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
highlightView.alpha = 1.0;
[UIView commitAnimations];
When I touch the Button, the highlight fades in, like you would expect. When I touch up immediately (before the animation is finished), my touchesEnded gets called. This is the behavior I want.
But now, I've become a big fan of blocks and try to use them wherever possible. So I replaced the UIView animation code with this:
[UIView animateWithDuration:0.2 animations:^{
highlightView.alpha = 1.0;
}];
Results: the highlight still fades in as expected, but if I touch up before the animation is finished, my touchesEnded does not get called. If I touch up after the animation is finished, my touchesEnded does get called. What's going on here?
The new animation blocks in iOS 4 by default disable user interaction. You can pass in an option to allow views to respond to touches during animation using bit flags in conjunction with the animateWithDuration:delay:options:animations:completion method of UIView as such:
UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:0.2 delay:0.0 options:options animations:^
{
highlightView.alpha = 1.0;
} completion:nil];
Documentation
One more thing is that Appple doesn't recommend to use [UIView beginAnimations:context:], you can find it in beginAnimations docs
Use of this method is discouraged in iOS 4.0 and later. You should use
the block-based animation methods to specify your animations instead.
Probably Apple can mark old methods as deprecated in the future releases and won't support them, so using block-based methods is really more preferable way for performing animation.
I have connected the two methods below to separate buttons in my UI but have noticed that after pressing the "VERSION 1" button that I could not press the button again until the animation duration within the method had ended. My understanding was that the animation uses its own thread so as not to block the main application.
// VERSION 1
-(IBAction)fadeUsingBlock {
NSLog(#"V1: Clicked ...");
[myLabel setAlpha:1.0];
[UIView animateWithDuration:1.5 animations:^{
[myLabel setAlpha:0.0];
}];
}
The older style version (below) does allow the button to be repressed before the animation timer ends, simply resetting the timer to start again. Should these both work the same, am I missing something or has there been a change in operation between 3.2 and 4?
// VERSION 2
-(IBAction)fadeUsingOld {
NSLog(#"V2: Clicked ...");
[myLabel setAlpha:1.0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[myLabel setAlpha:0.0];
[UIView commitAnimations];
}
Cheers gary
Animating with blocks doesn't block the main thread. I think the behavior you're seeing is because, by default, user interaction is disabled duration animation with the new block calls. You can override this by passing UIViewAnimationOptionAllowUserInteraction (calling animationWithDuration:delay:options:animations:completion), like this:
-(IBAction) fadeUsingBlock {
NSLog(#"V1: Clicked ...");
[myLabel setAlpha:1.0];
[UIView animateWithDuration:1.5
delay:0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
[myLabel setAlpha:0.0];
}
completion:nil];
}
For animateWithDuration:, the class reference doesn't say anything about threading, so I am not sure.
For beginAnimations:context: and commitAnimation:, yeah, they run in a separate thread
UIView class Reference.
Some of the property changes to view objects can be animated—for example, setting the frame, bounds, center, and transform properties. If you change these properties in an animation block, the changes from the current state to the new state are animated. Invoke the beginAnimations:context: class method to begin an animation block, set the properties you want animated, and then invoke the commitAnimations class method to end an animation block. The animations are run in a separate thread and begin when the application returns to the run loop. Other animation class methods allow you to control the start time, duration, delay, and curve of the animations within the block.