// // MPPositive_PlayerSilder.swift // MusicPlayer // // Created by Mr.Zhou on 2024/5/8. // import UIKit ///b面播放器进度条(展示缓存效果,聚焦时进行尺寸变化) class MPPositive_PlayerSilder: UISlider { /// 触控扩展边距 var hitTestEdgeInsets: UIEdgeInsets = UIEdgeInsets(top: -20*width, left: 0, bottom: -20*width, right: 0) /// 原始的Slider大小 var originalFrame: CGRect? //滑块图片 var thumbImage:UIImage = .init(named: "Player_Slider'logo")! //滑轨槽高度 var trackHeight: CGFloat = 6*width //进度渐变色 var minTrackColors: [UIColor]! //槽位渐变色 var maxTrackColors:[UIColor]! //进度渐变色定位列表(与渐变色数量保持一致) var minTrackLocations:[CGFloat]! //槽位渐变色定位列表(与渐变色数量保持一致) var maxTrackLocations:[CGFloat]! //初始化 override init(frame:CGRect) { super.init(frame: frame) setUpLayout() // print("调整Slider大小") originalFrame = self.frame } override func awakeFromNib() { super.awakeFromNib() } required init?(coder: NSCoder) { super.init(coder: coder) } private func setUpLayout() { layer.masksToBounds = false setThumbImage(thumbImage, for: .normal) //设置进度图片 let minTrackImg = makeTrackImage(rect: frame, colors: [UIColor.white], locations: [0,1]) setMinimumTrackImage(minTrackImg, for: .normal) // 设置槽位 let maxTrackImg = makeTrackImage(rect: frame, colors: [UIColor(hex: "#FFFFFF", alpha: 0.1)], locations: [0,1]) setMaximumTrackImage(maxTrackImg, for: .normal) } /// 滑块设置 /// - Parameters: /// - rect: 滑块大小 /// - color: 滑块颜色 /// - Returns: 返回的滑块图片 private func makeThumbImage(rect: CGRect, color:UIColor) -> UIImage { let lineWidth: CGFloat = 2 //开始绘制 UIGraphicsBeginImageContextWithOptions(rect.size, false, 0) //填充内部颜色 color.setFill() //曲线路径 let oval = UIBezierPath(ovalIn: rect) //填充路径 oval.fill() //设置路径颜色为白色 UIColor.white.setStroke() //路径宽度 oval.lineWidth = lineWidth oval.stroke() //转为图片 let thumbImg = UIGraphicsGetImageFromCurrentImageContext()! //转化结束 UIGraphicsEndImageContext() return thumbImg } /// 生成滑轨图片 /// - Parameters: /// - rect: 滑轨大小 /// - colors: 颜色列表 /// - locations: 位置分布列表 /// - Returns: 生成的图片 private func makeTrackImage(rect: CGRect, colors:[UIColor], locations:[CGFloat]) -> UIImage { let rect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: self.trackHeight) //开始绘制 UIGraphicsBeginImageContextWithOptions(rect.size, false, 0) let ctx = UIGraphicsGetCurrentContext()! // 创建并设置路径 let cornerRadius: CGFloat = rect.height * 0.5 let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath // 添加路径到图形上下文 ctx.addPath(path) ctx.clip() // 使用rgb颜色空间 let colorSpace = CGColorSpaceCreateDeviceRGB() //获取cgcolors var cgColors:[CGColor] = [] colors.forEach { item in cgColors.append(item.cgColor) } // 定义渐变色 let gradient:CGGradient = CGGradient(colorsSpace: colorSpace, colors: cgColors as CFArray, locations: locations)! // 渐变开始位置 let start = CGPoint(x: self.bounds.minX, y: self.bounds.minY) // 渐变结束位置 let end = CGPoint(x: self.bounds.maxX, y: self.bounds.minY) // 绘制渐变 ctx.drawLinearGradient(gradient, start: start, end: end, options: .drawsBeforeStartLocation) //转为图片 let trackImg = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return trackImg } // 重写【thumb】显示区域 方法 override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { let rect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value) // 设置thumb投影效果 // (这样设置的投影效果,如果调用setValue(_:animated:)的时候,animated参数为true,会有阴影和thumb不同步的问题,目前还不知到怎么解决) self.layer.shadowColor = UIColor.black.cgColor self.layer.shadowOffset = CGSize(width: 0, height: 0) self.layer.shadowOpacity = 0.15 self.layer.shadowRadius = 3 self.layer.shadowPath = UIBezierPath(cgPath: CGPath(ellipseIn: rect.insetBy(dx: 3, dy: 3), transform: nil)).cgPath return rect } // 重写【track】显示区域 方法 override func trackRect(forBounds bounds: CGRect) -> CGRect { return CGRect(x: 0, y: 0, width: bounds.width, height: self.trackHeight) } //MARK: - 交互代码 //当用户点击时 override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { //对Slider添加一个边距范围 let largerFrame: CGRect = self.bounds.inset(by: hitTestEdgeInsets) return largerFrame.contains(point) } //手势开始时 override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { let tracking = super.beginTracking(touch, with: event) if tracking == true { //增加高度 focusOnSlider(true) }else { let touchPoint = touch.location(in: self) // 寻找触摸点在滑动条上的位置所占的相对比例 let value = self.minimumValue + Float(touchPoint.x / self.bounds.width) * (self.maximumValue - self.minimumValue) // 更新滑块位置 self.setValue(value, animated: false) //让播放器恢复状态 MP_PlayerManager.shared.setEditProgressEnd(value) } return tracking } //手势途中 override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { //继续滑动 return super.continueTracking(touch, with: event) } //手势继续 override func endTracking(_ touch: UITouch?, with event: UIEvent?) { super.endTracking(touch, with: event) // 手势结束时恢复高度 focusOnSlider(false) } //手势取消 override func cancelTracking(with event: UIEvent?) { super.cancelTracking(with: event) // 手势取消时恢复高度 focusOnSlider(false) } //当用户焦点汇聚到slider private func focusOnSlider(_ focusing:Bool) { guard let originalFrame = originalFrame else { return } //动画修改Slider高度 UIView.animate(withDuration: 0.3) { if focusing { //聚焦状态,增加slider高度 self.transform = CGAffineTransform(scaleX: 1.0, y: 1.5) }else { //失去焦点,恢复原状 self.transform = .identity } } } }