Problems with UIView animation - iphone

I am performing animation on my view. But I am facing few problems with that. I have to button's startAnimation and Stop Animation. For performing animation on my imageview I am using following code in startAnimation button's action:
UIViewAnimationOptions option = UIViewAnimationOptionRepeat + UIViewAnimationOptionAutoreverse;
[UIView animateWithDuration:2.5 delay:0.0 options:option
animations:^{
CGAffineTransform scale = CGAffineTransformMakeScale(2.0, 2.0);
CGAffineTransform translate = CGAffineTransformMakeTranslation(-50.0, -100.0);
CGAffineTransform mix = CGAffineTransformConcat(scale, translate);
imv.transform = mix;
}
completion:^(BOOL finished) {
}
];
This is working.
Now the problems I am facing are:
How to stop this animation on my stopAnimation button's action?
If ImageView is animation and I enter in background after that I again come in foreground ImageView sticks there and do not animates.
How to solve these issues?

On your stopAnimation button you would need to remove animations from the UIView's layer. First you must import Quartzcore.framework.
#import <QuartzCore/QuartzCore.h>
[yourView.layer removeAllAnimations];
As for your other issue of pausing your animation while going into the background and coming back to foreground, theres no way to 'pause' an animation. Your best bet would be to manually handle that situation by restarting your animation.

To stop the animation you can use
#import <QuartzCore/QuartzCore.h>
...
[imv.layer removeAllAnimations];
As for making an animation restart it is a complex problem and the answer depends on what you want the application to do when it restores. One possible answer would be to keep track of where you are animating the ImageView to and then in ApplicationDidEnterBackground you could cancel all the animations and simply move it there. Then when you restored it would be in the correct location.
If you actually want to continue the animations I would have a read of some other Stack Overflow answers and see if that helps.
Restoring animation where it left off when app resumes from background
iOS, Restarting animation when coming out of the background

For further reference, for the second part of your response you have to restore the matrix to the identity before doing anything:
imv.transform = CGAffineTransformIdentity;

Related

iOS UIView block animations stop actually animating

I've got a weird issue with using UIView block-based animations. My app contains an assortment of images in scroll views and, after a while of using the app on the device, all animations in UIView animation blocks (such as the one below) stop animating. The animation is processed (in the example code below, the pageView does move) but this change isn't animated and happens instantly.
[UIView animateWithDuration:0.5 animations:^
{
self.pageView.center = CGPointMake(self.view.frame.size.width/2, 704.0/2);
self.pageView.transform = CGAffineTransformIdentity;
}
completion:^(BOOL finished)
{
NSLog(#"complete");
}];
Has anyone else experienced similar behaviour? I'm using an iPad on 5.1 and am wondering if it could be down to iOS version?
Thanks,
Michael
Check your memory usage. I am seeing the same thing you are -- eventually all of the animations stopped working. The animations didn't even run for me, and completion blocks weren't firing.
I found that I was holding on to a number of UIImageViews that weren't visible anymore because I wanted to re-show them later. Removing them and freeing up the UIImage made the problem go away. I now need to figure out how I'm going to get back the images but at least the animations work as expected.
When you're using transforms, animations can have a really unpredictable behavior if you use them separately. To avoid this, you ought to concatenate all your transforms into a single one via CGAffineTransformConcat and animate that single transform.
Try using some animation options and see if that helps?
For example here I'm letting the user interact and letting views redraw themselves during an animation :
[UIView animateWithDuration:0.5
delay:0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAllowAnimatedContent
animations:^ {
self.pageView.center = CGPointMake(self.view.frame.size.width/2, 704.0/2);
self.pageView.transform = CGAffineTransformIdentity;
} completion:^ (BOOL finished) {
} ];

How to obtain changes to view position when animating frame?

I need to update a view continuously depending on another view's position while it's moving across the screen. I tried using KVO on frame, but it seems to trigger only at the beginning of the animation. Is there a recommended way of doing this?
You want to have a look at the Core Animation presentation layer which should tell you the position during the animation.
I would add a repeatable timer and make something like:
[self updateView:_view
usingPosition:[_anotherView.presentationLayer position]];
(Don't you know _anotherView's animation in advance? Maybe then you can setup _view animation directly?)
Why not just set both animations for both view at the same time?
[UIImageView animateWithDuration:aDuration
delay:0
options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
animations:^(void) {
view1.center = somePosition;
view2.center = someOtherPosition;
} completion:NULL];
They will move at the same time and with the option : UIViewAnimationOptionBeginFromCurrentState if you start an other animation before this one is finished the views will start at the point they were stopped.
But if it's not what you are looking for, can you update your question with precision on how view1 is moving.

Is it possible to change UIView's "center" property inside the overriden touchesEnded method and redraw the view?

I want to implement a simple animation based on UIView's center property. I have a simple view and I can drag it (UIView touchesMoved is overriden). The animation should fade slowly like the view is moved under it's own inertia for some time after the user releases it. But for now I want simply to move the view after touch ends. Here is the code I have in touchesEnded:
int i;
for (i=1;i<4;i++)
{
self.center = CGPointMake(10*i, 12*i);
[self setNeedsDisplay];
usleep(100000);
}
The problem is when I run this, the code is executed nicely but "UIView" changes to late. I changed usleep time and other parameters but the result is the same. It looks like all the "pending changes" in the view are performed only after the overriden touchesEnded is finished.
Is this the right way of implementing such user interface feature or should I look for some other approaches?
Thanks in advance.
If you know the final positions you want your view center to have you could do this with an animation:
[UIView animateWithDuration:20
delay:0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
youView.center = CGPointMake(newCenterX, newCenterY);
}
completion:^(BOOL finished){
}];
If that code is being run inside of touchesEnded you are blocking the main thread and that is why the animation happens all at once when its done. You will need run this loop in the background to update the view over time. When you update the UI remember to always call back to the main thread.
Some Threading Options:
performSelectorInBackground:withObject:
performSelectorOnMainThread:withObject:waitUntilDone:
Grand Central Dispatch
Threading

