Swift:从中心开始的 UIBezierPath 描边动画
Swift: UIBezierPath Stroke Animation from Center
我一直在用 Swift 制作一个简单的 UIBezierPath
动画。此路径包括创建一个带有彩色边框的圆角矩形。动画必须是彩色边框的绘制。为此,我创建了一个 CAShapeLayer
和 UIBezierPath(roundedRect:, cornerRadius: )
let layer = CAShapeLayer()
var viewPrueba = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
viewPrueba = UIView(frame: CGRectMake(self.view.frame.width/2-100, self.view.frame.height/2 - 100, 200, 200))
self.view.addSubview(viewPrueba)
let path = UIBezierPath(roundedRect: CGRectMake(0, 0, 200, 200), cornerRadius: 40.0)
layer.path = path.CGPath
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blueColor().CGColor
layer.strokeStart = 0.0
layer.strokeEnd = 0.0
layer.lineWidth = 4.0
layer.lineJoin = kCALineJoinRound
viewPrueba.layer.addSublayer(layer)
let tapGR = UITapGestureRecognizer(target: self, action: #selector(ViewController.anim))
self.view.addGestureRecognizer(tapGR)
}
func anim() {
let anim1 = CABasicAnimation(keyPath: "strokeEnd")
anim1.fromValue = 0.0
anim1.toValue = 1.0
anim1.duration = 4.0
anim1.repeatCount = 0
anim1.autoreverses = false
anim1.removedOnCompletion = false
anim1.additive = true
anim1.fillMode = kCAFillModeForwards
self.layer.addAnimation(anim1, forKey: "strokeEnd")
}`
效果很好。唯一的问题是动画从正方形的左上部分开始,而不是从顶部中心开始。我该怎么做?
为了实现这一点,我发现的唯一方法是使用圆形而不是矩形,这不是我们想要的。
谢谢
CoreAnimate 的动画顺序与绘制 UIBezierPath 的顺序相同。
系统方法
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
return 从左上角绘制的 UIBezierPath,因此您的动画从左上角开始。
但是您可以创建自己的 UIBezierPath 绘制形式顶部中心:
func centerStartBezierPath(frame:CGRect,cornerRadius:CGFloat) -> UIBezierPath {
let path = UIBezierPath()
path.moveToPoint(CGPointMake(frame.width/2.0, 0))
path.addLineToPoint(CGPointMake(frame.width-cornerRadius, 0))
path.addArcWithCenter(CGPointMake(frame.width-cornerRadius, cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(-M_PI/2),
endAngle: 0,
clockwise: true)
path.addLineToPoint(CGPointMake(frame.width, frame.height-cornerRadius))
path.addArcWithCenter(CGPointMake(frame.width-cornerRadius, frame.height-cornerRadius),
radius: cornerRadius,
startAngle: 0,
endAngle: CGFloat(M_PI/2),
clockwise: true)
path.addLineToPoint(CGPointMake(cornerRadius, frame.height))
path.addArcWithCenter(CGPointMake(cornerRadius, frame.height-cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(M_PI/2),
endAngle: CGFloat(M_PI),
clockwise: true)
path.addLineToPoint(CGPointMake(0, cornerRadius))
path.addArcWithCenter(CGPointMake(cornerRadius, cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(M_PI),
endAngle: CGFloat(M_PI*3/2),
clockwise: true)
path.closePath()
path.applyTransform(CGAffineTransformMakeTranslation(frame.origin.x, frame.origin.y))
return path;
}
它是这样工作的:
您也可以更改代码,并从您想要的任何点开始。
Swift 语法在这三年中发生了很大变化。这是我最初接受的答案的更新版本,但在 Swift 5.1+
private extension UIBezierPath {
convenience init(roundedRectFromCenter frame: CGRect, cornerRadius: CGFloat) {
self.init()
move(to: CGPoint(x: frame.width / 2, y: 0))
addLine(to: CGPoint(x: frame.width - cornerRadius, y: 0))
addArc(
withCenter: CGPoint(x: frame.width - cornerRadius, y: cornerRadius),
radius: cornerRadius,
startAngle: -.pi / 2,
endAngle: 0,
clockwise: true
)
addLine(to: CGPoint(x: frame.width, y: frame.height - cornerRadius))
addArc(
withCenter: CGPoint(x: frame.width - cornerRadius, y: frame.height - cornerRadius),
radius: cornerRadius,
startAngle: 0,
endAngle: .pi / 2,
clockwise: true
)
addLine(to: CGPoint(x: cornerRadius, y: frame.height))
addArc(
withCenter: CGPoint(x: cornerRadius, y: frame.height - cornerRadius),
radius: cornerRadius,
startAngle: .pi / 2,
endAngle: .pi,
clockwise: true
)
addLine(to: CGPoint(x: 0, y: cornerRadius))
addArc(
withCenter: CGPoint(x: cornerRadius, y: cornerRadius),
radius: cornerRadius,
startAngle: .pi,
endAngle: .pi * 3 / 2,
clockwise: true
)
close()
apply(CGAffineTransform(
translationX: frame.origin.x,
y: frame.origin.y
))
}
}
我一直在用 Swift 制作一个简单的 UIBezierPath
动画。此路径包括创建一个带有彩色边框的圆角矩形。动画必须是彩色边框的绘制。为此,我创建了一个 CAShapeLayer
和 UIBezierPath(roundedRect:, cornerRadius: )
let layer = CAShapeLayer()
var viewPrueba = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
viewPrueba = UIView(frame: CGRectMake(self.view.frame.width/2-100, self.view.frame.height/2 - 100, 200, 200))
self.view.addSubview(viewPrueba)
let path = UIBezierPath(roundedRect: CGRectMake(0, 0, 200, 200), cornerRadius: 40.0)
layer.path = path.CGPath
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blueColor().CGColor
layer.strokeStart = 0.0
layer.strokeEnd = 0.0
layer.lineWidth = 4.0
layer.lineJoin = kCALineJoinRound
viewPrueba.layer.addSublayer(layer)
let tapGR = UITapGestureRecognizer(target: self, action: #selector(ViewController.anim))
self.view.addGestureRecognizer(tapGR)
}
func anim() {
let anim1 = CABasicAnimation(keyPath: "strokeEnd")
anim1.fromValue = 0.0
anim1.toValue = 1.0
anim1.duration = 4.0
anim1.repeatCount = 0
anim1.autoreverses = false
anim1.removedOnCompletion = false
anim1.additive = true
anim1.fillMode = kCAFillModeForwards
self.layer.addAnimation(anim1, forKey: "strokeEnd")
}`
效果很好。唯一的问题是动画从正方形的左上部分开始,而不是从顶部中心开始。我该怎么做?
为了实现这一点,我发现的唯一方法是使用圆形而不是矩形,这不是我们想要的。
谢谢
CoreAnimate 的动画顺序与绘制 UIBezierPath 的顺序相同。
系统方法
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
return 从左上角绘制的 UIBezierPath,因此您的动画从左上角开始。
但是您可以创建自己的 UIBezierPath 绘制形式顶部中心:
func centerStartBezierPath(frame:CGRect,cornerRadius:CGFloat) -> UIBezierPath {
let path = UIBezierPath()
path.moveToPoint(CGPointMake(frame.width/2.0, 0))
path.addLineToPoint(CGPointMake(frame.width-cornerRadius, 0))
path.addArcWithCenter(CGPointMake(frame.width-cornerRadius, cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(-M_PI/2),
endAngle: 0,
clockwise: true)
path.addLineToPoint(CGPointMake(frame.width, frame.height-cornerRadius))
path.addArcWithCenter(CGPointMake(frame.width-cornerRadius, frame.height-cornerRadius),
radius: cornerRadius,
startAngle: 0,
endAngle: CGFloat(M_PI/2),
clockwise: true)
path.addLineToPoint(CGPointMake(cornerRadius, frame.height))
path.addArcWithCenter(CGPointMake(cornerRadius, frame.height-cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(M_PI/2),
endAngle: CGFloat(M_PI),
clockwise: true)
path.addLineToPoint(CGPointMake(0, cornerRadius))
path.addArcWithCenter(CGPointMake(cornerRadius, cornerRadius),
radius: cornerRadius,
startAngle: CGFloat(M_PI),
endAngle: CGFloat(M_PI*3/2),
clockwise: true)
path.closePath()
path.applyTransform(CGAffineTransformMakeTranslation(frame.origin.x, frame.origin.y))
return path;
}
它是这样工作的:
您也可以更改代码,并从您想要的任何点开始。
Swift 语法在这三年中发生了很大变化。这是我最初接受的答案的更新版本,但在 Swift 5.1+
private extension UIBezierPath {
convenience init(roundedRectFromCenter frame: CGRect, cornerRadius: CGFloat) {
self.init()
move(to: CGPoint(x: frame.width / 2, y: 0))
addLine(to: CGPoint(x: frame.width - cornerRadius, y: 0))
addArc(
withCenter: CGPoint(x: frame.width - cornerRadius, y: cornerRadius),
radius: cornerRadius,
startAngle: -.pi / 2,
endAngle: 0,
clockwise: true
)
addLine(to: CGPoint(x: frame.width, y: frame.height - cornerRadius))
addArc(
withCenter: CGPoint(x: frame.width - cornerRadius, y: frame.height - cornerRadius),
radius: cornerRadius,
startAngle: 0,
endAngle: .pi / 2,
clockwise: true
)
addLine(to: CGPoint(x: cornerRadius, y: frame.height))
addArc(
withCenter: CGPoint(x: cornerRadius, y: frame.height - cornerRadius),
radius: cornerRadius,
startAngle: .pi / 2,
endAngle: .pi,
clockwise: true
)
addLine(to: CGPoint(x: 0, y: cornerRadius))
addArc(
withCenter: CGPoint(x: cornerRadius, y: cornerRadius),
radius: cornerRadius,
startAngle: .pi,
endAngle: .pi * 3 / 2,
clockwise: true
)
close()
apply(CGAffineTransform(
translationX: frame.origin.x,
y: frame.origin.y
))
}
}