检测 UIView 在动画期间何时更改大小以使阴影移动

Detect when UIView changes size during animation for shadow to move

UIView 子类中,我对 override var bounds: CGRect 有以下 属性 覆盖:

@IBDesignable
class GEView: UIView {

    private var shadowView: UIView? {
        didSet {
            guard let superview = superview else { return }
            guard let shadowView = self.shadowView else { return }

            // Add the shadow to the superview, as the shadow cannot
            // also allow rounded corners simultaneously
            superview.addSubview(shadowView)
            shadowView.layer.zPosition = layer.zPosition - 1
            shadowView.edges(to: self)
        }
    }

    // CALLED WHEN SETTING @IBInspectable PROPERTIES
    /// Creates a shadow if one has not yet been created.
    private func createShadowIfNeeded() {
        guard shadowView == nil else { return }

        shadowView = UIView()

        shadowView?.layer.shadowPath = UIBezierPath(roundedRect:    bounds,
                                                    cornerRadius:   cornerRadius).cgPath
        shadowView?.layer.shouldRasterize = true
    }


    // THE PROPERTY TO ATTEMPT THE SHADOW MOVING
    override var bounds: CGRect {
        didSet {
            shadowView?.layer.shadowPath = UIBezierPath(roundedRect:    bounds,
                                                        cornerRadius:   cornerRadius).cgPath
        }
    }
}

尝试多次重新绘制阴影,因为当视图约束被动画化时边界发生变化(导致视图大小发生变化)。

但是,边界会立即发生变化,因为动画只是视觉效果。有没有办法让这个阴影在动画时跟随视图?如果这可以在 UIView 子类而不是动画块中,那就更好了,即 UIView.animate.

问题如下:

我希望在视图移动时阴影跟随。在 gif 的末尾,阴影位置和视图位置是正确的,因为覆盖忽略了动画并假装它已经设置了动画。

我该如何解决这个问题?

尝试更新 CustomViewlayoutSubviews() 中的 shadow,即

class CustomView: UIView {
    override func layoutSubviews() {
        super.layoutSubviews()

        self.layer.shadowRadius = 10.0
        self.layer.shadowOpacity = 1.0
        self.layer.shadowColor = UIColor.black.cgColor

        let oldPath = self.layer.shadowPath
        let newPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: 0.0).cgPath
        if oldPath != nil {
            let shadowPathAnimation: CABasicAnimation = CABasicAnimation(keyPath: "shadowPath")
            shadowPathAnimation.fromValue = oldPath
            shadowPathAnimation.toValue = newPath
            self.layer.add(shadowPathAnimation, forKey: "shadowAnimation")
            self.layer.shadowPath = newPath
        }
    }
}

class ViewController: UIViewController {
    @IBOutlet weak var customView: CustomView!
    @IBOutlet weak var trailingConstraint: NSLayoutConstraint!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        UIView.animate(withDuration: 3.0) {
            self.trailingConstraint.constant = 200.0
            self.view.layoutIfNeeded()
        }
    }
}