Анимация не работает на вставленном CAGradientLayer в качестве подслоя - PullRequest
0 голосов
/ 26 мая 2020

Я хочу выполнить анимацию (полная высота до 88 пикселей, анимация снизу вверх) при загрузке viewController. Поэтому я добавил UIView (animationView) в раскадровку, программно добавил градиент в viewDidLoad () и выполнил анимацию в viewDidAppear () следующим образом:

override func viewDidLoad() {
        super.viewDidLoad()
        self.animationView.applyGradient(with: [UIColor(red: 0, green: 91/255, blue: 200/255, alpha: 1), UIColor(red: 0, green: 131/255, blue: 232/255, alpha: 1)])
}

override func viewDidAppear(_ animated: Bool) {

        super.viewDidAppear(animated)

        //Perform animation
        self.animationVWBottomContraint.constant = self.view.bounds.height - 88.0

        UIView.animate(withDuration: 0.75,delay: 10, options: .curveEaseIn, animations: {
            self.view.layoutIfNeeded()
        }, completion: {(_) in
            DispatchQueue.main.asyncAfter(deadline: .now()+6) {
                self.animationView.isHidden = true
            }
        }
extension UIView {

 open func applyGradient(with colours: [UIColor]) {

        //Create a gradient and apply it to the sublayer.
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.name  = "grad1"
        gradient.colors = colours.map { $0.cgColor }
        gradient.startPoint = CGPoint(x: 0.0,y: 0.0)
        gradient.endPoint = CGPoint(x: 0.0,y: 1.0)
        self.layer.insertSublayer(gradient, at: 0)
    }
}

Если мы добавим одно изображение в качестве subview animationView, чтобы проверить, действует ли анимация, и мы увидим, что анимация происходит. Но слой CAGradient не имеет никакого эффекта.

Вместо градиента, если мы добавляем backgroundColor, анимация происходит так, как ожидалось.

override func viewDidLoad() {
        super.viewDidLoad()
        //self.animationView.applyGradient(with: [UIColor(red: 0, green: 91/255, blue: 200/255, alpha: 1), UIColor(red: 0, green: 131/255, blue: 232/255, alpha: 1)])
      self.animationView.backgroundColor = UIColor.blue
}

Это означает, что размер только что добавленного подслоя не изменяется в layoutIfNeeded (). Следовательно, я попытался принудительно вызвать макет или создать подкласс и добавить градиент как часть настраиваемого init.

self.animationView.layer.setNeedsLayout()
or 
self.animationView.layoutIfNeeded()
or
class GradientView : UIView {
    required init?(coder: NSCoder) {
        super.init(coder:coder)
        self.customInit()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.customInit()
    }

    func animate(){
        UIView.animate(withDuration: 0.25, delay: 2, options: .curveLinear, animations: {
            self.frame.size.height = 80.0
            self.layoutIfNeeded()
        }, completion: nil)
    }

    func customInit(){

        let containerView = UIView()
        self.addSubview(containerView)
        containerView.frame = self.bounds
        self.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        let gradient = CAGradientLayer()
               gradient.frame = self.bounds
               gradient.name  = "grad1"
               gradient.colors = [UIColor(red: 0, green: 91/255, blue: 200/255, alpha: 1), UIColor(red: 0, green: 131/255, blue: 232/255, alpha: 1)].map { $0.cgColor }
               gradient.startPoint = CGPoint(x: 0.0,y: 0.0)
               gradient.endPoint = CGPoint(x: 0.0,y: 1.0)
        containerView.layer.insertSublayer(gradient, at: 0)
    }
}

Но это не помогло.

Как решить проблему?

Заранее спасибо.

1 Ответ

0 голосов
/ 26 мая 2020

Это означает, что размер только что добавленного подслоя не изменяется в layoutIfNeeded ()

Слои не изменяют свой размер при изменении границы / рамки родительского представления, например: если вы применить тень или границу к виду, а затем изменить рамку границы вида / тень не будет обновляться автоматически. Вы должны изменить размер слоя на layoutSubviews, поэтому измените свой код на

class GradientView : UIView {
    private var gradient: CAGradientLayer?

    override func layoutSubviews() {
        super.layoutSubviews()
        self.gradient?.frame = self.bounds
    }

    required init?(coder: NSCoder) {
        super.init(coder:coder)
        self.customInit()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.customInit()
    }

    func animate(){
        UIView.animate(withDuration: 0.25, delay: 2, options: .curveLinear, animations: {
            self.frame.size.height = 80.0
            self.layoutIfNeeded()
        }, completion: nil)
    }

    func customInit(){
        let containerView = UIView()
        self.addSubview(containerView)
        containerView.frame = self.bounds
        self.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        self.gradient = CAGradientLayer()
        gradient?.frame = self.bounds
        gradient?.name  = "grad1"
        gradient?.colors = [UIColor(red: 0, green: 91/255, blue: 200/255, alpha: 1), UIColor(red: 0, green: 131/255, blue: 232/255, alpha: 1)].map { $0.cgColor }
        gradient?.startPoint = CGPoint(x: 0.0,y: 0.0)
        gradient?.endPoint = CGPoint(x: 0.0,y: 1.0)
        if let gradient = self.gradient {
            containerView.layer.insertSublayer(gradient, at: 0)
        }
    }
}

Надеюсь, это поможет

...