I'm scaling UIImageView and then reverting it using UIView animateWithDuration with UIViewAnimationOptionAutoreverse option. The problem is the image animation is a little bit jaggy (twitching) at the end of the animation. Here's my code:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionAutoreverse
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);}
completion:^(BOOL finished){if (finished){
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);}}];
I know that I'm missing something but don't know where to start :(
UPDATE1: I'm performing nested 6 animations where each next animation performs after previous one. For that I'm using block animations and performing each next animation in complete block.
UPDATE2: I have tried with UIViewAnimationOptionRepeat option but there's still some flash effect after each scale animation.
UIViewAnimationOptionAutoreverse does nothing without also using the UIViewAnimationOptionRepeat option. Your animation as written will shrink the image to 90%, then snap back to 100% in the completion block. Maybe you can follow this animation with another that scales back to 100% over a quarter second. Something like this:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);}
completion:^(BOOL finished){if (finished){
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
myImage.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);}
completion:NULL];}}];
.h file declerd.
NSInteger imgint;
.m file in code and try.
-(void)
{
[NSTimer scheduledTimerWithTimeInterval:(0.85f)target:self selector:#selector(play_btn_animation) userInfo:nil repeats:YES];
}
-(void)play_btn_animation
{
if(imgint == 0)
{
[UIView animateWithDuration:0.8
delay:0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.8, 0.8);
}
completion:^(BOOL finished) {
img = 1;
}];
}
else
{
[UIView animateWithDuration:0.8
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
}
completion:^(BOOL finished) {
imgint = 0;
}];
}
}
Related
The question explains it all actually.
I load a custom UIView on top of my current view, animated, using this code:
- (void)showView
{
self.blurView.alpha = 0.f;
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
self.blurView.alpha = 1.f;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
self.blurView.alpha = 0.f;
} completion:nil];
}];
}
It works, but when I perform -(void)showView again while it is still animating, the custom view doesn't get removed from the screen.
It just stays like this:
I figured out what the problem was.
blurView is a public variable and every time I did -(void)showView it used the same variable, setting the alpha to 0.f just once, thus never changing the alpha of the first show.
I declared the variable blurView in the method itself and now it works because every blurView gets it's own pointer.
-(void)someMethod
{
//Create a live blur view
FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
blurView.center = CGPointMake(self.view.window.frame.size.width / 2, self.view.window.frame.size.height / 2);
blurView.layer.cornerRadius = 20.f;
[self.view.window addSubview:blurView];
[self showView:(blurView)];
}
- (void)showView:(FXBlurView *)blurView
{
//Make full transparent before showing
blurView.alpha = 0.f;
//Start animation
[FXBlurView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
blurView.alpha = 1.f;
} completion:^(BOOL finished) {
if (finished)
{
//End animation
[FXBlurView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
blurView.alpha = 0.f;
} completion:nil];
}
}];
}
You should add to the top of your function this line:
[self.view.layer removeAllAnimations];
It will remove all of the active animations.
It doesn't work because you have implemented a delay, use animation block with delay - it will create animation keys that could be removed with this function above.
[UIView animateWithDuration:0.3 delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^
{
// ...
} completion:NULL];
I'm trying to animate an image to rotate left and right when selected, basically to let the user which the object they're touching.
I found some code for animating:
- (void)rotateImage:(UIImageView *)image duration:(NSTimeInterval)duration
curve:(int)curve degrees:(CGFloat)degrees delay:(CGFloat)delay
{
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:delay];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix
CGAffineTransform transform =
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(degrees));
image.transform = transform;
// Commit the changes
[UIView commitAnimations];
}
However, when I try to run two animations, only the last one ever works. Even with a proper delay, only the second animation will show:
[self rotateImage:self duration:.5
curve:UIViewAnimationCurveEaseIn degrees:60 delay:0];
[self rotateImage:self duration:.5
curve:UIViewAnimationCurveEaseIn degrees:-60 delay:5];
What can I do to create the animation so it rotates left, then rotates right?
[UIView animateWithDuration:0.2 animations:^{
// animation left
[UIView setAnimationDelay:10];
} completion:^(BOOL finished){
[UIView animateWithDuration:0.2 animations:^{
// animation right
} completion:^(BOOL finished){
// done
}];
}];
found it here
https://developer.apple.com/library/content/featuredarticles/Short_Practical_Guide_Blocks/
[UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(60));
} completion:^(BOOL finished){
[UIView animateWithDuration:0.5f delay:5.0f options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-60));
}
completion:^(BOOL finished){}];
}];
Animation blocks are definitely the way to go. This should replicate what you're trying to do, including the easing. This assumes your calling from a view controller, but if your putting this code into a UIView or UIImageView, then just replace self.view with self.
[UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(60));
} completion:^(BOOL finished){}];
[UIView animateWithDuration:0.5f delay:5.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-60));
} completion:^(BOOL finished){}];
i am doing block animation, my project is using opengl for gameplay and uiview for menu like stuff.
i am animating uiview using animateWithDuration method, bt facing issue at getting delay complete animation boolean callback. I tried the same code in UIKit app and it works very smoothly.
Below is my code:
-(void) playAnimation:(UIButton *)_button atPosition:(CGRect)_rect withDuration:(CGFloat)_duration andDelay:(CGFloat)_delay andDiection:(NSInteger)_direction
{
[UIView animateWithDuration:_duration
delay:_delay
options:UIViewAnimationCurveLinear
animations:^{
_button.frame = _rect;
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
CGRect rect = _rect;
rect.origin.x = _rect.origin.x + (10 * _direction);
_button.frame = rect;
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
_button.frame = _rect;
}
completion:^(BOOL finished){
}];
}];
}];
}
I wanted to rotate a UIView on its horizontal axis for 360 degrees and then refresh the content in the view. I was looking out for solutions on this. Found a couple here n there. This is what I came out with.
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished){
NSLog(#"Finished first pi");
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished) {
NSLog(#"Finished second pi");
}];
}];
This flips the view but only by 180 degrees. I want it to flip one more time so that I can see the view normally..
Both my NSLogs are displayed one after the other. I am sure I am missing something here. ANy help would be helpful..
Thanks
In your completion block try concatenating the new transform with the current transform.
self.tableView.layer.transform = CATransform3DConcat(self.tableView.layer.transform, CATransform3DMakeRotation(M_PI,1.0,0.0,0.0));
You should check this answer How to make a CATransform3dMakeRotation rotate the other way? And chain together
I think that your problem is related with: "When you are working with a transform directly, Core Animation will interpolate the transform from the current value to the specified transform. It will find the shortest path to get to that transform, which will restrict the animation direction. If you try to animate the same transform property twice, the second value will simply override the first, not combine the two transforms together."
use this:-
rotatingView.layer.anchorPoint = CGPointMake(0.0f, 0.0f);
rotatingView.center = CGPointMake(0,
(rotatingView.center.y -
(rotatingView.bounds.size.height/2.0f)));
rotatingView.center = CGPointMake(0,
(rotatingView.center.y-
(rotatingView.bounds.size.height/2)));
// start the Page Open
[UIView beginAnimations:#"Animation" context:nil];
[UIView setAnimationDuration:13.0];
// set angle as per requirement
[rotatingView.layer setValue:[NSNumber numberWithInt:280]
forKeyPath:#"transform.rotation.x"];
[UIView commitAnimations];
You just have to change your code from 1.0 to 0.0 inside completion block and woohoo all done.
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
} completion:^(BOOL finished){
NSLog(#"Finished first pi");
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionTransitionNone animations:^{
self.tableView.layer.transform = CATransform3DMakeRotation(M_PI,0.0,0.0,0.0);
} completion:^(BOOL finished) {
NSLog(#"Finished second pi");
}];
}];
You can also approach this using the .Repeat and .Autoreverse animation options + setting animation's repeat count. Here's an example in Swift:
UIView.animateWithDuration(time, delay: 0, options: [.Repeat, .Autoreverse], animations: {
UIView.setAnimationRepeatCount(3)
self.view.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0)
}) { (completed) in
// completion
}
I am doing some animation using block level technique. I want to stop the animation on the basis of certain condition. How will I stop the animation from completing?
Following is my code for animation:
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>0)
vwb1.center = CGPointMake(260, 40);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.5 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>1)
vwb2.center = CGPointMake(260, 100);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>2)
vwb3.center = CGPointMake(260, 160);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
if([arrAns count]>3)
vwb4.center = CGPointMake(260, 220);
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
if([arrAns count]>4)
vwb5.center = CGPointMake(260, 280);
} completion:nil];
}];
}];
}
];
}];
I am not having any key here so I can nnot remove it on the basis of a key. There is also a feature as removeallanimation but I am not able to use it. If someone could help me on how to use that it will also be fine.
Edit: Ok I figured out how to do it, I am doing it using following code:
[self.view.layer removeAllAnimations];
But now I have problem that my block level animation which have not yet started is still running. So if I remove the animation at second block it still executes remaining block. I need to stop that also.
Thanks
Pankaj
You should check finished variable. And start next animation (inside a block) only if previous was finished (finished == YES), not stopped.
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
...
completion
A block object to be executed when the animation sequence
ends. This block has no return value and takes a single Boolean
argument that indicates whether or not the animations actually
finished before the completion handler was called. If the duration of
the animation is 0, this block is performed at the beginning of the
next run loop cycle.