Always animate UIView to user's tap location

I have a UIView that I want to animate to the position where the user's finger currently is.
So, when the touch begins, it has to animate to the tap location.
When the touch moves, it has to adjust its destination to the new location.
When the touch ends, it has to finish the animation to the last tap location.
I tried several things but none worked out. I tried creating a new animation with beginsFromCurrentState in touchesMoved, but that didn't work too.
It seems you're complicating this a little bit. If you are implementing touchesMoved, you are wanting a drag. If you are more interested in a tap, then touchesEnded is where you want to implement this. Either way, you just need to get the location in view and update your UIView's center based upon that location. If you wrap the change to the center value in a UIView animation block, it will animate to the position as it updates.
If you are using iOS 3.2 or later, you can use gesture recognizers which makes this pretty trivial:
// In viewDidLoad or some such
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(viewWasTapped:)];
[[self view] addGestureRecognizer:tapRecognizer];
Then declare your action selector:
- (void)viewWasTapped:(UITapGestureRecognizer*)recognizer
{
CGPoint location = [recognizer locationInView:[self view]];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0f]; // take a second to animate
[viewToMove setCenter:location];
[UIView commitAnimations];
}
This will animate the view from one location to another. This is referred to as implicit animation. Using Core Animation classes such CAKeyframeAnimation or CABasciAnimation would be explicit animation.
Need a few more details for this.. But are you sure you are using touchesBegan, touchesMoved and touchesEnded from the appropriate view (ie not the view you want to move)? Also make sure the userInteractionEnabled = YES. Try logging the touches from touchesBegan to make sure you are receiving the touches.
Or you might want to just check out Apples MoveMe sample code at https://developer.apple.com/library/ios/#samplecode/MoveMe/Introduction/Intro.html where they have solved all those problems for you.

smoothly stopping a core animation rotation

How do you stop the rotation of a custom drawn CALayer on the iPhone?
This
CATransform3D pausetransform = ((CALayer *)[layer presentationLayer]).transform;
[layer removeAllAnimations];
layer.transform = pausetransform;
stops the animation, then immediately rotates the layer back a little bit. Probably because after the pausetransform value is set the animation continues for a short while.
Setting the layer.transform value in the animation's - (void) animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)finishednormally delegate method briefly displays the layer in the starting position of the animation before it rotates to the correct position.
It turns out the UIActionSheet I was setting up when calling [layer removeAllAnimations] took so long to display it was postponing the actual stopping of the animation. By moving the setup of the UIActionSheet to the - (void) animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)finishednormally delegate method the rotation now stops smoothly.
Another way is to call
[view.layer removeAnimationForKey:#"name of your animation"];
However, in both removes, depending on how you set up the animation, the animation stops at the next iteration of the animation. If, let's say, you were spinning in 10 degree increments, the animation would stop before the next 10 degree increment.