// // ProgressButton.swift // Twear // // Created by yangbin on 2021/12/29. // import Foundation import UIKit fileprivate let StartAngle = CGFloat(Double.pi / 2) //protocol ProgressButtonDelegate: NSObjectProtocol { // func progressFinished() //} public class ProgressButton: UIButton { // 延迟初始化背景层,采用 fill 来绘层背景 private lazy var bgLayer: CAShapeLayer = CAShapeLayer() // 延迟初始化进度条层,采用 stroke 来绘制边框 private lazy var progressLayer: CAShapeLayer = CAShapeLayer() // 进度条百分比(最小为 0.0,最大为 1.0) private var progress: Double = 0 private let percent: CGFloat = 1.0/20.0 // 延迟初始化标签文本内容 // private lazy var label: UILabel = UILabel(frame: CGRect.zero) var progressClosure: (() -> ())? public override init(frame: CGRect) { super.init(frame: frame) initView() } required init?(coder: NSCoder) { super.init(coder: coder) initView() } // 仅初始化 layer & label,以及颜色,后续再给定实际大小和约束 func initView() { // fillColor 用于背景颜色填充 // strokeColor 用于线条颜色 self.addTarget(self, action: #selector(touchDown(_:)), for: .touchDown) self.addTarget(self, action: #selector(touchCancel(_:)), for: [.touchDragExit, .touchDragOutside, .touchUpInside]) // self.addTarget(self, action: #selector(touchFinish(_:)), for: .touchUpInside) // 0.25 透明度的白色背景 bgLayer.fillColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0).cgColor layer.addSublayer(bgLayer) // 边框全白,边框宽度为 4 progressLayer = CAShapeLayer() progressLayer.fillColor = nil progressLayer.strokeColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1).cgColor progressLayer.lineWidth = 4.0 layer.addSublayer(progressLayer) // 标签字体颜色为纯白 // label.textColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1) // // 使用约束来布局 // label.translatesAutoresizingMaskIntoConstraints = false // addSubview(label) } public override func draw(_ rect: CGRect) { super.draw(rect) } @objc func touchDown(_ sender: UIButton) { progressLayer.strokeEnd = 0 GCDTimer.shared.scheduledDispatchTimer(WithTimerName: "ProgressButton", timeInterval: 0.1, queue: .main, repeats: true) { [weak self] in self?.startTimer() } } @objc func touchCancel(_ sender: Any) { progressLayer.strokeEnd = 0 cancelTimer() } private func cancelTimer() { if GCDTimer.shared.isExistTimer(WithTimerName: "ProgressButton") { GCDTimer.shared.cancleTimer(WithTimerName: "ProgressButton") } } func startTimer() { if progressLayer.strokeEnd >= 1 { cancelTimer() progressLayer.removeFromSuperlayer() progressClosure?() } else { progressLayer.strokeEnd += percent } } // 布局 resize 时会触发该方法 public override func layoutSubviews() { super.layoutSubviews() let radius = bounds.height / 2 - 2 bgLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath // 设置 start 从 12点钟方向开始(默认是3点钟方向) // end = 360度 * progress - start // 设置为 顺时针 方向 let end = CGFloat(Double.pi * 2) - StartAngle progressLayer.path = UIBezierPath(arcCenter: CGPoint(rect: bounds), radius: radius, startAngle: -StartAngle, endAngle: end, clockwise: true).cgPath progressLayer.strokeEnd = 0 // 因为 宽 = 高,所以,圆角为宽 or 高的一半即可 // 设置 label 的中心点 = self 的中心点 // NSLayoutConstraint.activate([ // label.centerXAnchor.constraint(equalTo: self.centerXAnchor), // label.centerYAnchor.constraint(equalTo: self.centerYAnchor) // ]) } deinit { print("deinit\(NSStringFromClass(type(of: self)))!!!!!!!") } public func setProgress(_ progress: Double) { // 进度条目标值,即 0.0 -> progress // self.progress = progress // 初始化 label // label.text = "\(duration)s" progressLayer.strokeEnd = 0.5 // 创建进度条动画,时长 = duration // if !animated { // let animation = CABasicAnimation(keyPath: "strokeEnd") // animation.duration = 1 // animation.fromValue = 0 // animation.toValue = 1 // progressLayer.add(animation, forKey: nil) // } } // public func setContent(_ text: String) { // label.text = "\(text)s" // } } extension CGPoint { // 扩展,取 rect 的中心点 init(rect: CGRect) { self.init(x: rect.width / 2, y: rect.height / 2) } }