Все работает, за исключением того, что когда я касаюсь представления, граница кратковременно мигает, даже несмотря на то, что StrokeEnd = 0 и lineWidth = 0.
Вот полный код для пользовательского представления:
Код: Выделить всё
@IBDesignable
class CircularProgressView: UIView {
private let progressLayer = CAShapeLayer()
private let iconView = UIImageView()
@IBInspectable var ringWidth: CGFloat = 4
@IBInspectable var ringColor: UIColor = .white
@IBInspectable var playIcon: UIImage? = UIImage(named: "iconPause")
@IBInspectable var pauseIcon: UIImage? = UIImage(named: "iconPlay")
@IBInspectable var iconColor: UIColor = .white
@IBInspectable var isPlaying: Bool = false { didSet { updateIcon() } }
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
backgroundColor = .clear
iconView.contentMode = .scaleAspectFit
iconView.tintColor = iconColor
addSubview(iconView)
// PROGRESS RING
layer.addSublayer(progressLayer)
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = ringColor.cgColor
progressLayer.lineCap = .round
progressLayer.strokeEnd = 0
progressLayer.lineWidth = 0
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(viewTapped)))
updateIcon()
}
override func layoutSubviews() {
super.layoutSubviews()
drawRing()
iconView.frame = bounds.insetBy(dx: bounds.width * 0.28, dy: bounds.height * 0.28)
}
private func drawRing() {
let radius = min(bounds.width, bounds.height) / 2 - ringWidth / 2
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let path = UIBezierPath(arcCenter: center, radius: radius,
startAngle: -.pi/2, endAngle: 3 * .pi/2, clockwise: true)
progressLayer.frame = bounds
progressLayer.path = path.cgPath
}
func setProgress(_ value: CGFloat, animated: Bool = true) {
let clamped = max(0, min(value, 1))
if animated {
let anim = CABasicAnimation(keyPath: "strokeEnd")
anim.fromValue = progressLayer.strokeEnd
anim.toValue = clamped
anim.duration = 0.25
progressLayer.strokeEnd = clamped
progressLayer.add(anim, forKey: nil)
} else {
progressLayer.strokeEnd = clamped
}
}
private func updateIcon() {
let image = isPlaying ? pauseIcon : playIcon
iconView.image = image?.withRenderingMode(.alwaysTemplate)
iconView.tintColor = iconColor
}
@objc private func viewTapped() {
isPlaying.toggle()
//
Подробнее здесь: [url]https://stackoverflow.com/questions/79858500/cashapelayer-strokeend-causes-ring-flash-on-tap-how-to-stop-border-flash-on-cu[/url]
Мобильная версия