Reusable UIView Animation - ios

Consider this basic view animation. It will scale a view down to nothing over the course of 1 second:
[UIView animateWithDuration: 1.0
delay: 0.0
options: UIViewAnimationCurveEaseIn
animations:^{
vw.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
completion:^(BOOL finished) {
if (finished) {
vw.transform = CGAffineTransformIdentity;
}
}
];
What I'd like to do is use this same animation on many different views at different times throughout my app. To do this, I can easily put it in a method, pass in the view I want to zoom. No problem.
The challenge is that I may need to do different things at the completion of the animation depending on the situation. For example, I may want to remove the view from the SuperView in one case, and I may want to move the view to a new location (for zooming in later) in another case.
In a nutshell: How can I notify the caller of my method when the animation completes?
completion:^(BOOL finished) {
if (finished) {
vw.transform = CGAffineTransformIdentity;
// Do something unique here
}
}

You can just pass in the completion block itself as well:
- (void)animateView:(UIView *)v completion:(void ^(BOOL))ch
{
[UIView animateWithDuration: 1.0
delay: 0.0
options: UIViewAnimationCurveEaseIn
animations:^{
v.transform = CGAffineTransformMakeScale(0.0, 0.0);
}
completion:ch
];
}
Then call it like
[self animateView:someView completion:^(BOOL flag) {
// do stuff here
}];

Related

How to scale and change the origin of parent view and implement in subviews too?

I want to create a menu view which hides and unhides on button press. Now I managed to do it to the parent view but the buttons which are subview of the menuview are not scaling accordingly what i need to do? Here's the code!
menuInitFrame=menuView.frame;
newFrame=CGRectMake(320, 0, 0, 0);
Storing the initial state and new state;
if (menuView.hidden==NO) {
[UIView animateWithDuration:0.5
delay: 0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
menuView.frame = newFrame; // move
}
completion:^(BOOL finished)
{
menuView.hidden=YES;
}];
}
else if(menuView.hidden==YES)
{
menuView.hidden=NO;
[UIView animateWithDuration:0.5
delay: 0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
menuView.frame = menuInitFrame;
}
completion:^(BOOL finished)
{
//menuViewStatus=NO;
}];
}
Since you're using auto-layout you need to call layoutIfNeeded to recalculate frames of all subviews inside your menuView.
So inside your animation block add the following line:
menuView.frame = menuInitFrame;
[menuView layoutIfNeeded];

how to add right to left animation and zoom in animation using CGAffineTransformScale

I am new to core graphics, I want to show a view from right to left animation using CGAffineTransformScale after completion of this animation I have apply zooming animation to same view.
I can show the right to left animation. But I am unable to show the zooming animation.
Can some one help me to solve the above problem.
Please find the below code what i tried.
toView.layer.anchorPoint = CGPointMake(1, 0.5);
toView.center = CGPointMake(toViewController.view.bounds.size.width,toViewController.view.bounds.size.height/2.0);
toView.transform = CGAffineTransformScale(CGAffineTransformIdentity, -1.0, 1.0);
[UIView animateWithDuration:ANIMATION_DURATION delay: 0.0 options: UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[toView setTransform: CGAffineTransformMakeScale(1.0, 1.0)];
} completion:^(BOOL finished) {
}];
Your scale values are 1.0 that default value, change it to any other value other than 1.0, may be 1.2 to zoom-in, or 0.8 to zoom out.
And I think there should be few additions to your animation block.
[UIView animateWithDuration:ANIMATION_DURATION delay: 0.0 options: UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[toView setTransform: CGAffineTransformMakeScale(1.2, 1.2)]; //Zoom in
} completion:^(BOOL finished) {
if(finished){
[UIView animateWithDuration:ANIMATION_DURATION animations:^{
toView.transform=CGAffineTransformIdentity; //Make things normal.
}];
}
}];
I hope it works.
Cheers.

UIViewAnimateWithDuration completion never called

I am using the UIView animateWithDuration:delay:options:animations:completion: method but the completion method is never getting called. Here is my code:
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
//random lines of code
}completion:^(BOOL finished){
if (finished)
{
NSLog(#"FINISHED");
}
}];
EDIT: When I comment out the lines in my animations: it gets called???!!!
These are the lines:
CGFloat objectY = object.frame.origin.y;
objectY += speed;
object.frame = CGRectMake(object.frame.origin.x, objectY, 75, 75);
I am taking a guess - you want to animate the movement of a continuous gesture?
If yes, the animation never ends due the user interaction.
Just update the frame, no UIView Animation. Should work just fine.

How to stop this sequence?

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);
}];
}

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