想象一种高而瘦的视图,我们可以说它看起来像一把梯子。
它高达100个单位。我们对其进行动画处理,使其达到整个屏幕的高度。因此,伪代码如下:
func expandLadder() {
view.layoutIfNeeded()
UIView.animate(withDuration: 4 ...
ladderTopToTopOfScreenConstraint = 0
ladderBottomToBottomOfScreenConstraint = 0
view.layoutIfNeeded()
}
没问题。
不过,我们在 layoutSubviews 中绘制梯子。 (我们的梯子只是一条粗黑线。)
@IBDesignable class LadderView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
heightNow = frame size height
print("I've recalculated the height!")
shapeLayer ...
topPoint = (0, 0)
bottomPoint = (0, heightNow)
p.addLines(between: [topPoint, bottomPoint])
shapeLayer!.path = p
shapeLayer add a CABasicAnimation or whatever
layer.addSublayer(shapeLayer!)
}
没问题。
所以我们只是创建一条填充视图高度“heightNow”的线段。
当然,问题在于,当您这样做时...
func expandLadder() {
view.layoutIfNeeded()
UIView.animate(withDuration: 4 ...
ladderToTopOfScreenConstraint = 0
ladderBottomOfScreenConstraint = 0
view.layoutIfNeeded()
}
当你这样做时,LayoutSubviews
(或setBounds、draw#rect或其他任何你能想到的东西)只在UIView.animate动画之前和之后调用。这真的很麻烦。
在示例中,“实际”的梯子,即shapeLayer,在你动画视图L的大小之前会跳转到下一个值。也就是说:“我已经重新计算了高度!”在UIView.animate动画之前和之后只被调用一次。假设你不剪切子视图,你会在每个L长度的动画之前看到“错误的,即将到来的”大小。
解决方案是什么?
顺便说一句,当然你可以使用draw#rect并自己进行动画,即使用CADisplayLink(如Josh所提到的)。所以没问题。只是使用图层/路径绘制形状更加容易:我的问题是如何使示例中的setup()代码在涉及的视图约束的UIView动画的每个步骤中运行。