ios - IOS自定义进度条与CAShapeLayer
问题描述
我怎样才能用弧结束的文字创建一个像这张图片的自定义弓
这是我当前的代码和当前结果
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
当前结果我想在弧的末端添加一个圆形并像上图一样动画,我不知道如何实现这个
解决方案
为了让你开始...
您的弧线从.pi
到.pi*2
... 但.pi*2
它可能会帮助您将其视为:
- 弧从 开始
.pi
,即“9 点钟” - 完成进度将跨越到“3 点钟”,这增加
.pi
了开始角度
完成进度将是.pi
plus .pi * progressPercent
。
因此,要获得endAngle
:
- 25% 的进展将是
.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
value 和 a 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
}
}
结果:
如果你想“动画化”进度弧和标签,那将需要更多的工作......但这是你学习的一个很好的练习。
推荐阅读
- javascript - NSExtensionRequestHandling 不处理本机消息
- c++ - DLL 中的大型向量异常处理程序导致程序在没有调试器的情况下崩溃
- javascript - 如何在 discord.js 的频道中记录每条消息?不和谐 v11
- algorithm - 在所有选项中获得最少的金额
- node.js - 如何在 PostgreSQL 中存储 HTML emoji v3.0 代码?
- python - 箭头键在我的基于文本的 Python 游戏中不起作用
- r - 如果 tidyr 无法下载,如何在 R 中拆分列?
- node.js - 如何在“nuxt start”之后自动运行将服务器端节点脚本附加到 nuxt.js 应用程序?
- r - 如何解决“.本地对象中的错误,...):”R中的错误
- java - 房间数据库。插入成功但未找到数据