How to get current position of animating uiview in ios - ios

I want current position of animating UIView during animation and I am using this code.
CABasicAnimation * m_pAnimationObj = [CABasicAnimation animationWithKeyPath:#"transform.translation"];
[m_pAnimationObj setFromValue:[NSValue valueWithCGPoint:CGPointMake(0,-50)]];
[m_pAnimationObj setToValue:[NSValue valueWithCGPoint:CGPointMake(0,[UIScreen mainScreen].bounds.size.height+100)]];
m_pAnimationObj.duration = 2.0;
m_pAnimationObj.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[DropImage.layer addAnimation:m_pAnimationObj forKey:#"animations"];
Please answer if anyone knows about this.
Thank you in advance!

Use this code:
CGRect currentCenter = [drawingView.layer.presentationLayer center];
or
CGRect currentFrame = [DropImage.layer.presentationLayer frame];

Related

How to get perfect X , Y position of rotating UIView in iOS

I am using CABasicanimation for rotate an UIView. I am using this code:
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
NSNumber *currentAngle = [CircleView.layer.presentationLayer valueForKeyPath:#"transform.rotation"];
rotationAnimation.fromValue = currentAngle;
rotationAnimation.toValue = #(50*M_PI);
rotationAnimation.duration = 50.0f; // this might be too fast
rotationAnimation.repeatCount = HUGE_VALF; // HUGE_VALF is defined in math.h so import it
[CircleView.layer addAnimation:rotationAnimation forKey:#"rotationAnimationleft"];
in this I want perfect X,Y position while "UIView" is rotating. How can I achieve this?
I Got A Answer Of This Question Please Go To This Link For Answer
Go to This Link For Answer
So, if I understand you correctly, you just want to get the X and Y coordinates of your view during rotation?
You can do this by logging the frame of the presentationLayer, like this:
- (IBAction)buttonAction:(UIButton *)sender {
CGRect position = [[CircleView.layer presentationLayer] frame];
NSLog(#"%#", NSStringFromCGRect(position));
}

Animating both position and rotation in CAAnimationGroup makes position not updated in the end

I was trying to animate both position and rotation property of a UIView using an explicit animation and the result is that the rotation was successfully updated but the position of the view did not update although I updated both the layer's position and rotation property to its final value right after I add the animation to the view's layer(I guess it is so called explicit-override-implicit animation technique?).
Here is my code:
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:#"position.y"];
move.fromValue = #(self.square.center.y);
move.toValue = #(300);
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotate.fromValue = #(DEGREES_TO_RADIANS(0));
rotate.toValue = #(DEGREES_TO_RADIANS(45));
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 1.0;
group.animations = #[move, rotate];
self.square.center = CGPointMake(self.square.center.x, 300);
self.square.transform = CGAffineTransformMakeRotation(M_PI/4);
[self.square.layer addAnimation:group forKey:nil];
If I implement the position or rotation animation separately, the code performs well and I got the expected results. But when it combines into the CAAnimationGroup, the position just won't update to the final value in the end.
Any ideas here?
Maybe try this: of course with your values:
[UIView animateWithDuration:1.0f animations:^{
self.square.center = CGPointMake(10, 10);
self.square.transform =CGAffineTransformMakeRotation(90);
}completion:nil];

UITextField being clipped during CABasicAnimation with keyPath of bounds.size.width

I have a somewhat of an odd issue on hand. I have UITextField. This TextField has it’s width resized when a button is tapped. To do that I first did the following:
CGRect newbounds = originalBounds;
newbounds.size.width = newbounds.size.width/2;
[UIView beginAnimations:nil context:nil];
self.textField2.bounds = newbounds;
[UIView commitAnimations];
Easy enough and it worked. Now I move along and try to exert a bit more control over the animation. To do that I go the next level up to CABasicAnimation using the following:
CGRect newbounds = originalBounds;
newbounds.size.width = newbounds.size.width/2;
CABasicAnimation *animShrink = [CABasicAnimation animation];
animShrink.keyPath = #"bounds";
animShrink.toValue = [NSValue valueWithCGRect:newbounds];
animShrink.duration = 0.5;
animShrink.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animShrink.delegate = self;
[self.textField2.layer addAnimation:animShrink forKey:#"shrink"];
And that is when I run into the clipping issue during the animation as can be seen at: http://coldstorage.macbonsai.com/public/cabasic_animation_clipping.png (since I “need at least 10 reputation to post images” as per Stackoverflow).
So I tried the following version of the animation:
CGRect newbounds = originalBounds;
newbounds.size.width = newbounds.size.width/2;
CABasicAnimation *animShrink = [CABasicAnimation animation];
animShrink.keyPath = #"bounds.size.width";
animShrink.fromValue = [NSNumber numberWithFloat:originalBounds.size.width];
animShrink.toValue = [NSNumber numberWithFloat:newbounds.size.width];
animShrink.duration = 0.5;
animShrink.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animShrink.delegate = self;
[self.textField2.layer addAnimation:animShrink forKey:#"shrink"];
Still encountered the same issue. At this point I removed all constraints from the UITextField and tried both the CABasicAnimation versions. Same issue. At this point I don’t know what else to do. Any help will be greatly appreciated.
Many thanks in advance.
If you change the style of the button to UITextBorderStyleNone it doesn't get clipped.
My guess is that when the style is UITextBorderStyleRoundedRect, Apple probably just adds a UIImageView to the button with the "round rect" image, so when you animate the button's layer, its subviews don't animate together, because in iOS you have to explicitly animate all sublayers.

UISearchBar width animation and AutoLayout

I have had a massive amount of problems trying to animate the UISearchBar to simply expand when editing, so I thought I would provide a solution to anyone else who has had to suffer this problem.
There are already problems in animating a UISearchBar and problems increase further when mixing that with the iOS AutoLayout. If you have had the same issues then the I have posted the solution below. It may not be perfect but it does work.
After much trial and error I got it to work by turning the AutoLayout functionality off in the xib and then using the Animation method below:
+(CAAnimationGroup *)changeView:(UIView *)view frameTo:(CGRect)frame{
CGRect oldFrame = view.frame;
// /2.0 because size animation occurs from the anchor point which is set to (0.5,0.5) by default
CGPoint oldOrigin = CGPointMake(oldFrame.origin.x+oldFrame.size.width/2.0, oldFrame.origin.y+oldFrame.size.height/2.0);
CGPoint newOrigin = CGPointMake(frame.origin.x+frame.size.width/2.0, frame.origin.y+frame.size.height/2.0);
CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
positionAnimation.fromValue = [NSValue valueWithCGPoint:oldOrigin];
positionAnimation.toValue = [NSValue valueWithCGPoint:newOrigin];
view.layer.position = newOrigin;
CABasicAnimation *sizeAnimation = [CABasicAnimation animationWithKeyPath:#"bounds"];
sizeAnimation.fromValue = [NSValue valueWithCGRect:oldFrame];
sizeAnimation.toValue = [NSValue valueWithCGRect:frame];
view.layer.bounds = frame;
CAAnimationGroup *frameChangeAnimationGroup = [CAAnimationGroup animation];
frameChangeAnimationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
frameChangeAnimationGroup.animations = [NSArray arrayWithObjects:positionAnimation,sizeAnimation, nil];
[view.layer addAnimation:frameChangeAnimationGroup forKey:#"frame"];
return frameChangeAnimationGroup;}
I hope this helps and saves people some of the pain I had to go through.

iOS CAKeyFrameAnimation Scaling Flickers at animation end

In another test of Key Frame animation I am combining moving a UIImageView (called theImage) along a bezier path and scaling larger it as it moves, resulting in a 2x larger image at the end of the path. My initial code to do this has these elements in it to kick off the animation:
UIImageView* theImage = ....
float scaleFactor = 2.0;
....
theImage.center = destination;
theImage.transform = CGAffineTransformMakeScale(1.0,1.0);
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:#"bounds.size"];
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(theImage.image.size.height*scaleFactor, theImage.image.size.width*scaleFactor)]];
resizeAnimation.fillMode = kCAFillModeBackwards;
resizeAnimation.removedOnCompletion = NO;
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.path = [jdPath path].CGPath;
pathAnimation.fillMode = kCAFillModeBackwards;
pathAnimation.removedOnCompletion = NO;
CAAnimationGroup* group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:pathAnimation, resizeAnimation, nil];
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
group.removedOnCompletion = NO;
group.duration = duration;
group.delegate = self;
[theImage.layer addAnimation:group forKey:#"animateImage"];
Then, when the animation completes I want to retain the image at the larger size, so I implement:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
theImage.transform = CGAffineTransformMakeScale(scaleFactor,scaleFactor);
}
This all works .. sort of. The problem is that at the end of the animation theImage flickers for a brief moment - just enough to make it look bad. I am guessing that this is the transition at the end of the animation where I set the transform to the new size.
In experimenting with this I tried a slightly different form of the above, but still got the same flicker:
CAKeyframeAnimation *resizeAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
NSValue* startSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)];
NSValue* endSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, scaleFactor, scaleFactor, 1.0)];
NSArray* sizeKeys = [NSArray arrayWithObjects:startSizeKey, endSizeKey, nil];
[resizeAnimation setValues:sizeKeys];
....
theImage.transform = CGAffineTransformMakeScale(scaleFactor,scaleFactor);
But when I ended the animation at the same size as the original, there was NO flicker:
CAKeyframeAnimation *resizeAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
NSValue* startSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)];
NSValue* middleSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, scaleFactor, scaleFactor, 1.0)];
NSValue* endSizeKey = [NSValue valueWithCATransform3D:CATransform3DScale (theImage.layer.transform, 1.0, 1.0, 1.0)];
NSArray* sizeKeys = [NSArray arrayWithObjects:startSizeKey, middleSizeKey, endSizeKey, nil];
[resizeAnimation setValues:sizeKeys];
....
theImage.transform = CGAffineTransformMakeScale(1.0,1.0);
So my big question is how can I animate this image without the flicker, and end up with a different size at the end of the animation?
Edit March 2nd
My initial tests were with scaling the image up. I just tried scaling it down (IE scaleFactor = 0.4) and the flickering was a lot more visible, and a lot more obvious as to what I am seeing. This was the sequence of events:
Original sized image is painted on the screen at the starting location.
As the image moves along the path it shrinks smoothly.
The fully shrunk image arrives at the end of the path.
The image is then painted at its original size.
The image is finally painted at its shrunken size.
So it seems to be step 4 that is the flickering that I am seeing.
Edit March 22
I have just uploaded to GitHub a demo project that shows off the moving of an object along a bezier path. The code can be found at PathMove
I also wrote about it in my blog at Moving objects along a bezier path in iOS
It can be tricky to animate a view's layer using Core Animation. There are several things that make it confusing:
Setting an animation on a layer doesn't change the layer's properties. Instead, it changes the properties of a “presentation layer” that replaces the original “model layer” on the screen as long as the animation is applied.
Changing a layer's property normally adds an implicit animation to the layer, with the property name as the animation's key. So if you want to explicitly animate a property, you usually want to set the property to its final value, then add an animation whose key is the property name, to override the implicit animation.
A view normally disables implicit animations on its layer. It also mucks around with its layer's properties in other somewhat mysterious ways.
Also, it's confusing that you animate the view's bounds to scale it up, but then switch to a scale transformation at the end.
I think the easiest way to do what you want is to use the UIView animation methods as much as possible, and only bring in Core Animation for the keyframe animation. You can add the keyframe animation to the view's layer after you've let UIView add its own animation, and your keyframe animation will override the animation added by UIView.
This worked for me:
- (IBAction)animate:(id)sender {
UIImageView* theImage = self.imageView;
CGFloat scaleFactor = 2;
NSTimeInterval duration = 1;
UIBezierPath *path = [self animationPathFromStartingPoint:theImage.center];
CGPoint destination = [path currentPoint];
[UIView animateWithDuration:duration animations:^{
// UIView will add animations for both of these changes.
theImage.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
theImage.center = destination;
// Prepare my own keypath animation for the layer position.
// The layer position is the same as the view center.
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
positionAnimation.path = path.CGPath;
// Copy properties from UIView's animation.
CAAnimation *autoAnimation = [theImage.layer animationForKey:#"position"];
positionAnimation.duration = autoAnimation.duration;
positionAnimation.fillMode = autoAnimation.fillMode;
// Replace UIView's animation with my animation.
[theImage.layer addAnimation:positionAnimation forKey:positionAnimation.keyPath];
}];
}
CAAnimations will flicker at the end if the terminal state was assigned in such a way that it itself created an implicit animation. Keep in mind CAAnimations are temporary adjustments of an object properties for the purposes of visualizing transition. When the animation done, if the layer's state is still the original starting state, that is what is going to be displayed ever so temporarily until you set the final layer state, which you do in your animationDidStop: method.
Furthermore, your animation is adjusting the bounds.size property of your layer, so you should similarly set your final state rather than using the transform adjustment as your final state. You could also use the transform property as the animating property in the animation instead of bounds.size.
To remedy this, immediately after assigning the animation, change the layer's permeant state to your desired terminal state so that when the animation completes there will be no flicker, but do so in such a manner to no trigger an implicit animation before the animation begins. Specifically, in your case you should do this at the end of your animation set up:
UIImageView* theImage = ....
float scaleFactor = 2.0;
....
theImage.center = destination;
theImage.transform = CGAffineTransformMakeScale(1.0,1.0);
CGSize finalSize = CGSizeMake(theImage.image.size.height*scaleFactor, theImage.image.size.width*scaleFactor);
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:#"bounds.size"];
[resizeAnimation setToValue:[NSValue valueWithCGSize:finalSize]];
resizeAnimation.fillMode = kCAFillModeBackwards;
resizeAnimation.removedOnCompletion = NO;
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.path = [jdPath path].CGPath;
pathAnimation.fillMode = kCAFillModeBackwards;
pathAnimation.removedOnCompletion = NO;
CAAnimationGroup* group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:pathAnimation, resizeAnimation, nil];
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
group.removedOnCompletion = NO;
group.duration = duration;
group.delegate = self;
[theImage.layer addAnimation:group forKey:#"animateImage"];
[CATransaction begin];
[CATransaction setDisableActions:YES];
theImage.bounds = CGRectMake( theImage.bounds.origin.x, theImage.bounds.origin.y, finalSize.width, finalSize.height );
[CATransaction commit];
and then remove the transform adjustment in your animationDidStop: method.
I was experimenting with some CAAnimations this week and was noticing that there was a flickering at the end of my animations. In particular, I would animation from a circle to a square, while changing the fillColor as well.
Each CAAnimation has a property called removedOnCompletion which defaults to YES. This means that the animation will disappear (i.e. transitions, scales, rotations, etc.) when the animation completes and you'll be left with the original layer.
Since you already have set your removedOnCompletion properties to NO, I would suggest trying to shift your execution of your animations to use CATransactions, instead of delegates and animationDidStop...
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction setCompletionBlock: ^{ theImage.transform = ...}];
// ... CAAnimation Stuff ... //
[CATransaction commit];
You put the transaction's completion block call before you create your animations, as per:
http://zearfoss.wordpress.com/2011/02/24/core-animation-catransaction-protip/
The following is from one of my methods:
[CATransaction begin];
CABasicAnimation *animation = ...;
animation.fromValue = ...;
animation.toValue = ...;
[CATransaction setCompletionBlock:^ { self.shadowRadius = _shadowRadius; }];
[self addAnimation:animation forKey:#"animateShadowOpacity"];
[CATransaction commit];
And, I constructed this animation and it works fine for me with no glitches at the end:
The setup and trigger are custom methods I have in a window, and i trigger the animation on mousedown.
UIImageView *imgView;
UIBezierPath *animationPath;
-(void)setup {
canvas = (C4View *)self.view;
imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"img256.png"]];
imgView.frame = CGRectMake(0, 0, 128, 128);
imgView.center = CGPointMake(384, 128);
[canvas addSubview:imgView];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[UIImageView animateWithDuration:2.0f animations:^{
[CATransaction begin];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = 2.0f;
pathAnimation.calculationMode = kCAAnimationPaced;
animationPath = [UIBezierPath bezierPath];
[animationPath moveToPoint:imgView.center];
[animationPath addLineToPoint:CGPointMake(128, 512)];
[animationPath addLineToPoint:CGPointMake(384, 896)];
pathAnimation.path = animationPath.CGPath;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
[imgView.layer addAnimation:pathAnimation forKey:#"animatePosition"];
[CATransaction commit];
CGFloat scaleFactor = 2.0f;
CGRect newFrame = imgView.frame;
newFrame.size.width *= scaleFactor;
newFrame.size.height *= scaleFactor;
newFrame.origin = CGPointMake(256, 0);
imgView.frame = newFrame;
imgView.transform = CGAffineTransformRotate(imgView.transform,90.0*M_PI/180);
}];
}

Resources