I'm running this code...
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.settingsView.frame.size.width, 0);
CGAffineTransform speedTransform = CGAffineTransformMakeTranslation(-self.speedView.frame.size.width, 0);
self.settingsView.transform = settingsTransform;
self.speedView.transform = speedTransform;
} completion:nil];
But when it runs the views jump half the transform in the opposite direction before sliding to half a position in the correct direction.
I've slowed down the animation duration to 5 seconds but the initial jump is instantaneous and half the transformation in the wrong direction.
When I animate back using this code...
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.settingsView.transform = CGAffineTransformIdentity;
self.speedView.transform = CGAffineTransformIdentity;
} completion:nil];
It does exactly the same thing.
The result is that the final movement is half the desired transform as it jumps half the transform in the wrong direction first.
I really can't work out why this is happening?
Any ideas.
::EDIT::
Clearing up some possible ambiguity.
I'm not trying to have these views "bounce" back to where they are. The views I'm animating are like control panel at the edge of the screen. When the user presses "go" the view then slide out of the way. When the user presses "stop" the panels slide back into the view.
At least they used to. Since enabling auto layout (which I need for other parts of the app) I can't just change the frame of the views so I went the the transform route.
You can see this effect by sticking a view into a view controller and a button to run the animation.
Thanks
I had the exact same problem so here is the solution I came up with.
CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, translation.x, translation.y);
[UIView animateWithDuration:0.25 animations:^{
_assetImageView.transform = transform;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
So I call [self.view layoutIfNeeded]; inside of the animate block. Without this the it has the same problem as you and jumps the distance negative translation first then animates to the correct position from there. I am calling this from a view controller so self is a sub class of UIViewController. In your case "self.view" may not exist but I hope you get the idea.
None of the solutions here worked for me... My animation would always skip. (except when it was right at the end of another animation, hint).
Some details:
The view that was doing this had a series of scale and translates already in the stack.
Solution:
Doing a keyframe animation, with a super short first key that would basically re apply the transform that that the last animation should have set.
UIView.animateKeyframesWithDuration(0.4, delay: 0.0, options: [.CalculationModeCubic], animations: { () -> Void in
//reset start point
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.01, animations: { () -> Void in
self.element.transform = initialTransform
})
UIView.addKeyframeWithRelativeStartTime(0.01, relativeDuration: 0.99, animations: { () -> Void in
self.element.transform = finalTransform
})
}, completion: nil)
OK, having watched the WWDC videos again they state that one of the first things you have to do when using AutoLayout is to remove any calls for setFrame.
Due to the complexity of the screen I have removed the Auto-Layout completely and I'm now using the frame location to move the view around the screen.
Thanks
I've asked Apple Technical Support about this issue and got this response, so it's a bug.
iOS 8 is currently exhibiting a known bug in UIKit animations where transform animations get the wrong fromValue (primarily affecting the position of animated objects, making them appear to “jump” unexpectedly at the start on an animation).
[...]
The workaround until a potential fix is delivered is to drop down to Core Animation APIs to code your animations.
Here's improved version of Andreas answer The key difference is that you can specify just one keyframe and get less code
UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
animatedView.transform = newTransform
})
}, completion: nil)
Does your settingsView or speedView already have a transformation applied before this animation takes place?
If the transformations for these views is not the identity transformation (aka CGAffineTransformIdentity, aka no transformation), you cannot access their .frame properties.
UIViews' frame properties are invalid when they have a transformation applied to them. Use "bounds" instead.
Since you want your second animation to occurs from the current state of your first animation (whether it is finished or not) I recommend to use the UIViewAnimationOptionLayoutSubviews
option when setting your second animation.
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
animations:^{
self.settingsView.transform = CGAffineTransformIdentity;
self.speedView.transform = CGAffineTransformIdentity;
} completion:nil];
Here is a sample of the code i used for testing by using the simple view controller template:
myviewcontroller.m:
- (void)viewDidLoad
{
[super viewDidLoad];
self.animatedView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 160, 80)];
self.animatedView.backgroundColor = [UIColor yellowColor];
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
animations:^{
CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.animatedView.frame.size.width, 0);
self.animatedView.transform = settingsTransform;
}
completion:nil];
self.buttonToTest = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonToTest.frame = CGRectMake(90, 20, 80, 40);
[self.buttonToTest setTitle:@"Click Me!" forState:UIControlStateNormal];
[self.buttonToTest addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
// set-up view hierarchy
[self.view addSubview:self.buttonToTest];
[self.view addSubview: self.animatedView];
}
- (void) buttonClicked
{
[UIView animateWithDuration:.2
delay:0.0
options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionLayoutSubviews
animations:^{
self.animatedView.transform = CGAffineTransformIdentity;
}
completion:nil];
}
I had this problem and solved it by:
- Hide the original view
- Add a temp view that copies the view you want to animate
- Carry out animation which will now be as intended
- Remove the temp view and unhide the original view with the final state
Hope this helps.
来源:https://stackoverflow.com/questions/12535647/uiview-animation-jumps-at-beginning