75d24c15
yangbin
123
|
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
//
// 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)
}
}
|