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

时间:2014-11-12 04:25:09

标签: ios uikit core-animation calayer

有关如何同步父子图层动画的后续问题,请参阅How to manage CALayer animations throughout a hierarchy

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

我有一个容器控制器,它有任意数量的子控制器。父控制器在屏幕上组织此内容,并且在各个点需要更改其子视图的大小和位置。

我正在尝试为每个子视图设置动画,以将其大小/形状/位置从原始起点转换到目标。带有一些基本动画的基本首次通过开始完成工作。

事情变得更复杂,但事实上,一些被调整大小的视图也应该对视图的内容执行动画。想象一下具有居中内容的子视图。当孩子缩小或扩展时,居中的内容应该与外部动画一起动画,以补偿边界变化,使内容保持居中。

为了使问题更加复杂,我还为每个子视图都有一个遮罩层,需要在孩子的动画旁边进行动画处理。我也有一些手势需要没有动画用于过渡 - 所以我需要一种方法来有时动画整个视图/层树,有时不动画。

所以这一切都给了我一个架构,我有类似下面的内容

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已经出局了,因为我需要做所有这些动画以响应用户操作,而不仅仅是外部事物,如旋转或帧更改。

1 个答案:

答案 0 :(得分:1)

有几个选项需要考虑:

  1. 对于UIView过渡,您可以传递UIViewAnimationOptionLayoutSubviews选项。这将在您刚刚更改了框架的视图上调用layoutSubviews之前和之后为子视图之间的更改设置动画。
  2. 您可以覆盖layoutSubviewssetBounds:子类上的setFrame:UIView,而不是使用CALayer。这样,如果在动画块中调用它们,则子视图将与超视图一起动画化。如果他们未在动画块中调用,则他们会立即更新。
  3.   

    我担心的是并非每个属性都需要动画(如辅助视图中) - 我已经开启/关闭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