// // SPPlayerProgressView.swift // MoviaBox // // Created by 曾觉新 on 2025/4/9. // import UIKit class SPPlayerProgressView: UIView { ///滑动开始 var panStart: (() -> Void)? ///滑动中 var panChange: ((_ progress: CGFloat) -> Void)? ///滑动完成回调 var panFinish: ((_ progress: CGFloat) -> Void)? var progress: CGFloat = 0 { didSet { if !isPaning { setNeedsDisplay() } } } ///用来记录滑动时的当前进度 private var tempProgress: CGFloat = 0 ///滑动进度 private var panProgress: CGFloat = 0 var progressColor: UIColor = .color3D4556() { didSet { self.backgroundColor = progressColor } } var currentProgress: UIColor = .colorFFFFFF() var lineWidth: CGFloat = 2 ///加载中状态 var isLoading = false { didSet { if isLoading { if gradientTimer == nil { gradientTimer = Timer.scheduledTimer(timeInterval: 0.05, target: YYWeakProxy(target: self), selector: #selector(handleGradientTimer), userInfo: nil, repeats: true) } } else { gradientTimer?.invalidate() gradientTimer = nil } } } ///是否在滑动中 private var isPaning: Bool = false private var gradientTimer: Timer? private var gradientValue: CGFloat = 0 override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = progressColor let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(sender:))) self.addGestureRecognizer(pan) let tap = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(sender:))) self.addGestureRecognizer(tap) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) setNeedsDisplay() } @objc private func handleGradientTimer() { gradientValue += 0.1 if gradientValue > 1 { gradientValue = 0 } setNeedsDisplay() } override func draw(_ rect: CGRect) { super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else { return } let width = rect.width let height = rect.height if isLoading, !isPaning { // 定义颜色空间 let colorSpace = CGColorSpaceCreateDeviceRGB() let colors: [CGColor] = [ UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.clear.cgColor ] let locations: [CGFloat] = [0.0, gradientValue, 1.0] guard let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations) else { return } // 定义渐变的起点和终点 let startPoint = CGPoint(x: rect.minX, y: rect.minY) let endPoint = CGPoint(x: rect.maxX, y: rect.maxY) // 绘制渐变 context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: []) } else { var progress = self.progress if self.isPaning { progress = self.panProgress } ///绘制进度 let progressPath = UIBezierPath(roundedRect: CGRect(x: 0, y: height - lineWidth, width: width, height: lineWidth), cornerRadius: lineWidth / 2) context.addPath(progressPath.cgPath) context.setFillColor(progressColor.cgColor) context.fillPath() ///绘制当前进度 let currentPath = UIBezierPath(roundedRect: CGRect(x: 0, y: height - lineWidth, width: width * progress, height: lineWidth), cornerRadius: lineWidth / 2) context.addPath(currentPath.cgPath) context.setFillColor(currentProgress.cgColor) context.fillPath() } } } extension SPPlayerProgressView { @objc func handlePanGesture(sender: UIPanGestureRecognizer) { switch sender.state { case .began: self.isPaning = true self.tempProgress = self.progress sender.setTranslation(CGPoint(x: 0, y: 0), in: self) self.panStart?() case .changed: let point = sender.translation(in: self) let offsetX = point.x / self.width self.panProgress = self.tempProgress + offsetX if self.panProgress < 0 { self.panProgress = 0 } self.panChange?(self.panProgress) setNeedsDisplay() default: self.isPaning = false self.panFinish?(self.panProgress) self.panProgress = 0 } } @objc func handleTapGesture(sender: UITapGestureRecognizer) { let point = sender.location(in: self) let offsetX = point.x / self.width self.panFinish?(offsetX) } }