当前位置: 首页 > 知识库问答 >
问题:

带有约束的动画立即完成

公羊浩气
2023-03-14

我有一些动画,我试图转换为约束。它背后的想法是当出现错误时登录提示会反弹。

我的方法是,视图控制器上的所有内容都在bounceView中,而bounceView本身也在主视图中。

BounceView使用居中约束和前导空间约束绑定到主视图。为了使布局在设计时明确无误,还有一个前导空间和顶部空间约束。不过,这些只是占位符,在运行时被等高/宽约束替换。

没有其他约束与主视图相关联。

现在,一些细节…

我使用这些约束来定义反弹:

enum {animationDone, bounceStart, bounceLeft, bounceRight, bounceReturn};
static const NSTimeInterval BounceDuration = 20.0;
static const int NumberOfBounces = 3;
static const CGFloat BounceDistance = 16.0f;

(20秒的延迟通常要短得多;我加大了延迟以证明这不起作用。)

额外的运行时约束是这样设置的:

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_bounceView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_bounceView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
}

我用以下代码开始动画:

_animateCount = NumberOfBounces;
_animateStage = bounceStart;
[self animationStep];

实际代码非常简单:

- (void)animationStep {
    CGFloat bounceTo = 0;
    BOOL half = NO;
    switch (_animateStage) {
        case bounceStart:
            _animateStage = bounceLeft;
            bounceTo = -BounceDistance;
            half = YES;
            break;
        case bounceLeft:
            _animateStage = bounceRight;
            bounceTo = BounceDistance;
            break;
        case bounceRight:
            if ( --_animateCount > 0 ) {
                _animateStage = bounceLeft;
                bounceTo = -BounceDistance;
            } else {
                _animateStage = bounceReturn;
                bounceTo = 0;
            }
            break;
        case bounceReturn:
            half = YES;
            _animateStage = animationDone;
            break;
    }

    BOOL finishedAnimation = ( ( _animateStage == animationDone ) || ( self.view == nil ) );

    if ( !finishedAnimation ) {
        [_bounceView layoutIfNeeded];
        _centerX.constant = bounceTo;
        [_bounceView setNeedsUpdateConstraints];

        NSTimeInterval duration = half ? BounceDuration / 2.0f : BounceDuration;
        [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            NSLog(@"Bouncing to %f over %f seconds.", bounceTo, duration);
            [_bounceView layoutIfNeeded];
        } completion:^(BOOL finished) {
            [self animationStep];
        }];
    }
}

然而,这一切都将立即完成:

2013-10-29 10:59:43.852 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.864 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.865 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.866 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.866 App[9151:907] Bouncing to -16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.867 App[9151:907] Bouncing to 16.000000 over 20.000000 seconds.
2013-10-29 10:59:43.867 App[9151:907] Bouncing to 0.000000 over 20.000000 seconds.

有什么想法吗?

使现代化

对于后代,这是由在子视图上调用setNeedsUpdateConstraintlayoutIfNeed引起的。尽管Apple的留档暗示并非如此,但您需要在超级视图上调用它。我在下面的答案中详细说明了这一点。

然而,我接受了@nielsbot的回答。尽管这不是我问题的直接答案,但这是一个比修复我试图做的事情更好的解决方案。

共有3个答案

燕宜修
2023-03-14

您必须在superview上调用setNeedsUpdateConstraints和layoutIfNeeded。尽管苹果的文档中说需要布局(layoutIfNeeded),但事实似乎并非如此。

为了将来参考,Apple当前为layoutIfNeed留档:

使用此方法在绘图前强制子视图的布局。从接收器开始,只要超级视图需要布局,此方法就会向上遍历视图层次结构。然后它会在该祖先下方布局整个树。因此,调用此方法可能会强制整个视图层次结构的布局。

钮高朗
2023-03-14

这篇文章中建议的模式有帮助吗?

我知道你在动画中使用的是比那篇文章中简单的更细粒度的控制方法,但我认为底层的setneedsupdatelayoutstraints和后续的layoutIfNeeded调用在这里仍然适用。

东郭鸿福
2023-03-14

不能使用核心动画临时设置视图的动画吗?

请参见我的答案:https://stackoverflow.com/a/9371196/210171

基本上,在要设置动画的视图上,获取其层并向其添加动画。如果通过设置层变换的动画来执行此操作,则不会更改视图的大小或位置,也不会触发布局循环。

CAKeyframeAnimation * anim = [ CAKeyframeAnimation animationWithKeyPath:@"transform" ] ;
anim.values = @[ [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-5.0f, 0.0f, 0.0f) ], [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(5.0f, 0.0f, 0.0f) ] ] ;
anim.autoreverses = YES ;
anim.repeatCount = 2.0f ;
anim.duration = 0.07f ;

[ viewToShake.layer addAnimation:anim forKey:nil ] ;
 类似资料:
  • 我的视图控制器中有几个视图,当检测到向上滑动时向上移动,然后当检测到向下滑动时向下移动。我使用CGRectOffset通过调整y原点来强制视图移动。我现在使用IB对视图施加了约束,我不确定移动视图的最佳方法是什么,以便它们最终在iPhone 5、6和6上的正确位置。 目前我正在做这样的事情: 用比值改变常数是否更好?因此,对于上面的约束,不使用338,这样做是否更好:

  • 在我的人造示例中,我有以下单个视图: 如您所见,它由几个简单的约束组成: 将水平和垂直中心对齐, 高度(设置为常数) 前导空格和尾随空格(设置为常量) 我想要实现的是让这个红色/粉红色的视图从顶部“进来”。传统上,在一个没有约束的世界中,我只需修改,但我不确定在约束世界中如何进行类似操作。 为了重申我的问题,我如何使我的视图从场景开始,并为从顶部飞入的视图设置动画? 我考虑过设置垂直中心约束的动画

  • 我设置了一个动画,以在打开另一个开关/标签时隐藏一个开关/标签。同时,刚刚打开的开关向上移动。这里的简单解释非常有效。 但是,当我在开关/标签关闭后尝试向下移动时,它不会移动。另一个开关会很好地重新出现,但不会触发顶部约束更改。 我对这种类型的设置和动画都是以编程方式进行的相对较新,在花了一个小时之后,我被难住了。是因为我正在制作相对于另一个顶部约束的动画吗?如果它第一次工作,这有什么关系?即使隐

  • 问题内容: 我有一个UITextField我想在点击时扩大它的宽度。我设置了约束,并确保左侧的约束的优先级低于我要尝试在右侧进行动画的优先级。 这是我尝试使用的代码。 这可行,但是似乎只是瞬间发生,似乎没有任何动作。我尝试将其设置为10秒以确保没有遗漏任何东西,但得到的结果相同。 nameInputConstraint是我控制拖动以从IB连接到我的类的约束的名称。 谢谢您的帮助! 问题答案: 您需

  • 我有一个UIImageView,我想在背景上用平移效果慢慢动画。我的背景图像视图有四个约束: 从顶部到顶部布局指南的距离(零) 图像视图的视图模式设置为“纵横比填充”。当我运行我的应用程序时,没有问题,会显示静态图像。我添加以下代码来设置视图的动画: 然后我调用[self-AnimateBackground Horizontal:YES] 视图将显示:。发生的情况如下: 图像从一个意外(但始终相同

  • 下面的函数只是将视图移动到一个新位置。它不显示动画: