动画 CALayer 在 iOS 14 上不起作用

Animating CALayer is not working on iOS 14

更新到 Xcode12 和 iOS14 后,我在设置 CALayer 动画时遇到问题 - 用于 iOS13 的动画不适用于 iOS14。这是动画代码:

private func animateCellPress() {
    let lightShadowAnimation = CABasicAnimation(keyPath: "shadowOffset")
    lightShadowAnimation.fromValue = CGSize(width: -self.shadowRadius, height: -self.shadowRadius)
    lightShadowAnimation.toValue = CGSize(width: self.shadowRadius, height: self.shadowRadius)
    lightShadowAnimation.fillMode = .forwards;
    lightShadowAnimation.isRemovedOnCompletion = false;
    lightShadowAnimation.duration = self.animationDuration
    self.lightShadow.add(lightShadowAnimation, forKey: lightShadowAnimation.keyPath)

    let darkShadowAnimation = CABasicAnimation(keyPath: "shadowOffset")
    darkShadowAnimation.fromValue = CGSize(width: self.shadowRadius, height: self.shadowRadius)
    darkShadowAnimation.toValue = CGSize(width: -self.shadowRadius, height: -self.shadowRadius)
    darkShadowAnimation.fillMode = .forwards;
    darkShadowAnimation.isRemovedOnCompletion = false;
    darkShadowAnimation.duration = self.animationDuration
    self.darkShadow.add(darkShadowAnimation, forKey: darkShadowAnimation.keyPath)
}

lightShadow 和 darkShadow 存储为属性,这里是它们的初始化代码:

private func initializeDarkShadow() {
    darkShadow = CALayer()
    darkShadow.frame = bounds
    darkShadow.backgroundColor = backgroundColor?.cgColor
    darkShadow.cornerRadius = cornerRadius
    darkShadow.shadowOffset = CGSize(width: shadowRadius, height: shadowRadius)
    darkShadow.shadowOpacity = 1
    darkShadow.shadowRadius = shadowRadius
    darkShadow.shadowColor = Asset.Colors.darkShadow.color.cgColor
    let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
    darkShadow.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
    layer.insertSublayer(darkShadow, at: 0)
}

private func initializeLightShadow() {
    lightShadow = CALayer()
    lightShadow.frame = bounds
    lightShadow.backgroundColor = backgroundColor?.cgColor
    lightShadow.cornerRadius = cornerRadius
    lightShadow.shadowOffset = CGSize(width: -shadowRadius, height: -shadowRadius)
    lightShadow.shadowOpacity = 1
    lightShadow.shadowRadius = shadowRadius
    lightShadow.shadowColor = Asset.Colors.lightShadow.color.cgColor
    let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
    lightShadow.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
    layer.insertSublayer(lightShadow, at: 0)
}

有什么问题以及如何解决的想法吗?我也没有收到任何编译器错误或警告。控制台日志也为空。

这行得通。我认为每次调用动画 layoutSubviews 都会被调用,从而删除图层和动画。您可以在那里更新框架或检查是否已添加图层。如果这不是问题,则您的按下或触摸功能有问题。创建一个具有单一视图的项目并将其复制并粘贴到您的 ViewController 文件中。

import UIKit

class TableViewCell : UITableViewCell{
    let darkShadowColor = UIColor.green
    let lightShadowColor = UIColor.red
    let animationDuration : Double = 2
    
    var darkShadow = CALayer()
    var lightShadow = CALayer()
    let cornerRadius : CGFloat = 4
    let shadowRadius : CGFloat = 3
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        initializeDarkShadow()
        initializeLightShadow()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initializeDarkShadow()
        initializeLightShadow()
    }
    
    private func initializeDarkShadow() {
        darkShadow = CALayer()
        darkShadow.frame = bounds
        darkShadow.backgroundColor = backgroundColor?.cgColor
        darkShadow.cornerRadius = cornerRadius
        darkShadow.shadowOffset = CGSize(width: shadowRadius, height: shadowRadius)
        darkShadow.shadowOpacity = 1
        darkShadow.shadowRadius = shadowRadius
        darkShadow.shadowColor = darkShadowColor.cgColor
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
        darkShadow.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
        layer.insertSublayer(darkShadow, at: 0)
    }

    private func initializeLightShadow() {
        lightShadow = CALayer()
        lightShadow.frame = bounds
        lightShadow.backgroundColor = backgroundColor?.cgColor
        lightShadow.cornerRadius = cornerRadius
        lightShadow.shadowOffset = CGSize(width: -shadowRadius, height: -shadowRadius)
        lightShadow.shadowOpacity = 1
        lightShadow.shadowRadius = shadowRadius
        lightShadow.shadowColor = lightShadowColor.cgColor
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
        lightShadow.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
        layer.insertSublayer(lightShadow, at: 0)
    }
    
    func animateCellPress() {
        print("called")
        let lightShadowAnimation = CABasicAnimation(keyPath: "shadowOffset")
        lightShadowAnimation.fromValue = CGSize(width: -self.shadowRadius, height: -self.shadowRadius)
        lightShadowAnimation.toValue = CGSize(width: self.shadowRadius, height: self.shadowRadius)
        lightShadowAnimation.beginTime = CACurrentMediaTime()
        lightShadowAnimation.fillMode = .both;
        lightShadowAnimation.isRemovedOnCompletion = false;
        lightShadowAnimation.duration = self.animationDuration
        self.lightShadow.add(lightShadowAnimation, forKey: nil)


        let darkShadowAnimation = CABasicAnimation(keyPath: "shadowOffset")
        darkShadowAnimation.fromValue = CGSize(width: self.shadowRadius, height: self.shadowRadius)
        darkShadowAnimation.toValue = CGSize(width: -self.shadowRadius, height: -self.shadowRadius)
        darkShadowAnimation.beginTime = CACurrentMediaTime()
        darkShadowAnimation.fillMode = .both;
        darkShadowAnimation.isRemovedOnCompletion = false;
        darkShadowAnimation.duration = self.animationDuration
        self.darkShadow.add(darkShadowAnimation, forKey: nil)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.lightShadow.frame = self.bounds
        self.darkShadow.frame = self.bounds
    }
}

class ViewController: UIViewController {

    let identifier = "someCellID"
    lazy var tableView : UITableView = {
        let tv = UITableView(frame: self.view.bounds)
        tv.delegate = self
        tv.dataSource = self
        tv.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        tv.register(TableViewCell.self, forCellReuseIdentifier: identifier)
        return tv
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.view.addSubview(tableView)
    }
}

extension ViewController : UITableViewDelegate,UITableViewDataSource{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? TableViewCell{
            cell.selectionStyle = .none
            return cell
        }
        print("error")
        return UITableViewCell()
    }
    
    
    
    func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? TableViewCell{
            cell.animateCellPress()
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }
}