使用自定义 UIBezierPath 动画视图边框
Animate view borders with custom UIBezierPath
我正在尝试制作一个带有聊天功能的应用程序 "bubbles",我需要制作每个气泡状态之间的过渡动画。
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 Initializer,然后按照描述为 UIView 添加了一个扩展。
但是当我尝试更新单元格的状态时,没有任何反应,只是立即绘制路径。我该怎么办?
我附上了一些图片以了解发生了什么
我弄错了,用 maskLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 5).cgPath
替换了初始路径
但是现在这件事正在发生
您需要指定动画对象的 fromValue
属性。
这样,Core Animation 就知道如何在 from
和 to
值之间进行插值。
let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.path))
animation.fromValue = UIBezierPath(…).path
animation.toValue = path.cgPath
animation.duration = 1
顺便说一句,如果你想用 UIBezierPath
生成带有漂亮圆角的矩形(a.k.a.squircles),你可能需要查看我的 extension of UIBezierPath.
动画立即发生的原因是相同的路径分配给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
由于该路径是动画的预期结束值,因此您需要提供一个值作为动画来源。
注:路径动画为"undefined"
如果两条路径有不同数量的控制点或段。
我正在尝试制作一个带有聊天功能的应用程序 "bubbles",我需要制作每个气泡状态之间的过渡动画。
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 Initializer,然后按照描述为 UIView 添加了一个扩展。
但是当我尝试更新单元格的状态时,没有任何反应,只是立即绘制路径。我该怎么办?
我附上了一些图片以了解发生了什么
我弄错了,用 maskLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 5).cgPath
但是现在这件事正在发生
您需要指定动画对象的 fromValue
属性。
这样,Core Animation 就知道如何在 from
和 to
值之间进行插值。
let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.path))
animation.fromValue = UIBezierPath(…).path
animation.toValue = path.cgPath
animation.duration = 1
顺便说一句,如果你想用 UIBezierPath
生成带有漂亮圆角的矩形(a.k.a.squircles),你可能需要查看我的 extension of UIBezierPath.
动画立即发生的原因是相同的路径分配给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
由于该路径是动画的预期结束值,因此您需要提供一个值作为动画来源。
注:路径动画为"undefined" 如果两条路径有不同数量的控制点或段。