检测 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 的末尾,阴影位置和视图位置是正确的,因为覆盖忽略了动画并假装它已经设置了动画。
我该如何解决这个问题?
尝试更新 CustomView
的 layoutSubviews()
中的 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()
}
}
}
在 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 的末尾,阴影位置和视图位置是正确的,因为覆盖忽略了动画并假装它已经设置了动画。
我该如何解决这个问题?
尝试更新 CustomView
的 layoutSubviews()
中的 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()
}
}
}