How to stop this sequence? - ios

i am animating a frame, through this code, which is easily understandable in code, now i am trying to stop this sequence after 20 time means in completion parentheses i need to call that function for 20 times only: how can i do that?
-(void)conveyComplete:(UIView*)v
{
[self convey:v delay:0];
}
-(void)convey:(UIView*)v delay:(int)nDelay
{
[UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
CGRect rPos = v.frame;
NSLog(#"x:%f y:%f vFrame:%f vFrame:%f" , rPos.origin.x,rPos.origin.y,v.frame.origin.x,v.frame.origin.y);
rPos.origin.x -= 5;
rPos.origin.y -=100;
v.frame = rPos;
}
completion: ^(BOOL finished)
{
[self conveyComplete:v];
NSLog(#"I:%i, F:%i",i,f);
}];
}

As your function does only animation, one possible solution is not to call function 20 times, but instead set repeat count of animation with setAnimationRepeatCount: method.
It'll looks something similar to this:
[UIView UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionRepeat | ...)
animations: ^{
// Do your animation stuff
[UIView setAnimationRepeatCount:20];
}
completion:NULL];
But one other aspect that is worth regarding is whether you need to repeat animation 20 times at all. All you do is just stepwise shifting of you view frame. Why not to animate this at once by setting appropriate offsets and animation duration?

i have made a global integer:
int i=1;
-(void)conveyComplete:(UIView*)v{
[self convey:v delay:0];
}
-(void)convey:(UIView*)v delay:(int)nDelay{
[UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
CGRect rPos = v.frame;
i+=1;// then increase +1 every time it runs
NSLog(#"x:%f y:%f vFrame:%f vFrame:%f" , rPos.origin.x,rPos.origin.y,v.frame.origin.x,v.frame.origin.y);
rPos.origin.x -= 5;
rPos.origin.y -=100;
v.frame = rPos;
}
completion: ^(BOOL finished)
{
if(i<20){
[self conveyComplete:v];
}
NSLog(#"I:%i, F:%i",i,f);
}];
}

Related

Show Hide UIView Twice Every 5 Seconds Using NSTimer

I have a UIView added to a view controller. I want to make it blink twice every 5 seconds.
The following code makes the UIView blink on and off every 1 second:
-(void) showHideView{
[UIView animateWithDuration:1
delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.myview.alpha = 0;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1
delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.myview.alpha = 1;
}
completion:nil
];
}
];
}
How can I make the UIView blink twice every 5 seconds? (i.e. a pulse of two blinks)
Since you've flagged this with iOS7, I might suggest keyframe animation:
[UIView animateKeyframesWithDuration:2.5 delay:0.0 options:UIViewKeyframeAnimationOptionRepeat animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
self.myview.alpha = 0.0;
}];
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.25 animations:^{
self.myview.alpha = 1.0;
}];
} completion:nil];
Tweak total duration (how often the cycle repeats), the relative start times (a % of the total duration), and the relative duration (again, a % of the total duration) as you see fit.
Change both of your delays to zero.
Set both durations to 1.25.
Use a timer to call the method every 2.5 seconds.
How do I use NSTimer?
Edit based on comments:
Use this instead:
-(void) showHideView {
if( self.view.alpha == 1.0 ) alpha = 0.0;
else alpha = 1.0;
}
- (void)timerCallback {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.25 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self showHideView];
});
// repeat above code for 2.5, 3.75, 5.0
}
Make your timer call timerCallback every 5 seconds.

UIView animation on completion not working properly

I have a problem using a slider to trigger a series of animations, here's the code:
-(void)slideAlpha:(id)sender{
self.bigPhotoViewA.alpha = self.alphaSlider.value;
if (self.alphaSlider.value == 1){
[UIView animateWithDuration:1
animations:^{
self.alphaSlider.alpha = 0;
} completion:nil
];
[self performSelector:#selector(nextPhotoAnimation) withObject:self afterDelay:5.0 ];
}
}
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
];
}
So, when the slider reaches a value of 1, nextPhotoAnimation is launched after a delay. So far so good. The problem comes inside nextPhotoAnimation. The animations block runs ok, but the completion block runs several times every time nextPhotoAnimation is called. I get the NSLog from 6 to 9 times displayed when nextPhotoAnimation starts, and then I get it again at the right time, after 2 seconds.
I've tried to replicate the problem with simpler code and the animation/completion flow works just fine.
Try this in nextPhotoAnimation,
-(void) nextPhotoAnimation{
self.alphaSlider.value = 0;
[UIView animateWithDuration:2
animations:^{
self.bigPhotoViewA.alpha = 0.0;
self.bigPhotoView.alpha = 0.0;
self.smallPhotoView.center = CGPointMake(startX, startY);
}
completion:^(BOOL finished) {
if (finished) {
NSLog(#"Animation ended");
self.smallPhotoView.image = ((UIImage *)[smallImagesArray objectAtIndex:imageCount]);
}
}
];
}
neither you are using
[UIView beginAnimations:nil context:nil];
nor
[UIView commitAnimations];
Best way is to create a UIView and then use the protocols.call your methods using [self YOURMETHOD]; in the View.
:-)

Rotate(Fixed End) an imageView with Animation Between Two angles

