32

我正在运行此代码...

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

但是当它运行时,视图会在相反的方向上跳跃一半的变换,然后在正确的方向上滑动到一半的位置。

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

当我使用此代码制作动画时...

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];

它做同样的事情。

结果是最终的移动是所需变换的一半,因为它首先在错误的方向上跳跃了一半的变换。

我真的想不通为什么会这样?

有任何想法吗。

::编辑::

消除一些可能的歧义。

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

至少他们曾经如此。由于启用了自动布局(我需要应用程序的其他部分),我不能只更改视图的框架,所以我采用了转换路线。

您可以通过将视图粘贴到视图控制器和运行动画的按钮来查看此效果。

谢谢

4

9 回答 9

71

我遇到了完全相同的问题,所以这是我想出的解决方案。

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

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

于 2012-10-31T01:51:14.910 回答
16

这里没有一个解决方案对我有用......我的动画总是会跳过。(除非它正好在另一个动画的结尾,提示)。

一些细节:

执行此操作的视图具有一系列比例,并且已经在堆栈中进行了转换。

解决方案:

做一个关键帧动画,用一个超短的第一个键,基本上会重新应用最后一个动画应该设置的变换。

    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)
于 2016-03-19T00:59:50.930 回答
8

好的,再次观看 WWDC 视频后,他们指出使用 AutoLayout 时您必须做的第一件事就是删除对 setFrame 的任何调用。

由于屏幕的复杂性,我完全删除了自动布局,现在我使用框架位置在屏幕上移动视图。

谢谢

于 2012-10-02T11:09:21.613 回答
8

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

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

[...]

在提供潜在修复之前的解决方法是下拉到 Core Animation APIs 来编码你的动画。

于 2015-03-04T08:42:59.017 回答
4

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

UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: [], animations: {
  UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
    animatedView.transform = newTransform
    })
  }, completion: nil)
于 2017-08-23T07:35:16.120 回答
1

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

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

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

于 2012-09-21T18:23:06.517 回答
1

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

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];

这是我使用简单视图控制器模板进行测试的代码示例:

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];
}
于 2012-09-21T18:47:42.800 回答
0

我遇到了这个问题并通过以下方式解决了它:

  1. 隐藏原始视图
  2. 添加一个临时视图,用于复制要设置动画的视图
  3. 执行现在将按预期进行的动画
  4. 删除临时视图并取消隐藏具有最终状态的原始视图

希望这可以帮助。

于 2016-03-07T22:03:45.477 回答
0

我尝试了上面关于 layoutIfNeeded 的答案,但没有奏效。我在动画块之外(之前)添加了 layoutIfNeeded,它解决了我的问题。

view.layoutIfNeeded()
    
UIView.animate(withDuration: duration, delay: 0, options: .beginFromCurrentState, animations: {
    // Animation here
})
于 2021-03-17T08:33:58.013 回答