如何在复杂的层次结构上下同步CALayer和UIView动画 [英] How to synchronize CALayer and UIView animations up and down a complex hierarchy

查看:64
本文介绍了如何在复杂的层次结构上下同步CALayer和UIView动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请参见如何在整个层次结构中管理CALayer动画涉及仅与如何同步父子层动画有关的后续问题。

See How to manage CALayer animations throughout a hierarchy for a follow-up question that is concerned just with how to synchronize parent-child layer animations.

这是一个设计问题,涉及在不同的位置运行相关动画

This is a design question concerning running dependent animations at different levels of the view hierarchy in response to animations up the hierarchy.

我有一个容器控制器,该容器控制器具有任意数量的子控制器。父控制器将这些内容组织在屏幕上,并且在各个地方都需要更改其子视图的大小和位置。

I have a container controller that has any number of child controllers. The parent controller organizes this content on the screen and at various points needs to change the size and positions of its children views.

我正在尝试为每个子视图设置动画视图以将其大小/形状/位置从其原始起点转换到目的地。基本的第一遍操作和一些基本的动画就可以完成工作。

I'm trying to animate each of these child views to transition its size/shape/position from their original starting point to the destination. A basic first pass with some basic animations starts to get the job done.

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

Things get more complicated though by the fact that some of the views being resized should also be performing animations on the contents of the view. Imagine a child view with centered content. As the child is shrunk or expanded, the centered content should be animated alongside the outer animation to compensate for the bounds changes so that the content stays centered.

进一步使事情复杂化,对于每个子视图,我也都有一个遮罩层,需要在该子视图的动画旁边进行动画处理。我还有些手势不需要使用任何动画来进行过渡-因此,我需要一种有时为整个视图/图层树设置动画的方法,有时不需要。

To further complicate matters, I also have a mask layer for each child view that needs to be animated alongside the child’s animation. I also have some gestures that require NO animations to be used for transitions - so I need a way to sometimes animate the whole view/layer tree, and sometimes not.

所以所有这些都为我提供了一个类似以下内容的体系结构

So all of this gives me an architecture where I have something like the following

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

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

Now my question is really one of maintainability. I can animate each of these parts using explicit or implicit animations. What I need to figure out is what’s the best way to make sure that all of the animations being done are done using the same duration and timing function. At present, I trigger a lot of these off of property changes. In some cases the property changes come from layoutSubviews (triggered from setNeedsLayout).

因此,设置这些动画(尤其是显式动画)的最佳策略是什么。我能从CATransaction中获取价值是我所能做的最好的事情吗?我担心并不是在每种情况下都需要对每个属性进行动画处理(就像在辅助视图中一样)-我已经打开/关闭setDisableActions来强制/拒绝某些属性动画。

So, what’s the best strategy for setting up these animations, especially the explicit ones. Is the best that I can do just picking up values from CATransaction? My fear is that not every property needs to be animated in every case (like in the auxiliary views) - I already am flipping setDisableActions on/off to force/deny some property animations.

应该使用CATransaction触发显式视图动画的设置吗?如何将为UIView动画指定的参数绑定到将用于基础层的参数?以下代码似乎可以完成工作,但看起来确实很丑。

Should CATransaction be used to trigger the setup of explicit view animations? How do I bind the parameters specified for a UIView animation to the parameters that will be used for the underlying layers? The following code seems to get the job done, but seems really ugly.

-(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已退出,因为我需要在其中执行所有这些动画

I think that UIViewControllerTransitionCoordinator is out because I need to do all of these animations in response to user actions, not just external things, like rotations or frame changes.

推荐答案

有一些选择要考虑:


  1. 对于UIView过渡,您可以传递 UIViewAnimationOptionLayoutSubviews 选项。这将为子视图之间的更改设置动画,在您刚刚更改了框架的视图上调用 layoutSubviews 之前和之后。

  2. 而不是使用 layoutSubviews ,您可以在 setBounds: setFrame:上覆盖您的 UIView CALayer 子类。这样,如果在动画块中调用它们,则子视图将与超级视图一起进行动画处理。如果未在动画块中调用它们,它们将立即更新。

  1. For UIView transitions, you can pass the UIViewAnimationOptionLayoutSubviews option. This will animate the changes between subviews before and after calling layoutSubviews on the view whose frame you just changed.
  2. Instead of using layoutSubviews at all, you could override setBounds: or setFrame: on your UIView and CALayer subclasses. This way, if they're called within an animation block, the subviews will animate together with the superview. If they're not called within an animation block, they'll update instantly.




我的担心是并不是在每种情况下都需要对每个属性进行动画处理(如在辅助视图中一样)-我已经打开/关闭setDisableActions以强制/拒绝某些属性动画。

My fear is that not every property needs to be animated in every case (like in the auxiliary views) - I already am flipping setDisableActions on/off to force/deny some property animations.

通常,如果您希望将其动画化,请将其放在动画块中,否则,则不要。显然,它会变得比这更复杂,这就是为什么苹果有时会有一个带有 animated 参数的二传手(例如 setSelected:animated:)。

Generally, if you want it animated, put it in an animation block, and if you don't, don't. Obviously, it can get more complex than this, which is why Apple sometimes has a setter with an animated argument (like setSelected:animated:).

如果您有时会启用属性,有时会关闭属性,请自己遵循这种模式。一种可能的实现方式:

If you have sometimes on, sometimes off properties, follow this pattern yourself. One possible implementation:

- (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];
    }
}




我的问题是是可维护性之一。

My question is really one of maintainability.

是的,听起来您正在考虑某种巨型对象,可以为您管理所有动画可能性。抵制这种诱惑。让每个视图负责为其自己的子视图设置动画,并 tell 一个视图(不要问)是否应对这些更改进行动画处理。

Yes, it sounds like you're thinking about some kind of giant object that manages all the animation possibilities for you. Resist this temptation. Let each view be responsible for animating its own subviews, and tell a view (don't let it ask) whether or not these changes should be animated.


我认为UIViewControllerTransitionCoordinator没用了,因为我需要做所有这些动画来响应用户操作,而不仅仅是响应外部事物,例如旋转或帧更改。

I think that UIViewControllerTransitionCoordinator is out because I need to do all of these animations in response to user actions, not just external things, like rotations or frame changes.

是的,这是正确的。请勿为此使用 UIViewControllerTransitionCoordinator

Yes, that's correct. Don't use UIViewControllerTransitionCoordinator for this.

这篇关于如何在复杂的层次结构上下同步CALayer和UIView动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