动画UIView上的动画层 [英] Animate layer on animated UIView

查看:94
本文介绍了动画UIView上的动画层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在其中一个视图上设置图层动画。我已经用Google搜索这个问题,但是只能使用 CATransaction 查找答案,假设我知道 fromValue toValue 的范围。我在 tableHeader 中有一个视图,该视图在单击时会自动调整大小。此视图是普通的 UIView ,并在 UIView.animate()块中进行动画设置。此视图具有 CAGradientLayer 作为子层,以为其提供渐变backgroundcolor。当视图为其高度设置动画时,该图层不会为其设置动画。动画开始时,该层会立即更改其边界。



为确保该层的整体大小正确(在初始化/加载/屏幕旋转等过程中),我一直在告诉执行此操作:

 重写func layoutSubviews(){
super.layoutSubviews()
gradientLayer。 frame = backgroundView.bounds
}

每次都获得正确的大小,但是从没有



要做我的视图动画,我这样做:

  self.someLabelHeightConstraint.constant = someHeight 
UIView.animate(withDuration:0.3,animations:{[weak self] in
self?.layoutIfNeeded()
})

效果很好,但我假设 layoutIfNeeded()调用 layoutSubviews 有时,我认为这会破坏我添加到块中的所有CALayer动画。



可以看到,我只改变常数在视图内部的视图上设置了一个约束,所以我实际上不知道动画完成后实际标题视图的大小。我可能可以做一些数学运算来弄清楚它会是什么,但这似乎是不必要的。



没有更好的方法吗?

解决方案

有动画方法可以在动画过程中更新子图层的 frame ,但最优雅解决方案是让 UIKit 帮您解决这个问题。创建一个子类 UIView ,其子类


I'm having trouble animating a layer on one of my views. I have googled the issue, but only find answers using CATransaction which assumes that I know the fromValue and toValue of its bounds. I have a view in a tableHeader that resizes itself when clicked. This view is an ordinary UIView and animates just as expected in an UIView.animate()-block. This view has a CAGradientLayer as a sublayer, to give it a gradient backgroundcolor. When the view animates its height, the layer does not animate with it. The layer changes its bounds immediately when the animation starts.

To make sure the layer gets the right size overall (during init/loading/screen rotation etc.) I have been told to do this:

override func layoutSubviews() {
    super.layoutSubviews()
    gradientLayer.frame = backgroundView.bounds
}

It gets the right size every time, but it never animates to it.

To do my view-animation, I do this:

self.someLabelHeightConstraint.constant = someHeight
UIView.animate(withDuration: 0.3, animations: { [weak self] in                
    self?.layoutIfNeeded()
})

which works perfectly, but I assume layoutIfNeeded() calls layoutSubviews at some point, which I assume will ruin any CALayer-animations I add into the block.

As you can see, I only change the constant of a constraint set on a view inside my view, so I actually don't know what the size of the actual header-view will be when the animation is completed. I could probably do some math to figure out what it'll be, but that seems unnecessary..

Are there no better ways to do this?

解决方案

There are kludgy ways to update a sublayer's frame during an animation, but the most elegant solution is to let UIKit take care of this for you. Create a subclass UIView whose layerClass is a CAGradientLayer. When the view is created, the CAGradientLayer will be created for you. And when you animate the view's frame, the gradient layer is animated gracefully for you.

@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]
    }

}

Note, I've made this @IBDesignable so you can put it in a framework target and then use it in IB, but that's up to you. That's not required. The main issue is the overriding of layerClass so that UIKit takes care of the animation of the layer as it animates the view.

这篇关于动画UIView上的动画层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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