如何使CALayer和UIView动画在复杂层级结构中同步上下移动

3
请见如何在整个层次结构中管理CALayer动画,这是一个后续问题,只涉及如何同步父子层动画。
这是一个关于在响应来自层次结构的动画时,在不同级别的视图层次结构中运行依赖动画的设计问题。
我有一个容器控制器,其中包含任意数量的子控制器。父控制器组织屏幕上的内容,并且在各个点需要更改其子视图的大小和位置。
我试图对每个子视图进行动画处理,使其从原始起始点到目标的大小/形状/位置转换。一些基本的动画开始完成工作。
然而,有些被调整大小的视图也应该对视图内容执行动画。想象一下一个带有居中内容的子视图。当子视图缩小或扩展时,中心内容应该与外部动画一起进行动画处理,以补偿边界变化,使内容保持居中状态。
为了进一步复杂化问题,我还有一个需要与子动画一起进行动画处理的mask层。我还有一些手势需要使用没有动画的转换 - 所以我需要一种方法来有时对整个视图/层树进行动画处理,有时则不需要。
因此,所有这些都给我提供了一个架构,就像以下的结构一样。
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个回答

1

有几种选择需要考虑:

  1. 对于UIView的转换,您可以传递UIViewAnimationOptionLayoutSubviews选项。这将在调用刚更改框架的视图上的layoutSubviews之前和之后动画显示子视图之间的更改。
  2. 您可以完全不使用layoutSubviews,而是重写setBounds:setFrame:在您的UIViewCALayer子类上。这样,如果它们在动画块内调用,则子视图将与父视图一起动画。如果它们未在动画块内调用,则将立即更新。

我的担心是并非每个属性在每种情况下都需要进行动画处理(例如在辅助视图中)- 我已经翻转了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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接