【发布时间】:2025-12-24 04:00:07
【问题描述】:
我有一个自定义视图 CustomView,它可以为自己制作动画以响应 animate 消息:
// in a view controller
[self.customView animate];
-[CustomView animate]内部,逻辑如下:
- (void)animate {
for each subview {
startFrame = subview.frame;
endFrame = EndFrameFromStartFrame(startFrame);
subview.animation = AnimationLoopBetween(startFrame, endFrame);
}
}
* 这个块是伪代码。
也就是说,animate 方法检查每个子视图的当前帧,并为每个子视图生成一个动画结束帧,该帧本质上是一个比当前帧大固定比例的帧。然后,它为每个子视图创建一个动画,该动画改变其子视图的帧,在当前(或开始)帧和结束帧之间交替,之前计算。
一般来说,这种方法效果很好。它允许CustomView 正确地制作动画,而不管其超级视图的位置和大小如何。
然而,在少数情况下,CustomView(即视图控制器)的“用户”在其生命周期的早期就调用了animate——事实上,太早了,以至于 Auto Layout 还没有做出任何约束或布局通过。这意味着当CustomView 的所有子视图帧都是CGRectZero 时调用animate。正如您可能猜到的那样,这会导致动画的开始值和结束值计算不正确。
即使布局传递完成,并且视图的模型层具有适当的框架,CustomView 实例仍然不可见,因为它的子视图正在愉快地从一个零矩形动画到另一个。不好。
我应该如何重构这个动画行为,让这个类的用户可以随时调用animate而不产生负面影响?
以下是我考虑过的一些可能的答案,以及为什么它们对我来说似乎不满意:
在任何使用
CustomView的视图控制器中,推迟对animate的调用,直到viewDidLayoutSubviews。
这对使用该视图的视图控制器施加了一个笨拙的限制。在
CustomView的layoutSubviews方法中,先调用[super layoutSubviews],如果动画已经运行则重启。
一个有趣的想法,但CustomView有不止一个级别的子视图。因此,即使在[super layoutSubviews]之后,视图层次结构中更靠后的许多视图都没有有效的帧,这意味着animate仍然会出现异常。在
CustomView的layoutSubviews方法中,首先调用[super layoutSubviews],然后使用[<view> layoutIfNeeded]手动布局任何需要的视图帧,最后重新启动动画(如果它已经在运行)。
这实际上可能有效,但似乎不是一个好主意。我想尽可能将布局工作留给 Auto Layout。
【问题讨论】:
-
“我想尽可能将布局工作留给自动布局。”但是调用
super layoutSubviews确实执行自动布局。这就是自动布局是。在调用super之后将代码放入layoutSubviews是完全标准且正确的 - 包括在必要时更改约束并再次调用super。
标签: ios animation uiview autolayout