UIView动画一开始就跳了起来

时间:2012-09-21 17:53:50

标签: ios objective-c uiviewanimation

我正在运行此代码......

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

它完全一样。

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

我真的无法理解为什么会这样?

任何想法。

:: EDIT ::

清除一些可能的歧义。

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

至少他们习惯了。由于启用了自动布局(我需要应用程序的其他部分),我不能只改变视图的框架,所以我去了转换路径。

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

由于

9 个答案:

答案 0 :(得分:67)

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

    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”可能不存在,但我希望你明白这一点。

答案 1 :(得分:15)

这里的解决方案都不适用于我...我的动画总会跳过。 (除非它在另一个动画结束时正确,提示)。

一些细节:

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

解决方案:

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

    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)

答案 2 :(得分:8)

好的,再次观看了WWDC视频时,他们声明使用AutoLayout时要做的第一件事就是删除对setFrame的任何调用。

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

由于

答案 3 :(得分:7)

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

  

iOS 8目前正在展示UIKit动画中的一个已知错误   变换动画得到错误的fromValue(主要影响   动画对象的位置,使它们看起来“跳跃”   意外地在动画开始时)。

     

[...]

     

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

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

UIViews的框架属性在应用了转换时无效。改为使用“bounds”。

答案 6 :(得分: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];
}

答案 7 :(得分:0)

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

  1. 隐藏原始视图
  2. 添加复制要制作动画的视图的临时视图
  3. 执行现在将按预期进行的动画
  4. 删除临时视图并取消隐藏具有最终状态的原始视图
  5. 希望这有帮助。

答案 8 :(得分:0)

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

view.layoutIfNeeded()
    
UIView.animate(withDuration: duration, delay: 0, options: .beginFromCurrentState, animations: {
    // Animation here
})