代码之家  ›  专栏  ›  技术社区  ›  Max Kraev

使用自定义UIBezierPath设置视图边框动画

  •  0
  • Max Kraev  · 技术社区  · 6 年前

    我正在尝试制作一个带有聊天“泡泡”的应用程序,我需要在每个泡泡状态之间设置一个转换动画。

    extension UIView {
        func makeRoundedCorners(topLeftRad: Double, topRightRad: Double, bottomRightRad: Double, bottomLeftRad: Double) {
            let path = UIBezierPath(roundedRect: self.bounds, topLeftRadius: CGFloat(topLeftRad), topRightRadius: CGFloat(topRightRad), bottomRightRadius: CGFloat(bottomRightRad), bottomLeftRadius: CGFloat(bottomLeftRad))
            let maskLayer = CAShapeLayer()
            maskLayer.path = path.cgPath
    
            let animation = CABasicAnimation(keyPath: "path")
            animation.toValue = path.cgPath
            animation.duration = 1
    
            maskLayer.add(animation, forKey: "makeRoundedCorners")
            self.layer.mask = maskLayer
        }
    }
    
    extension UIBezierPath {
        convenience init(roundedRect rect: CGRect, topLeftRadius r1: CGFloat, topRightRadius r2: CGFloat, bottomRightRadius r3: CGFloat, bottomLeftRadius r4: CGFloat) {
            let left  = CGFloat(Double.pi)
            let up    = CGFloat(1.5*Double.pi)
            let down  = CGFloat(Double.pi / 2)
            let right = CGFloat(0.0)
            self.init()
    
            addArc(withCenter: CGPoint(x: rect.minX + r1, y: rect.minY + r1), radius: r1, startAngle: left,  endAngle: up,    clockwise: true)
            addArc(withCenter: CGPoint(x: rect.maxX - r2, y: rect.minY + r2), radius: r2, startAngle: up,    endAngle: right, clockwise: true)
            addArc(withCenter: CGPoint(x: rect.maxX - r3, y: rect.maxY - r3), radius: r3, startAngle: right, endAngle: down,  clockwise: true)
            addArc(withCenter: CGPoint(x: rect.minX + r4, y: rect.maxY - r4), radius: r4, startAngle: down,  endAngle: left,  clockwise: true)
            close()
        }
    }
    

    所以我编写了一个自定义的UIBeziePath初始值设定项,然后如前所述为UIView添加了一个扩展。

    但当我试图更新细胞的状态时,什么也没发生,只是立刻画出路径。我该怎么办?

    我附上了一些照片想知道发生了什么事

    enter image description here enter image description here

    maskLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 5).cgPath

    但现在这件事发生了

    enter image description here

    2 回复  |  直到 6 年前
        1
  •  1
  •   David Rönnqvist    6 年前

    动画立即发生的原因是相同的路径被指定给 maskLayer 用作 toValue

    let maskLayer = CAShapeLayer()
    maskLayer.path = path.cgPath // same path used here...
    
    let animation = CABasicAnimation(keyPath: "path")
    animation.toValue = path.cgPath // ... as here
    animation.duration = 1
    
    maskLayer.add(animation, forKey: "makeRoundedCorners")
    self.layer.mask = maskLayer
    

    由于该路径是动画的预期结束值,因此需要提供一个要从中设置动画的值。

    注: 如果两条路径具有不同数量的控制点或段。

        2
  •  1
  •   Vin Gazoil    6 年前

    您需要指定 fromValue 动画对象的属性。
    这样,核心动画就知道如何在 from to 价值观。

    let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.path))
    animation.fromValue = UIBezierPath(…).path
    animation.toValue = path.cgPath
    animation.duration = 1
    

    顺便说一下,如果你想用 UIBezierPath ,您可能想查看我的 extension of UIBezierPath .