封装了一个UILabel并让它显示圆形的边框,UILabel上面显示百份比,而边框则用Animation绘制到整个圆占指定百分比的点。
这只是我个人想的继承一个UILabel实现的,用到两个CAShapeLayer,第一个Layer的作用是画出灰色的背影圆圈,第二个Layer位置放置在第一个Layer的上面,并设置为红色描绘颜色并描绘到插定的位置,之后实现相应的动画效果即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | import UIKit class kCircleLabel: UILabel { var percent:Double! convenience init(percent per:Double,frame:CGRect) { self .init(frame: frame) self .percent = per createCircle() } override init(frame: CGRect) { super .init(frame: frame) } required init?(coder aDecoder: NSCoder ) { super .init(coder: aDecoder) } func createCircle() { self .textAlignment = NSTextAlignment .Center self .text = "\(percent * 100 )%" //第一个圆形Layer,边框为灰色的 let circleLayer:CAShapeLayer = CAShapeLayer() circleLayer.lineWidth = 8 //清除填充的颜色 circleLayer.fillColor = UIColor.clearColor().CGColor //边框的颜色 circleLayer.strokeColor = UIColor.init(red: CGFloat(220.0 / 255.0 ), green: CGFloat(220.0 / 255.0), blue: CGFloat(220.0 / 255.0), alpha: 1.0).CGColor //用贝塞尔曲线画出一个圆 let circlePath:UIBezierPath = UIBezierPath(ovalInRect: CGRect(x: 0, y: 0, width: self .frame.size.width, height: self .frame.size.height)) circleLayer.path = circlePath.CGPath self .layer.addSublayer(circleLayer) //第二个只描绘到特定位置的弧Layer let arcLayer:CAShapeLayer = CAShapeLayer() //画出特定的弧 let arcPath:UIBezierPath = UIBezierPath(arcCenter: CGPoint(x: self .frame.size.width / 2, y: self .frame.size.height / 2), radius: self .frame.size.width / 2, startAngle: 0.0, endAngle: CGFloat(360 * percent / 180 * M_PI), clockwise: true ) arcLayer.path = arcPath.CGPath arcLayer.lineWidth = 8 //清除填充的颜色 arcLayer.fillColor = UIColor.clearColor().CGColor arcLayer.strokeColor = UIColor.redColor().CGColor //弧Layer的动画 let arcAnimation:CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd" ) arcAnimation.fromValue = 0.0 arcAnimation.toValue = 1.0 arcAnimation.duration = 1.5 arcAnimation.removedOnCompletion = false arcAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) //这是从大到小的动画,适用于整个Layer let scaleAnimation:CABasicAnimation = CABasicAnimation(keyPath: "transform.scale" ) scaleAnimation.fromValue = 5.0 scaleAnimation.toValue = 1.0 scaleAnimation.duration = 0.5 arcLayer.addAnimation(arcAnimation, forKey: nil ) /*let animationGroup:CAAnimationGroup = CAAnimationGroup() animationGroup.duration = 1.0 animationGroup.animations = [ arcAnimation, scaleAnimation]*/ self .layer.insertSublayer(arcLayer, above : circleLayer) self .layer.addAnimation(scaleAnimation, forKey: nil ) } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. //override func drawRect(rect: CGRect) { // Drawing code //} } |
调用时:
let circleLabel = kCircleLabel(percent: 0.52, frame: CGRect(x: (self.view.bounds.width - 100.0) / 2, y: 260, width: 100.0, height: 100.0))
self.view.addSubview(circleLabel)
要实现这个效果的关键是要学会怎么使用贝塞尔曲线,并给Layer设置Path。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端