Hi i am developing an application which needs image animation between two angles.ie from 0-90 and then 90-0 degrees after image reaches to 0 degrees ,Animation has to stop.
I am using the following code it is giving animation from 0-90 only, but also i need to get the image to 0 with animation from 90.
[UIView animateWithDuration: 0.5f
delay: 0.0f
options: options
animations: ^{
self.imageToMove.transform = CGAffineTransformRotate(imageToMove.transform, M_PI / 2);
}
completion: ^(BOOL finished) {
if (finished) {
// if flag still set, keep spinning with constant speed
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
}
}
}];
Any help please....
Try this by changeing value of "RADIANS"
#define RADIANS(degrees) ((degrees * M_PI) / 180.0)
//- (void)startWobble
-(IBAction)start:(id)sender
{
itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(-1));
[UIView animateWithDuration:0.15 delay:0.0 options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse)
animations:^ {
itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(1));
}
completion:NULL
];
}
//- (void)stopWobble
-(IBAction)end:(id)sender
{
[UIView animateWithDuration:0.25
delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear)
animations:^ {
itemView.transform = CGAffineTransformIdentity;
}
completion:NULL
];
}

IOS Animation not working with my animation block

Im Trying to make a red square move from top of view to a random position at the bottom of the view and the return to the top again at random position.
The app starts with the following code into [super viewLoad]:
[redSquare setCenter:CGPointMake(25,25)];
(with the red square view set 50 x 50, this starts the app with the redsquare in the top left corner).
The first part of the animation works well - the red square animates to a random position to the bottom of the page. But, it then jumps to a random position to the top without animation.
Please help what I'm doing wrong or any other solutions to help with this simple animation.
-(void)moving{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}];
}
Your completion block simply sets the new position. You aren't animating it back to the top:
Try this, instead
-(void)moving {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion: NULL
}];
}
Edited to add
It's true that sublevels can get confusing, but you can make life simple and less indented if you define the blocks separately from the method.
For example, you could rewrite the above as:
-(void)moving {
workBlk_t animationBlock = ^ {
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
};
void (^completionBlock)(BOOL finished) = ^{
[UIViewAnimateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion : NULL
};
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationCurveEaseIn
animations:animationBlock
completion:completionBlock
}];
}
you should start new animation in completion block for example:
completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,25)];
} completion:^(BOOL finished) {
}];
}];
This part does exactly what you are describing:
completion:^(BOOL finished) {
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
}
I.e. returns the object to the top of the screen after the animiation is completed. This will not be animated, it will happen after the animation is completed, and thus it will be instant.
You need to trigger a new animation after the animation is completed.
To create several nested animation blocks can however become a bit messy, the most clean way is to create another method for animating back and call it when the first animation is completed, like this:
-(void) moveDown{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
int randomx = arc4random() % 295;
[redSquare setCenter:CGPointMake(randomx,435)];
} completion:^(BOOL finished) {
// First animation completed
[self moveBack];
}];
}
-(void) moveBack{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationCurveEaseIn animations:^{
[redSquare setCenter:CGPointMake(redSquare.frame.origin.x,25)];
} completion:^(BOOL finished) {
// Second animation completed
}];
}

UILabel animated fade in out isn't working

I am trying to build an introduction to my app with UILabels fading in and out. I have two labels. I want the first one to fade in, stay on the screen for 4 seconds. Then second label should fade in and stay on the screen for 4 seconds. Then it should fade out both the labels.
I have the following code but it does not do anything since it goes straight to the final state. I have the following method in viewDidAppear(). What am I doing wrong?
-(void) animateLabels
{
[UIView beginAnimations:#"First Label Display" context:nil];
[UIView setAnimationDelay:4.0];
firstLabel.alpha = 1;
[UIView commitAnimations];
[UIView beginAnimations:#"Second Label Display" context:nil];
[UIView setAnimationDelay:6.0];
secondLabel.alpha = 1;
[UILabel commitAnimations];
[UIView beginAnimations:#"Hide Labels" context:nil];
[UIView setAnimationDelay:10.0];
secondLabel.alpha = 0;
firstLabel.alpha=0;
[UILabel commitAnimations];
}
Use block based animation & chain your animations together. So there are 3 steps. label1 fadesIn, Label2 fadesIn, finally Label3 fadesIn. I have written the code below for fading in label1 & label2. Fading out is simple. I think you can fill in the rest. Its straight-forward from here...
Try this -
[UIView animateWithDuration:1.0
delay:4
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^(void)
{
[firstLabel setAlpha:1.0];
}
completion:^(BOOL finished)
{
if(finished)
{
[UIView animateWithDuration:1.0
delay:4.0
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^(void)
{
[secondLabel setAlpha:1.0];
}
completion:^(BOOL finished)
{
if(finished)
{
//put another block her to hide both the labels.
}
}];
}
}];
I suggest rewriting this using blocks. First animateWithDuration:animations:completion: and then nested animateWithDuration:delay:options:animations:completion:. It's far more flexible, and there's no need to run on pre-blocks systems these days.
Also, your first animation as written wouldn't trigger for 4 seconds.
Here is a solution in swift 4+
UIView.animate(withDuration: 1.0, delay: 4, options: [.curveLinear, .allowUserInteraction], animations: {
firstLabel.alpha = 1.0
}) { finished in
if finished {
UIView.animate(withDuration: 1.0, delay: 4.0, options: [.curveLinear, .allowUserInteraction], animations: {
secondLabel.alpha = 1.0
}) { finished in
if finished {
//put another block her to hide both the labels.
}
}
}
}

Resources