【问题标题】:CAShapeLayer is appearing before ViewsCAShapeLayer 出现在 Views 之前
【发布时间】:2023-06-18 05:28:01
【问题描述】:

我有两个视图,它们之间位于可调整大小的线(使用 CAShapeLayer 视图)。我面临的问题是,尽管图层上有动画,但它的出现速度比视图的变化快。我知道图层的动画完全不同,但不明白我的错在哪里。如果我做错了什么,请告诉我。

这是我的图层动画的代码(也使用了“strokeStart”,但没有用):

override func layoutSubviews() {
    super.layoutSubviews()
    let centerX = bounds.size.width / 2
    let path = CGMutablePath()
    path.addLines(between: [CGPoint(x: centerX, y: 0), CGPoint(x: centerX, y: frame.height)])
    dashedLayer.path = path
    dashedLayer.frame = bounds

    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.fromValue = height
    animation.toValue = bounds.size.height
    height = bounds.size.height
    animation.duration = 0.3
    dashedLayer.add(animation, forKey: nil)
}

视图动画的代码(因为修改了视图,我为layoutIfNeeded设置了动画):

UIView.animate(withDuration: 0.3, animations: {
    self.view.layoutIfNeeded()
    ...

【问题讨论】:

    标签: ios swift calayer cashapelayer cabasicanimation


    【解决方案1】:

    我认为解决这个问题的一种简单方法是像这样为约束常量设置动画:

      @IBOutlet weak  var heightConstraint: NSLayoutConstraint!
    
      UIView.animate(withDuration: 3, animations: {
    
            self. heightConstaint.constant = 300 // This constant is the height of top big view. 
    
            self.view.layoutIfNeeded()}
    

    CAShapeLayer 所在的另一个视图。我称之为line View。它的高度应限制为与top big view 的高度相同。

    line view,可以添加动画。这应该与您的实现类似。

       override func didMoveToSuperview() {
         super.didMoveToSuperview()
         dashedLayer.backgroundColor = UIColor.clear.cgColor
         layer.addSublayer(dashedLayer)
         height = bounds.size.height
       }
    
      override func layoutSubviews() {
        super.layoutSubviews()
        let centerX = bounds.size.width / 2
        let path = CGMutablePath()
        path.addLines(between: [CGPoint(x: centerX, y: 0), CGPoint(x: centerX, y: frame.height)])
        dashedLayer.path = path
        dashedLayer.lineWidth = 3.0
        dashedLayer.strokeColor = UIColor.blue.cgColor
    
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = height / bounds.size.height
        animation.toValue = 1.0 
        animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeInEaseOut)
        height = bounds.size.height
        animation.duration = 3.0
        dashedLayer.add(animation, forKey: nil)
    }
    

    这里正在扩展。您可以自己修改代码以适应合同。

    以下是倒车动画。

    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        dashedLayer.backgroundColor = UIColor.clear.cgColor
        layer.addSublayer(dashedLayer)
        height = bounds.size.height
          clipsToBounds = true
    }
    
    
    override func layoutSubviews() {
        super.layoutSubviews()
        let centerX = bounds.size.width / 2
        let path = CGMutablePath()
        path.addLines(between: [CGPoint(x: centerX, y: 0), CGPoint(x: centerX, y: max(height , bounds.size.height) )])
        dashedLayer.path = path
        dashedLayer.lineWidth = 3.0
        dashedLayer.strokeColor = UIColor.blue.cgColor
    
        let animation = CABasicAnimation(keyPath: "strokeEnd")
    
        if (height < bounds.size.height){
        animation.fromValue = height / bounds.size.height
            animation.toValue = 1.0}
    
        else {
            animation.fromValue = 1.0
            animation.toValue = bounds.size.height / height}
    
    
        animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeInEaseOut)
        height = bounds.size.height
        animation.duration = 3
        dashedLayer.add(animation, forKey: nil)
    }
    

    【讨论】:

    • 它可以工作,但是当涉及到向后动画时,它的行为就像以前一样
    • 我现在添加倒车的。
    • 为什么不只是动画路径而不是描边?
    • 他可能需要一些背景图片作为路径
    • @E.Coms 非常感谢您!除了 CGPoint 中的 max() 之外,已经尝试过类似的方式
    【解决方案2】:

    您当前的代码存在一些问题。目前您正在更改没有动画的路径,因此它会立即更新。 strokeEnd 的值也是 0 到 1,所以现在你的路径总是有一个完整的笔划。

    您应该为路径更改而不是笔划设置动画。

    override func layoutSubviews() {
        super.layoutSubviews()
        let centerX = bounds.size.width / 2
        let path = CGMutablePath()
        path.addLines(between: [CGPoint(x: centerX, y: 0), CGPoint(x: centerX, y: frame.height)])
        dashedLayer.path = path
        dashedLayer.frame = bounds
    
        let animation = CABasicAnimation(keyPath: "path")
        animation.duration = 0.3
        animation.fromValue = dashedLayer.path
        animation.toValue = path
        dashedLayer.add(animation, forKey: "pathAnimation")
    }
    

    【讨论】: