UIView animation jumps at beginning

萝らか妹 提交于 2019-11-27 20:04:17

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];
}
Gaz Long

I had this problem and solved it by:

  1. Hide the original view
  2. Add a temp view that copies the view you want to animate
  3. Carry out animation which will now be as intended
  4. Remove the temp view and unhide the original view with the final state

Hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!