IOS自定义进度条与CAShapeLayer
Posted
技术标签:
【中文标题】IOS自定义进度条与CAShapeLayer【英文标题】:IOS custom progress bar with CAShapeLayer 【发布时间】:2021-04-14 11:19:22 【问题描述】:如何用弧尾的文字创建像这张图片一样的自定义弓
这是我当前的代码和当前结果
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 120, startAngle: CGFloat.pi , endAngle: CGFloat.pi*2, clockwise: true)
let greyLayer = CAShapeLayer()
greyLayer.strokeColor = greyColor
greyLayer.lineWidth = lineWidth
greyLayer.path = circularPath.cgPath
greyLayer.lineCap = .round
greyLayer.fillColor = UIColor.clear.cgColor
greyLayer.shadowColor = UIColor.black.cgColor
greyLayer.shadowOpacity = 1
greyLayer.shadowOffset = .zero
greyLayer.shadowRadius = 2
view.layer.addSublayer(greyLayer)
shapeLayer.strokeColor = bowColor
shapeLayer.lineWidth = lineWidth
shapeLayer.path = circularPath.cgPath
shapeLayer.lineCap = .round
shapeLayer.strokeEnd = 0
shapeLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(shapeLayer)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
let label = UILabel()
label.text = "Best"
label.textAlignment = .center
label.textColor = .red
label.font = UIFont.boldSystemFont(ofSize: 30)
view.addSubview(label)
view.layer.addSublayer(label.layer)
label.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
当前结果 我想在圆弧的末端添加一个圆形并像上图一样动画, 我不知道如何实现这个
【问题讨论】:
github.com/EranBoudjnah/MTCircularSlider/blob/master/… 【参考方案1】:让您开始...
您的弧线从.pi
变为.pi*2
...但不是.pi*2
,它可能会帮助您将其视为:
.pi
开始,即“9 点”
完整进度将跨越到“3 点钟”,即添加 .pi
到开始角度
完成进度为.pi
加 .pi * progressPercent
。
所以,要获得endAngle
:
.pi + ((25.0 / 100.0) * .pi)
50% 的进度将是.pi + ((50.0 / 100.0) * .pi)
83% 的进度将是.pi + ((83.0 / 100.0) * .pi)
编码,你会做这样的事情:
let score = 83
let endAngle: CGFloat = .pi + ((CGFloat(score) / 100.0) * .pi)
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 120, startAngle: .pi, endAngle: endAngle, clockwise: true)
现在你的弧线跨越了“半圆”的 83%。
要在弧的末端添加标签,您可以从路径中获取该点:
// point at end of arc
let endPoint: CGPoint = circularPath.currentPoint
您可以使用该点来定位您的标签(或自定义“气球”标签视图)。
这是您的代码,稍作修改以添加 score
值和 progressLabel
:
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
view.backgroundColor = .systemTeal
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
let greyColor = UIColor.gray.cgColor
let bowColor = UIColor.systemPink.cgColor
let lineWidth: CGFloat = 12
let shapeLayer = CAShapeLayer()
let score = 83
let endAngle: CGFloat = .pi + (.pi * (CGFloat(score) / 100.0))
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 120, startAngle: .pi, endAngle: endAngle, clockwise: true)
// point at end of arc
let endPoint: CGPoint = circularPath.currentPoint
let greyLayer = CAShapeLayer()
greyLayer.strokeColor = greyColor
greyLayer.lineWidth = lineWidth
greyLayer.path = circularPath.cgPath
greyLayer.lineCap = .round
greyLayer.fillColor = UIColor.clear.cgColor
greyLayer.shadowColor = UIColor.black.cgColor
greyLayer.shadowOpacity = 1
greyLayer.shadowOffset = .zero
greyLayer.shadowRadius = 2
view.layer.addSublayer(greyLayer)
shapeLayer.strokeColor = bowColor
shapeLayer.lineWidth = lineWidth
shapeLayer.path = circularPath.cgPath
shapeLayer.lineCap = .round
shapeLayer.strokeEnd = 0
shapeLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(shapeLayer)
//view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
let label = UILabel()
label.text = "Best"
label.textAlignment = .center
label.textColor = .red
label.font = UIFont.boldSystemFont(ofSize: 30)
view.addSubview(label)
view.layer.addSublayer(label.layer)
label.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
let progressLabel = UILabel()
progressLabel.backgroundColor = .cyan
progressLabel.text = "\(score)%"
progressLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(progressLabel)
progressLabel.bottomAnchor.constraint(equalTo: view.topAnchor, constant: endPoint.y).isActive = true
progressLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: endPoint.x).isActive = true
结果:
如果您想“动画化”进度弧和标签,那将需要更多的工作......但这是一个很好的学习练习。
【讨论】:
以上是关于IOS自定义进度条与CAShapeLayer的主要内容,如果未能解决你的问题,请参考以下文章