UIView animation jumps at beginning

僤鯓⒐⒋嵵緔 提交于 2019-11-26 22:53:08

问题


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


回答1:


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.




回答2:


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)



回答3:


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




回答4:


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.




回答5:


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)



回答6:


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.




回答7:


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



回答8:


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.



来源:https://stackoverflow.com/questions/12535647/uiview-animation-jumps-at-beginning

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