创build一个自定义的animation属性

UIView你可以改变backgroundColouranimation。 在UISlideView你可以改变animation的值。

你可以添加一个自定义属性到你自己的UIView子类,以便它可以animation?

如果我在我的UIView有一个CGPath ,那么我可以通过改变path的绘制百分比来animation它的绘图。

我可以将该animation封装到子类中吗?

即我有一个CGPath创build一个圆的UIView

如果圆圈不在那里,则代表0%。 如果圆圈满了,则代表100%。 我可以通过改变绘制path的百分比来绘制任何值。 我还可以通过animationCGPath的百分比和重绘path来animation更改(在UIView子类中)。

我可以在UIView上设置一些属性(即百分比),这样我就可以将变化粘贴到一个UIView animateWithDuration块中,并为path百分比的变化设置animation效果。

我希望我已经解释了我想做的事情。

基本上,我想要做的就是像…

 [UIView animateWithDuration:1.0 animations:^{ myCircleView.percentage = 0.7; } completion:nil]; 

以及给定百分比的圆形path。

如果您扩展CALayer并实现您的自定义

 - (void) drawInContext:(CGContextRef) context 

您可以通过覆盖needsDisplayForKey (在您的自定义CALayer类中)来创buildanimation属性,如下所示:

 + (BOOL) needsDisplayForKey:(NSString *) key { if ([key isEqualToString:@"percentage"]) { return YES; } return [super needsDisplayForKey:key]; } 

当然,你也需要一个叫做percentage@property 。 从现在开始,您可以使用核心animation为百分比属性设置animation。 我没有检查是否使用[UIView animateWithDuration...]调用。 它可能工作。 但是这对我有效:

 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"percentage"]; animation.duration = 1.0; animation.fromValue = [NSNumber numberWithDouble:0]; animation.toValue = [NSNumber numberWithDouble:100]; [myCustomLayer addAnimation:animation forKey:@"animatePercentage"]; 

哦,并使用myCircleView yourCustomLayer ,执行此操作:

 [myCircleView.layer addSublayer:myCustomLayer]; 

对于那些需要更多细节的人,就像我所做的那样:

苹果在这个问题上有一个很酷的例子 。

例如感谢它,我发现你实际上并不需要添加你的自定义图层作为子图层( @Tom van Zummerenbuild议)。 相反,向View类添加一个类方法就足够了:

 + (Class)layerClass { return [CustomLayer class]; } 

希望它有助于某人。

完整的Swift 3例子:

完成品

 public class CircularProgressView: UIView { public dynamic var progress: CGFloat = 0 { didSet { progressLayer.progress = progress } } fileprivate var progressLayer: CircularProgressLayer { return layer as! CircularProgressLayer } override public class var layerClass: AnyClass { return CircularProgressLayer.self } override public func action(for layer: CALayer, forKey event: String) -> CAAction? { if event == #keyPath(CircularProgressLayer.progress), let action = action(for: layer, forKey: #keyPath(backgroundColor)) as? CAAnimation { let animation = CABasicAnimation() animation.keyPath = #keyPath(CircularProgressLayer.progress) animation.fromValue = progressLayer.progress animation.toValue = progress animation.beginTime = action.beginTime animation.duration = action.duration animation.speed = action.speed animation.timeOffset = action.timeOffset animation.repeatCount = action.repeatCount animation.repeatDuration = action.repeatDuration animation.autoreverses = action.autoreverses animation.fillMode = action.fillMode animation.timingFunction = action.timingFunction animation.delegate = action.delegate self.layer.add(animation, forKey: #keyPath(CircularProgressLayer.progress)) } return super.action(for: layer, forKey: event) } } /* * Concepts taken from: * https://stackoverflow.com/a/37470079 */ fileprivate class CircularProgressLayer: CALayer { @NSManaged var progress: CGFloat let startAngle: CGFloat = 1.5 * .pi let twoPi: CGFloat = 2 * .pi let halfPi: CGFloat = .pi / 2 override class func needsDisplay(forKey key: String) -> Bool { if key == #keyPath(progress) { return true } return super.needsDisplay(forKey: key) } override func draw(in ctx: CGContext) { super.draw(in: ctx) UIGraphicsPushContext(ctx) //Light Grey UIColor.lightGray.setStroke() let center = CGPoint(x: bounds.midX, y: bounds.midY) let strokeWidth: CGFloat = 4 let radius = (bounds.size.width / 2) - strokeWidth let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: twoPi, clockwise: true) path.lineWidth = strokeWidth path.stroke() //Red UIColor.red.setStroke() let endAngle = (twoPi * progress) - halfPi let pathProgress = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle , clockwise: true) pathProgress.lineWidth = strokeWidth pathProgress.lineCapStyle = .round pathProgress.stroke() UIGraphicsPopContext() } } let circularProgress = CircularProgressView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) UIView.animate(withDuration: 2, delay: 0, options: .curveEaseInOut, animations: { circularProgress.progress = 0.76 }, completion: nil) 

这里有一个很好的objc文章,详细介绍了这是如何工作的

以及这里使用相同概念的objc项目:

本质上,动作(对于图层:)将在对象从animation块进行animation处理时调用,我们可以使用相同的属性(从backgroundColor属性中窃取)开始我们自己的animation,并为更改设置animation。

您必须自己实施百分比部分。 您可以覆盖图层绘制代码,以根据设置的百分比值绘制您的cgpath。 核心animation节目指南和animationtypes和时间指南