ios UIView 动画一开始就跳转

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12535647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:19:08  来源:igfitidea点击:

UIView animation jumps at beginning

iosobjective-cuiviewanimation

提问by Fogmeister

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.

我已将动画持续时间减慢到 5 秒,但初始跳跃是瞬时的,并且一半的转换方向错误。

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.

我并不是要让这些观点“反弹”回到它们所在的位置。我正在制作动画的视图就像屏幕边缘的控制面板。当用户按下“go”时,视图就会滑开。当用户按下“停止”时,面板会滑回到视图中。

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

谢谢

采纳答案by Fogmeister

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.

好的,再次观看 WWDC 视频后,他们指出使用 AutoLayout 时您必须做的第一件事就是删除对 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

谢谢

回答by David Nesbitt

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.

所以我调用 [self.view layoutIfNeeded]; 动画块的内部。没有这个,它和你有同样的问题,首先跳跃距离负平移,然后从那里动画到正确的位置。我从视图控制器调用它,所以 self 是 UIViewController 的子类。在你的情况下,“self.view”可能不存在,但我希望你能明白。

回答by Andres Canella

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)

回答by denbec

I've asked Apple Technical Support about this issue and got this response, so it's a bug.

我已经向 Apple 技术支持询问了这个问题并得到了这个回复,所以这是一个错误。

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.

iOS 8 目前在 UIKit 动画中表现出一个已知的错误,即变换动画的 fromValue 错误(主要影响动画对象的位置,使它们在动画开始时出现意外“跳跃”)。

[...]

在提供潜在修复之前的解决方法是下拉到核心动画 API 来编码您的动画。

回答by bananabastard

Here's improved version of Andreas answer The key difference is that you can specify just one keyframe and get less code

这是 Andreas 答案的改进版本 关键区别在于您可以仅指定一个关键帧并获得更少的代码

UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: [], animations: {
  UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
    animatedView.transform = newTransform
    })
  }, completion: nil)

回答by MikeS

Does your settingsView or speedView already have a transformation applied before this animation takes place?

在此动画发生之前,您的 settingsView 或 speedView 是否已经应用了转换?

If the transformations for these views is not the identity transformation (aka CGAffineTransformIdentity, aka no transformation), you cannot access their .frame properties.

如果这些视图的转换不是身份转换(又名 CGAffineTransformIdentity,又名无转换),则无法访问它们的 .frame 属性。

UIViews' frame properties are invalid when they have a transformation applied to them. Use "bounds" instead.

UIViews 的框架属性在应用了转换时无效。改用“界限”。

回答by tiguero

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 UIViewAnimationOptionLayoutSubviewsoption when setting your second animation.

由于您希望第二个动画从第一个动画的当前状态(无论是否完成)开始,我建议UIViewAnimationOptionLayoutSubviews在设置第二个动画时使用该选项。

[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:

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

回答by 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
  1. 隐藏原始视图
  2. 添加一个临时视图来复制您想要制作动画的视图
  3. 执行动画,现在将按预期执行
  4. 删除临时视图并取消隐藏具有最终状态的原始视图

Hope this helps.

希望这可以帮助。