I am trying to implement a game using the iPhone OS 4.0 (iOS4?) SDK. In the previous versions of the SDK, I've been using the [UIView beginAnimations:context:] and [UIView commitAnimations] to create some animations. However, when I look at the documentation of the functions in 4.0, I see this comment.
Use of this method is discouraged in
iPhone OS 4.0 and later. You should
use the block-based animation methods
instead.
You can find it here:
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/commitAnimations
My question is, what are block-based animations in iPhone OS 4.0? I though that the beginAnimations:context: and commitAnimations functions were used to create animation blocks..
I have posted an example in my blog:
CGPoint originalCenter = icon.center;
[UIView animateWithDuration:2.0
animations:^{
CGPoint center = icon.center;
center.y += 60;
icon.center = center;
}
completion:^(BOOL finished){
[UIView animateWithDuration:2.0
animations:^{
icon.center = originalCenter;
}
completion:^(BOOL finished){
;
}];
}];
The above code will animate a UIImageView* (icon) in a 2-second animation. Once completed, another animation will move the icon back to it’s original position.
If you follow that link and scroll up a bit, you will see animate methods new to ios4.
animateWithDuration:animations:
animateWithDuration:animations:completion:
animateWithDuration:delay:options:animations:completion:
There are also some related transition methods. For each of these, the animations argument is a block object:
animations
A block object containing
the changes to commit to the views.
This is where you programmatically
change any animatable properties of
the views in your view hierarchy. This
block takes no parameters and has no
return value. This parameter must not
be NULL.
Block objects are part of Concurrent Programming
Here's a very simple example. The code just fades out an UIView and hides it after the animation is done:
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
bgDisplay.alpha = 0.0;
}
completion:^(BOOL finished) {
bgDisplay.hidden = YES;
}];
or in different formatting:
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^ {
bgDisplay.alpha = 0.0;
} completion:^(BOOL finished) {
bgDisplay.hidden = YES;
}];
Related
In my viewcontroller i am using animation for changing the frame of UIButton and UIView, going from portrait to landscape user can see views growing but problem is animation is leaking everywhere and showing everything coming from different sides.
Here is the code
[UIView beginAnimations:Nil context:Nil];
[UIView setanimationDuration:1];
[view1 setFrame:CGRectMake(100,100,200,300)];
[UIView commitAnimations];
Thanks
Please elaborate more on what "leaking everywhere" means, and does it make a difference if you use block animation:
[UIView animateWithDuration:1.0 delay:0.0 options:nil animations:^{
[view1 setFrame:CGRectMake(100,100,200,300)];
}completion:^(BOOL done){
if (done) {
NSLog(#"animation complete");
}
}];
According to Apple's documentation:
In iOS 4 and later, use the block-based animation methods.
(Recommended)
I've searched loads of SO stuff and in Apple's references, but still unable to manage my problem.
What I have:
A screen with 2 UIImageViews and 2 UIButtons connected to them
2 kinds of animation:
Scaling up and then down of each image, one after another, only once in viewDidLoad
When a button pressed (a custom button hidden 'inside' of each UIImageView) it triggers animation of appropriate UIImageView–only one, not both–(also scale up, then down).
As I am writing for iOS4+ I'm told to use block based animations!
What I need:
How do I cancel a running animation? I've managed to cancel after all but the last one... :/
Here is my code snippet:
[UIImageView animateWithDuration:2.0
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
isAnimating = YES;
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
}
completion:^(BOOL finished){
if (!finished) return;
//block letter buttons
[self.bigLetterButton setUserInteractionEnabled:YES];
[self.smallLetterButton setUserInteractionEnabled:YES];
//NSLog(#"vieDidLoad animations finished");
}];
}];
}];
}];
Somehow the smallLetter UIImageView is not working properly, because when pressed (through button) bigLetter is canceling animations properly...
EDIT:
I've used this solution, but still having problem with scaling down smallLetter UIImageView - not cancelling at all...
solution
EDIT2: I've added this at the beginning of next/prev methods:
- (void)stopAnimation:(UIImageView*)source {
[UIView animateWithDuration:0.01
delay:0.0
options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
animations:^ {
source.transform = CGAffineTransformIdentity;
}
completion:NULL
];
}
problem stays... :/ no idea how to interrupt last animation for letters in animation chain
You can stop all animations on a view by calling:
[view.layer removeAllAnimations];
(You'll need to import the QuartzCore framework to call methods on view.layer).
If you want to stop a specific animation, not all animations, your best best bet is to use CAAnimations explicitly rather than the UIView animation helper methods, then you will have more granular control and can stop animations explicitly by name.
The Apple Core Animation documentation can be found here:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html
For iOS 10 use UIViewPropertyAnimator to animate.
It provides methods to start, stop and pause UIView animations.
let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
self.view.alpha = 0.0
}
// Call this to start animation.
animator.startAnimation()
// Call this to stop animation.
animator.stopAnimation(true)
I'd add to Nick's answer that to make removeAllAnimations smooth next idea be very handy.
[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[view.layer displayIfNeeded];
} completion:nil];
You can try this (in Swift):
UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)
Note: you can put code between those two calls if necessary, for example:
UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)
I'm keen on the new block animations in iOS 4. That is, the syntax
[UIView animateWithDuration:.25 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
someview.alpha = 0
} completion::^(BOOL finished)
{
focusAndExposureBox.hidden = true;
}];
I have a case where I am using gesture recognizers and animating a view at the end of a gesture. I have a completion handler which sets someview to hidden (for performance reasons I need to do this). Often interaction is blocked due to the hidden property being set. My previous solution is to use the previous style of animation with an animationDidStop handler
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.25];
someview.alpha = 0;
[UIView commitAnimations];
However, I'd like to use the newer style if possible, because it has a cleaner method of performing actions after the animation finishes, and is recommended by Apple. So, currently I am using this hackery:
[UIView animateWithDuration:1 delay:0
options:UIViewAnimationOptionAllowUserInteraction animations:^{
someview.alpha = 0;
} completion:^(BOOL finished) {
[someview performSelector:#selector(setHidden:) withObject:[NSNumber numberWithBool:true] afterDelay:1];
}];
Does anyone know of a way to prevent blocking in this case?
You should be able to avoid the Blocking issue if you're using Gesture Recognizers with delegates, as the delegate function will be invoked independent of the main thread.
I have the following code:
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
imageView.bounds = endBounds;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:0.5 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
imageView.bounds = startBounds;
}
completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
}];
Additionally I have:
[imageView setUserInteractionEnabled:YES];
and a tap gesture recognizer set that will handle the user tapping on imageView. While the first animation is happening, the gesture recognizer fires as I would expect. But if I try and tap imageView during the chained animation from the completion block, nothing happens even though I have set the appropriate option.
Anyone have any thoughts? I've googled and can't find an answer.
When using the new animation blocks, if you want user interaction to be enabled during the animation, you have to set it in the options mask. For example:
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{ myView.alpha = 0.5; }
completion:NULL];
I came up with a solution:
I wrap the UIImageView in a UIView (I subclass UIView) with the same bounds/center point as the image. Then I attach the gesture recognizer to the wrapper, instead of the image. Because the wrapper's bounds rectangle/center point never change for the duration of the animation, it's always available as the target of a gesture.
This works quite well.
-j
Do you see the same behaviour if you use:
+ [UIView setAnimationDidStopSelector:]
instead of using blocks?
I am trying to make a button move in my application without having to implement the cocos2d framework in my application. I am making a data application and dont want to add any other game elements except for a button that moves. Does anyone know how to do this?
To move any object you simply have to give it a new frame by setting
myView.frame = CGRectMake( x, y, width, height );
You can even easily have the phone animate it for you without any added frameworks by wrapping it with [UIView beginAnimation...] blocks.
Here's an example:
[UIView beginAnimations:#"moveButton" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:0.5];
someButton.frame = CGRectMake( newX, newY, newWidth, newHeight );
[UIView commitAnimations];
You can move a view directly using
[theview setFrame:CGRectMake(x,y,w,h)];
or you can use animations to do so a in cooler way (this should be the iOS 4.x Way)
[UIView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionLayoutSubviews
animations:^{ [theview setFrame:CGRectMake(x,y,w,h)]; }
completion:^(BOOL finished){
[self iAmDoneAnimatingNowICanDoSomethingElse]; }];