使用 UINavigationController 和 UINavigationBar 时图层 y 位置的动画错误

Posted

技术标签:

【中文标题】使用 UINavigationController 和 UINavigationBar 时图层 y 位置的动画错误【英文标题】:Wrong animation of layer's y position when using a UINavigationController and UINavigationBar 【发布时间】:2015-02-20 07:52:56 【问题描述】:

我像往常一样在viewWillAppear: 中设置和自定义UINavigationController's 导航栏。然后我有一个NSTimerviewDidLoad 中以0.6 的时间间隔发射。这个计时器触发我的动画代码。

我正在使用 Facebook 的 POP 框架,我想要做的就是使用以下代码稍微改变图层的 y 位置并反弹一点:

// Move object up
POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY];
positionAnimation.toValue = @(self.myView.frame.origin.y - 5);
positionAnimation.springBounciness = 20;
positionAnimation.velocity = @(2000);
[self.myView.layer pop_addAnimation:positionAnimation1 forKey:@"positionAnimation"];

出于某种原因,这总是导致视图位于UINavigationBar 下方的一半。如果我切换到以下代码,视图将转到正确的位置:

POPSpringAnimation *frameAnimation = [POPSpringAnimation animation];
frameAnimation.property = [POPAnimatableProperty propertyWithName:kPOPViewFrame];
frameAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(12, 24, 91, 116)];
[self.myView.layer pop_addAnimation:secondFrameAnimation forKey:@"frameAnimation"];

问题是,如果我尝试使用 frameAnimation 属性向 frameAnimation 添加任何反弹,应用程序崩溃并且我收到以下错误:

'Invalid value', reason: '2000 should be of type CGRect'

如果我将我的 positionAnimation 代码放入一个不使用带有导航栏的 UINavigationController 的新项目中,那么一切正常,并且视图动画到正确的 y 位置。唯一的其他区别也是我当前的项目是从nib/xib 文件加载此视图,但一切都是在新项目中以编程方式完成的。我不确定这是否与此有关。

那么如何使用带有导航栏的nav控制器,又能成功使用位置动画呢?

编辑:

我现在可以正常运行动画,但仍然遇到一些非常奇怪的行为。这是成功移动视图而不是将其放在UINavigationBar 下方的代码:

    // Fade in
    POPSpringAnimation *opacityAnimation = [POPSpringAnimation animation];
    opacityAnimation.property = [POPAnimatableProperty propertyWithName:kPOPLayerOpacity];
    opacityAnimation.toValue = @(1.0);
    [self.design.layer pop_addAnimation:opacityAnimation forKey:@"opacityAnimation"];

    // Move object up
    POPSpringAnimation *positionAnimation1 = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY];
    positionAnimation1.toValue = @(self.design.frame.origin.y - 10);
    positionAnimation1.springBounciness = 15;
    positionAnimation1.velocity = @(2000);
    [self.design.layer pop_addAnimation:positionAnimation1 forKey:@"positionAnimation"];
    [positionAnimation1 setCompletionBlock:^(POPAnimation *anim, BOOL success) 
        //
        NSLog(@"design frame: %@", NSStringFromCGRect(self.design.frame));

    ];

这就是奇怪的地方。当上述动画的完成块触发时,帧记录如下:

design frame: 12, 36, 91, 116

没错。但是,如果我更改位置动画的以下行并仅切换 36 的 y 值,它会再次出现在 UINavigationBar 下方的一半:

positionAnimation1.toValue = @(36);

那么为什么我在使用 36 的 y 值时会得到一个不好的结果,如果我使用 self.design.frame.origin.y - 10 的 y 值,它最终还是 36,为什么它会起作用?

【问题讨论】:

【参考方案1】:

动画kPOPLayerPositionY控制图层中心位置的y值,而不是帧上的原点。以下应该有效:

positionAnimation1.toValue = @(36 + 116 * 0.5);

对于您之前提到的速度错误,这是因为速度参数中的组件数量必须与正在动画的属性中的组件数量相匹配。因此,如果您要为 CGRect 设置动画,则需要将 CGRect 传递给速度,其中每个组件都是相应组件的速度。

【讨论】:

不知道 kPOPLayerPositionY 专注于中心而不是框架的原点。谢谢! positionAnimation1.toValue = @(self.design.center.y - 10);

以上是关于使用 UINavigationController 和 UINavigationBar 时图层 y 位置的动画错误的主要内容,如果未能解决你的问题,请参考以下文章

UINavigationcontroller 中未使用的视图会发生啥?

使用 push segue 时 UINavigationController 是不是强制

UINavigationController - 使用 UIBlurEffect 清除背景

一起使用 UITabBarController 和 UINavigationController

iPhone - UINavigationController - 使用 CATransaction 自定义动画

如何在 SwiftUI 中使用 UINavigationController