animating a button with delays - iPhone - iphone

I'm trying to have a button move to a co-ordinates, pause, move to another co-orinates, pause, then move again. the process should then repeat infinitely. what I have right now just moves the last step.
this is what I have so far ('mover' is the UIButton name):
- (void) firstAnimation {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:5];
[UIView setAnimationRepeatCount:-1];
[UIView setAnimationRepeatAutoreverses:NO];
CGPoint pos = mover.center;
pos.y = 200.f;
pos.x = 169.f;
mover.center = pos;
[NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(firstAnimation:) userInfo:nil repeats:NO];
pos.y = 100.f;
pos.x = 179.f;
mover.center = pos;
[NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(firstAnimation:) userInfo:nil repeats:NO];
pos.y = 160.f;
pos.x = 129.f;
mover.center = pos;
[UIView commitAnimations];
}
thanks for any help

You don't need to use timers, just set the animation delegate to self and implement the animationfinished method.
See my answer here:
animations on infinite loop

If you're shipping for iOS4 exclusively, I thoroughly recommend using blocks and the following method:
[UIView animateWithDuration:kAnimationDuration
delay:kAnimationDelay
options:UIViewAnimationCurveEaseInOut
animations:^ {
// your animations here.
}
completion:^(BOOL finished) {
// what you want to do upon animation completion here.
}];
Note that in the completion block you can just as well cue up another animation. In fact, you could store the three animation blocks as block variables and then simply pass them in to the above method to be executed, one after another, until the third completes. Then just restart the process!
Blocks are your friends.

You would be better suited to use CoreAnimation keyframes and setting repeatCount = HUGE_VALF to loop forever

Related

get coordinates of animated UIImageview

I am animating an UIImageview in horizontal position for this purpose i have used the below code i have used the NSTimer
timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
-(void)onTimer
{
[UIView animateWithDuration:10.0f animations:^{
//Moving_Cloud is an image view
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
}];
}
now the problem i am facing is i need to get the coordinates of the "Moving_Cloud" after the animate duration
please help me
Thanks in advance.
Abhijit Chaudhari from the comment in my previous post I understand that what you want is not the position "after the animate duration" but instead the position during the animation.
If I still didn't get it right please clarify your question. (Or buy me an new brain)
-(void) animateMe(){
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
[UIView animateWithDuration:10.0f animations:^{
//Moving_Cloud is an image view
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
}];
}
-(void)onTimer:(id)sender{
NSLog(#"Currently in x=%f", [[ddddd.layer presentationLayer] frame].origin.x);
NSLog(#"Currently in y=%f", [[ddddd.layer presentationLayer] frame].origin.y);
}
[UIView animateWithDuration:10.0f animations:^{
Moving_Cloud.frame = CGRectMake(200.0f, 150.0f, Moving_Cloud.frame.size.width, Moving_Cloud.frame.size.height);
} completion:^(BOOL finished){
CGPoint newPost = Moving_Cloud.frame.origin;
CGFloat xPos = newPost.x;
CGFloat yPos = newPost.y;
// do stuff ?
}];
At the end of your animation the block "completion:" will be trigger.
Normally your image should be in x = 200, y = 150.
Be aware that those coordinates are relative to it superview (the view wrapping Moving_Cloud view).
Note:
By convention I recommend changing "Moving_Cloud" to "movingCloud".
Instance class start in lower cap in objective-C.
Also don't use _ but a capital letter instead.

Start animate UIView before complete?

I'm using [UIView animateWithDuration:...] for animate sequence of UIImageView views. Like this:
[UIView animateWithDuration:1.0 animations:^{
imageView.frame = newImageRectPosition;
}completion:^(BOOL finished){
//animate next UIImageView
}];
I need animate 'next UIImageView' not on completion. I need animate 'next UIImageView' on the middle of previous animation, not on completion. Is it possible to do so?
You can setup two UIView animation blocks, one which has a delay of half the duration of the first animation:
[UIView animateWithDuration:1.0
animations:^{ ... }
completion:^(BOOL finished){ ... }
];
[UIView animateWithDuration:1.0
delay:0.5
options:UIViewAnimationCurveLinear
animations:^{ ... }
completion:^(BOOL finished) { ... }
];
There are many options you can use to achieve the effect you're after. One which comes to mind is the use of timers.
Use an NSTimer with a firing interval half of that of your animation, and get the timer to fire off another animation. As long as the two animations don't interfere with each other, you should be ok.
An example would be as so:
NSTimer* timer;
// Modify to your uses if so required (i.e. repeating, more than 2 animations etc...)
timer = [NSTimer scheduledTimerWithTimeInterval:animationTime/2 target:self selector:#selector(runAnimation) userInfo:nil repeats:NO];
[UIView animateWithDuration:animationTime animations:^{
imageView.frame = newImageRectPosition;
} completion:nil];
- (void)runAnimation
{
// 2nd animation required
[UIView animateWithDuration:animationTime animations:^{
imageView.frame = newImageRectPosition;
} completion:nil];
}
With a timer, this could scale up if you needed to do more than two animations, and it all holds together if you need to change the animation time later on.

Erratic behavior with NSTimers and NSRunLoops

I am attempting to have a UIImageView (a picture of a finger) animate from right to left, using CGAffineTransformMakeTranslation(). This animation will repeat until the user performs a swipe, moving the user along in a tutorial. All of this is already working swimmingly as follows:
[UIView animateWithDuration:1.0 animations:^ {
self.finger.alpha = 1.0;
}completion:^(BOOL finished) {
CGAffineTransform originalTransform = self.finger.transform;
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^ {
self.finger.transform = CGAffineTransformMakeTranslation(-200, 0);
self.finger.alpha = 0.0;
}completion:^(BOOL finished) {
self.finger.transform = originalTransform;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(repeatSwipeAnimation1) userInfo:nil repeats:YES];
self.swipeTimerForFinger1 = timer;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.swipeTimerForFinger1 forMode:NSDefaultRunLoopMode];
[self.swipeTimerForFinger1 fire];
}];
}];
And the selector:
-(void)repeatSwipeAnimation1 {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^ {
self.finger.alpha = 1.0;
}completion:^(BOOL finished) {
CGAffineTransform originalTransform = self.finger.transform;
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^ {
self.finger.transform = CGAffineTransformMakeTranslation(-200, 0);
self.finger.alpha = 0.0;
}completion:^(BOOL finished) {
self.finger.transform = originalTransform;
}];
}];
}
The finger animates and translates beautifully.
The issue comes when I want to do this with a different finger with a different timer. I have the same exact code, however it is a different finger and different selector for the timer.
What happens is that the timer's selector will not translate the UIImageView, and (more scary) the timer will not invalidate when I call the method to invalidate. Upon debugging, I see that the the 2nd timer is calling the 2nd selector, but just not behaving (e.g. not translating, and fading in the 2nd finger too rapidly).
What I am assuming is that I need to somehow turn off the NSRunLoop when I first call it? This is the first time working with NSRunLoop so I apologize for my ignorance. Any help is very much appricated.
Well, you certainly have a block retain cycle going on. You need to use either the __block or __weak specifier. See Blocks and Variables. Your problem may be related to a memory issue.
Make sure you invalidate the first timer when it is done.
For safety, you may also want to reset the transform on your UIImageView before attempting to transform it. You can do that like so:
finger.transform = CGAffineTransformIdentity;

How to stop an looping animation and call it again with new value

i currently have a default looping animation which fade in and out once the view appear, when background processing of data are completed it will stop the current animation an load new animation, in terms of new picture.
i can't seen to stop the animation using [self.view.layer removeAllAnimations]; [self.imageViewBottom.layer removeAllAnimations]; [self.imageViewTop.layer removeAllAnimations];
-(void)nextAnimation:(float)previousWidth {
//picture loop
imageViewTop.image = imageViewBottom.image;
imageViewBottom.image = [imageArray objectAtIndex:[imageArray count] - 1];
[imageArray insertObject:imageViewBottom.image atIndex:0];
[imageArray removeLastObject];
imageViewTop.alpha = 1.0;
imageViewBottom.alpha = 0.0;
[UIView animateWithDuration:4.0
animations:^{
imageViewTop.alpha = 0.0;
imageViewBottom.alpha = 1.0;
}
completion:^(BOOL completed){
[self nextAnimation:stringsize.width];
}
];
-(void)foundSetup
{
//[imageViewTop removeFromSuperview];
//[imageViewBottom removeFromSuperview];
//[buttonCaption removeFromSuperview];
[self.view.layer removeAllAnimations];
[self.imageViewBottom.layer removeAllAnimations];
[self.imageViewTop.layer removeAllAnimations];
//[self.imageArray removeAllObjects];
//self.imageArray = foundImageArray;
}
[UIView animateWithDuration:4.0
animations:^{
imageViewTop.alpha = 0.0;
imageViewBottom.alpha = 1.0;
}
completion:^(BOOL completed){
[self nextAnimation:stringsize.width];
}
Here, in your completion block, you will call the next animation method again regardless of the animation being cancelled or not.
Inside your completion block, only call nextAnimation if completed == YES:
completion:^(BOOL completed){
if (completed)
[self nextAnimation:stringsize.width];
}
This, coupled with removing animations from the views that are actually being animated as suggested by Till, should do it for you.
You can go with timer as well create a timer object and call this function through that object once ur background processing gets over invalidate the object [boothTimer1 invalidate] and call again. In one of my application i have done for similar scenario u mentioned. Declare boothTimer1 in .h
NSTimer* boothTimer1; self.boothTimer1 = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:#selector(ur function) userInfo:nil repeats:NO];
Now u can invalidate the timer when ur background processing is completed.

Objective-C Block stops UIGestureRecognizer

Here is my problem.
I use blocks to display two labels on screen one by one (one READY label appears, then disappears, and GO! label appears, then disappears).
I also have a gesture recognizer to detect if the user is dragging a view.
When my app is displaying the labels, gesture recognizers stop calling their callback.
Here is my code:
[UIView animateWithDuration:1 animations:^{
readyLabel.alpha = 0;
}completion:^(BOOL finished){
[readyLabel removeFromSuperview];
[self.view addSubview:goLabel];
[UIView animateWithDuration:1 animations:^{
goLabel.alpha = 0;
}completion:^(BOOL finished){
self.ball = [[Ball alloc] init];
[self.view addSubview:self.ball];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:#selector(moveBall:) userInfo:nil repeats:YES];
}];
}];
What I tried so far is using NSThread to execute my blocks outside of the main thread, but without result.
I could use performSelector:withObject:afterDelay to avoid the problem for my labels (display one label after the first animation has finished) but I think it's a bit dirty.
Why does my gesture recognizer stop calling his callback? Are blocks responsible for this?
This is because block animations disable user interaction. You should use animateWithDuration:delay:options:animations:completion: and specify UIViewAnimationOptionAllowUserInteraction in options.
This is because, when UIView is animating using blocks it prevents UI interaction. To avoid this behaviour you must use the UIViewAnimationOptionAllowUserInteraction option:
[UIView animateWithDuration:1
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
readyLabel.alpha = 0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
goLabel.alpha = 0;
}
completion:^(BOOL finished){
self.ball = [[Ball alloc] init];
[self.view addSubview:self.ball];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:#selector(moveBall:) userInfo:nil repeats:YES];
}
];
}
];