美文网首页
【iOS】UISlider自定义样式(swift)

【iOS】UISlider自定义样式(swift)

作者: Qire_er | 来源:发表于2021-11-28 13:25 被阅读0次

    写在前面的:

    在实际项目开发中,我们经常有定制Slider拖动控件样式的需求!

    最近,在自己的项目中,正好也需要定制UISlider
    这里将我自己的经验写下来,供需要的人参考!

    最终效果:

    动图效果

    实现思路:

    遇到需要定制控件样式的需求,我们往往一开始会想到用UIView来封装自己的控件,因为这样最直接,也最顺手!……但是,如果从效率角度来讲,自己封装控件,也不见得好,甚至在调试和优化,以及代码复用方面,可能还不如在原生控件上面进行修改!

    所以,我最终还是选择在UISlider的基础上,重写部分现有方法,来实现想要的效果!

    • 重写thumbRect
    • 重写trackRect
    • 生成thumbImage图片
    • 生成trackImage图片

    完整代码:

    UISlider 定义部分

    //
    //  ColorSlider.swift
    //  UIKit-basic
    //
    //  Created by Qire_er on 2021/11/27.
    //
    
    import UIKit
    
    class ColorSlider: UISlider {
        
        var valueLabel: UILabel! // 定义【值】文本
    
        private var thumbColor: UIColor! // 定义【滑块】颜色
        private var trackHeight: CGFloat = 0 // 定义【track】高度
        private var colors: [CGColor]! // 定义【颜色】列表
        private var locations: [CGFloat]! // 定义【位置】列表
        
        init(frame: CGRect, trackHeight: CGFloat, colors: [CGColor], locations: [CGFloat]) {
            super.init(frame: frame)
            
            self.trackHeight = trackHeight
            self.colors = colors
            self.locations = locations
            
            addValueLabel() // 添加【值】文本
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
        
        // 添加【值】文本
        private func addValueLabel() {
            self.valueLabel = UILabel()
            self.valueLabel.textAlignment = .center
            self.addSubview(valueLabel)
        }
        
        // 重写 draw 方法
        override func draw(_ rect: CGRect) {
            // 设置ThumbImage
            let thumbWidth = rect.height
            let thumbImg = makeThumbImage(rect: CGRect(x: 0, y: 0, width: thumbWidth, height: thumbWidth))
            self.setThumbImage(thumbImg, for: .normal)
            
            // 设置MinimumTrackImage
            let minTrackImg = makeTrackImage(rect: rect)  // 定义minimumTrackImage
            self.setMinimumTrackImage(minTrackImg, for: .normal)  // 设置minimumTrackImage
            
            // 设置MaximumTrackImage(如果不设置,只有一边有渐变底色)
            let maxTrackImg = makeTrackImage(rect: rect)
            self.setMaximumTrackImage(maxTrackImg, for: .normal)
        }
        
        // 生成thumbImage图片 方法
        private func makeThumbImage(rect: CGRect) -> UIImage {
            
            let lineWidth: CGFloat = 2
            UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
            let rect = rect.insetBy(dx: lineWidth / 2 + 3, dy: lineWidth / 2 + 3)
    
            self.thumbColor.setFill()
            let oval = UIBezierPath(ovalIn: rect)
            oval.fill()
            UIColor.white.setStroke()
            oval.lineWidth = lineWidth
            oval.stroke()
    
            let thumbImg = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
            return thumbImg
        }
        
        // 生成trackImage图片 方法
        private func makeTrackImage(rect: CGRect) -> 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()
        
            // 定义渐变色
            let gradient = CGGradient(
                colorsSpace: colorSpace,
                colors: self.colors as CFArray,
                locations: self.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
        }
        
        // 重写 beginTracking 方法
        override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
            let tracking = super.beginTracking(touch, with: event)
            let thumbWidth = frame.height
            let thumbImg = makeThumbImage(rect: CGRect(x: 0, y: 0, width: thumbWidth, height: thumbWidth))
            self.setThumbImage(thumbImg, for: .normal)
            return tracking
        }
        
        // 重写 continueTracking 方法
        override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
            let tracking = super.continueTracking(touch, with: event)
            let thumbWidth = frame.height
            let thumbImg = makeThumbImage(rect: CGRect(x: 0, y: 0, width: thumbWidth, height: thumbWidth))
            self.setThumbImage(thumbImg, for: .normal)
            return tracking
        }
        
        // 重写 endTracking 方法
        override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
            super.endTracking(touch, with: event)
            let thumbWidth = frame.height
            let thumbImg = makeThumbImage(rect: CGRect(x: 0, y: 0, width: thumbWidth, height: thumbWidth))
            self.setThumbImage(thumbImg, for: .normal)
        }
        
        // 重写【thumb】显示区域 方法
        override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
            let rect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
            
            self.thumbColor = UIColor(hue: CGFloat(self.value), saturation: 1, brightness: 1, alpha: 1)
            
            // 添加【值】文本 label
            if let valueLabel = self.valueLabel {
                let offsetY: CGFloat = 25
                valueLabel.frame = CGRect(x: rect.minX, y: rect.minY - offsetY, width: rect.width, height: rect.height)
                valueLabel.text = String(Int(self.value * 100))
            }
            
            // 设置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)
        }
    }
    
    

    UISlider 调用部分

    //
    //  ColorSliderVC.swift
    //  UIKit-basic
    //
    //  Created by Qire_er on 2021/11/27.
    //
    
    import UIKit
    
    class ColorSliderVC: UIViewController {
    
        let width = UIScreen.main.bounds.width // 屏幕【宽度】
        let height = UIScreen.main.bounds.height // 屏幕【高度】
        lazy var sliderWidth: CGFloat = width - 60 // slider【宽度】
        let slidermHeight: CGFloat = 36 // slider【高度】
        
        let colors = [
            UIColor.red.cgColor,
            UIColor.yellow.cgColor,
            UIColor.green.cgColor,
            UIColor.cyan.cgColor,
            UIColor.blue.cgColor,
            UIColor.magenta.cgColor,
            UIColor.red.cgColor
        ] // 定义【颜色】列表
        
        var locations = [
            CGFloat(0)/CGFloat(360),
            CGFloat(60)/CGFloat(360),
            CGFloat(120)/CGFloat(360),
            CGFloat(180)/CGFloat(360),
            CGFloat(240)/CGFloat(360),
            CGFloat(300)/CGFloat(360),
            CGFloat(360)/CGFloat(360)
        ] // 定义【位置】列表
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let colorSlider = ColorSlider(
                frame: CGRect(x: (width - sliderWidth) * 0.5, y: (height - slidermHeight) * 0.5, width: sliderWidth, height: slidermHeight),
                trackHeight: 8,
                colors: self.colors,
                locations: self.locations
            )  // 放置在屏幕中心
            
            colorSlider.setValue(0.5, animated: true) // 设置slider【初始值】
         
            view.addSubview(colorSlider) // 添加slider 到 主视图
            view.backgroundColor = UIColor.white // 设置 主视图背景色
        }
    
    }
    
    

    (==完==)

    相关文章

      网友评论

          本文标题:【iOS】UISlider自定义样式(swift)

          本文链接:https://www.haomeiwen.com/subject/cwgcxrtx.html