【问题标题】:IOS custom progress bar with CAShapeLayerIOS自定义进度条与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
         

当前结果 我想在圆弧的末端添加一个圆形并像上图一样动画, 我不知道如何实现这个

【问题讨论】:

标签: ios swift view progress


【解决方案1】:

让您开始...

您的弧线从.pi 变为.pi*2 ...但不是.pi*2,它可能会帮助您将其视为:

  • 弧线从.pi 开始,即“9 点”
  • 完整进度将跨越到“3 点钟”,即添加 .pi 到开始角度

完成进度为.pi .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 值和 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

    }
}

结果:

如果您想“动画化”进度弧和标签,那将需要更多的工作......但这是一个很好的学习练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-29
    • 2016-05-06
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多