Ios 在动画视图上设置层动画

Ios 在动画视图上设置层动画,ios,swift,animation,Ios,Swift,Animation,在我的一个视图上设置图层动画时遇到问题。我用谷歌搜索了这个问题,但只使用CATransaction找到了答案,它假设我知道fromValue和toValue的范围。我在表格标题中有一个视图,单击该视图可调整自身大小。此视图是一个普通的ui视图,其动画效果与ui视图.animate()-块中的预期效果相同。此视图有一个子层CAGradientLayer,为其提供渐变背景色。当视图设置其高度的动画时,层不会随之设置动画。动画开始时,层立即更改其边界 为了确保图层整体大小正确(在初始化/加载/屏幕旋转

在我的一个视图上设置图层动画时遇到问题。我用谷歌搜索了这个问题,但只使用
CATransaction
找到了答案,它假设我知道
fromValue
toValue
的范围。我在
表格标题中有一个视图,单击该视图可调整自身大小。此视图是一个普通的
ui视图
,其动画效果与
ui视图.animate()
-块中的预期效果相同。此视图有一个子层
CAGradientLayer
,为其提供渐变背景色。当视图设置其高度的动画时,层不会随之设置动画。动画开始时,层立即更改其边界

为了确保图层整体大小正确(在初始化/加载/屏幕旋转等过程中),我被告知要这样做:

override func layoutSubviews() {
    super.layoutSubviews()
    gradientLayer.frame = backgroundView.bounds
}
它每次都会得到正确的大小,但它从来没有为它设置动画

要执行视图动画,请执行以下操作:

self.someLabelHeightConstraint.constant = someHeight
UIView.animate(withDuration: 0.3, animations: { [weak self] in                
    self?.layoutIfNeeded()
})
这非常有效,但是我假设
layoutfneed()
在某个时候调用
layoutSubviews
,我假设这会破坏我添加到块中的任何CALayer动画

如您所见,我只更改视图内部视图上约束集的常数,因此我实际上不知道动画完成时实际标题视图的大小。我可能会做一些数学来计算它会是什么,但这似乎没有必要


没有更好的方法可以做到这一点吗?

您需要删除
CALayer

添加此代码

gradientLayer.actions = ["position": NSNull(),"frame":NSNull(),"bounds":NSNull()]

在动画过程中,有很多方法可以更新子层的
,但最优雅的解决方案是让
UIKit
为您解决这个问题。创建一个子类
UIView
,它是一个
CAGradientLayer
。创建视图时,将为您创建
CAGradientLayer
。当您设置视图帧的动画时,渐变层将为您优雅地设置动画

@IBDesignable
public class GradientView: UIView {

    @IBInspectable public var startColor: UIColor = .white { didSet { updateColors() } }
    @IBInspectable public var endColor:   UIColor = .black { didSet { updateColors() } }

    override open class var layerClass: AnyClass { return CAGradientLayer.self }

    override public init(frame: CGRect = .zero) {
        super.init(frame: frame)
        config()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        config()
    }

    private func config() {
        updateColors()
    }

    private func updateColors() {
        let gradientLayer = layer as! CAGradientLayer

        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
    }

}
注意,我已经将这个
@IBDesignable
设置为可设计的,这样您就可以将它放在框架目标中,然后在IB中使用它,但这取决于您。这不是必需的。主要问题是覆盖
layerClass
,以便UIKit在为视图设置动画时处理层的动画


这将解决什么问题?它会使我的图层自动与UIView.animate-code一起工作,还是会使我的图层自己的CATTransaction动画与UIView.animate一起工作?这很有魅力,谢谢!但我不太清楚为什么。发生了什么事?UIView中的原始CALayer是否具有内置逻辑,而您实际上制作了一个UIView,其中原始CALayer是一个CAGradientLayer,这给了它所有的魔力?我最初认为是这样,但当我试图设置self.layer=gradientLayer时,我被告知self.layer是只读的。您的解决方案非常出色。是的,您不能在事后使用
self.layer=gradientLayer
更改图层,而是指定
layerClass
,以便UIKit同时执行原始实例化和动画。一旦熟悉了这项技术,它实际上会更容易,但它不是很明显,是吗?这是天才!Thanks@iVentis不,这不适用于
CAShapeLayer
,因为您需要更新
路径。选项包括
CABasicAnimation
CADisplayLink
驱动动画。最简单的选项是在
绘制(:)
方法中渲染边框(并使用
内容模式
。重画
)。。。笔划不是完美的中间动画,但如果动画相当短,没有人会注意到。但是,所有这些都超出了这个问题的范围,我建议你发布你自己的…@Rob谢谢你的快速回答!我通过使用相同的动画选项设置层的动画解决了这个问题。