如何同步CALayer和UIView动画上下复杂的层次结构

请参阅如何在整个层次结构中管理CALayer动画,以了解如何同步父子图层动画的后续问题。

这是一个设计问题,涉及在视图层次结构的不同层次上运行依赖动画,以响应层次结构中的动画。

我有一个容器控制器,有任何数量的子控制器。 父母控制者在屏幕上组织这些内容,并且在各个点上需要改变其子视图的大小和位置。

我试图为每个这些子视图设置动画,以将其大小/形状/位置从其原始起点转移到目标。 带有一些基本动画的基本第一遍开始完成工作。

事情变得更加复杂,尽管事实上一些被调整大小的视图也应该对视图的内容执行动画。 设想一个中心内容的儿童视图。 随着孩子缩小或扩大,居中内容应与外部动画一起动画,以补偿边界变化,以便内容保持居中。

为了进一步复杂化,我还为每个子视图设置了一个遮罩层,这个遮罩层需要与孩子的动画一起动画。 我也有一些手势需要没有动画用于转换 - 所以我需要一种方法来动画整个视图/图层树,有时不需要。

所以这一切都给了我一个架构,让我拥有如下的东西

ContainerViewController.view
 -> auxiliary and decorative views
 -> WrapperView (multiple)
    ----> mask layer
    -> Child controller view
       -> subviews & layers

现在我的问题真的是可维护性。 我可以使用显式或隐式动画来动画每个部分。 我需要弄清楚的是确保所有动画的完成都使用相同的持续时间和计时功能完成的最佳方式是什么。 目前,我触发了很多这些财产变化。 在某些情况下,属性更改来自layoutSubviews(由setNeedsLayout触发)。

那么,设置这些动画的最佳策略是什么,特别是明确的动画。 我能做的最好的只是从CATransaction中获取价值吗? 我的恐惧是,并​​非每一个属性都需要在任何情况下都进行动画处理(如在辅助视图中) - 我已经在打开/关闭setDisableActions以强制/拒绝某些属性动画。

是否应该使用CATransaction来触发显式视图动画的设置? 如何将为UIView动画指定的参数绑定到将用于底层的参数? 下面的代码似乎完成了工作,但看起来真的很难看。

-(void) animateForReason:(enum AnimationReason) animationReason
              animations:(void(^)()) animationBlock completion:(void(^)(BOOL)) completionBlock {
    const auto animationDuration = 3.0; // make this long to be noticeable!
    [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         [CATransaction begin];
                         [CATransaction setAnimationDuration:animationDuration];
                         animationBlock();
                         [CATransaction commit];
                     }completion:completionBlock];
}

我认为UIViewControllerTransitionCoordinator已经出来了,因为我需要做所有这些动画来响应用户的操作,而不仅仅是外部的东西,比如旋转或者框架变化。


有几个选项需要考虑:

  • 对于UIView转换,您可以传递UIViewAnimationOptionLayoutSubviews选项。 这将在刚刚更改了框架的视图上调用layoutSubviews之前和之后的子视图之间的变化动画化。
  • 根本不用layoutSubviews ,你可以在你的UIViewCALayer子类上覆盖setBounds:setFrame: 这样,如果它们在动画块中被调用,则子视图将与超级视图一起动画。 如果他们没有在动画块中调用,他们会立即更新。
  • 我的恐惧是,并​​非每一个属性都需要在任何情况下都进行动画处理(如在辅助视图中) - 我已经在打开/关闭setDisableActions以强制/拒绝某些属性动画。

    一般来说,如果你想动画,把它放在一个动画块中,如果你不这样做,就不要。 显然,它可能比这更复杂,这就是为什么Apple有一个带有animated参数的setter(比如setSelected:animated:

    如果您有时有时,有时会关闭属性,请自行遵循此模式。 一个可能的实现:

    - (void) setNumberOfWidgets:(int)widgetCount animated:(BOOL)animated {
        BOOL oldAnimationValue = [UIView areAnimationsEnabled];
    
        if (!animated) {
            [UIView setAnimationsEnabled:NO];
        }
    
        // a related property which may or may not cause an animation
        self.someOtherProperty = someValue;
    
        if (!animated) {
            [UIView setAnimationsEnabled:oldAnimationValue];
        }
    }
    

    我的问题真的是可维护性。

    是的,这听起来像是在考虑某种管理所有动画可能性的巨型对象。 抵制这种诱惑。 让每个视图都负责动画自己的子视图,并告诉一个视图(不要让它问)这些更改是否应该动画化。

    我认为UIViewControllerTransitionCoordinator已经出来了,因为我需要做所有这些动画来响应用户的操作,而不仅仅是外部的东西,比如旋转或者框架变化。

    对,那是正确的。 不要为此使用UIViewControllerTransitionCoordinator

    链接地址: http://www.djcxy.com/p/74173.html

    上一篇: How to synchronize CALayer and UIView animations up and down a complex hierarchy

    下一篇: CAKeyFrameAnimation of transform property on CALayer not working as expected