当前位置: > > > Swift - 实现自定义的Slider滑块组件(轨道上带有刻度标记)

Swift - 实现自定义的Slider滑块组件(轨道上带有刻度标记)

我之前过一篇关于 UISlider 的文章:Swift - 滑块(UISlider)的用法,介绍了 UISlider 的使用方法以及样式的修改。但如果我们想在背景轨道上标注一些刻度线,这个功能 UISlider 原生是没有提供的。
本文演示如何通过继承 UISlider,实现一个支持显示刻度线的滑块组件。比如我们可以在轨道的 1/41/23/4 处做个标记,方便用户定位。又比如使用 slider 作为播放进度条时,可以在进度上面标注出关键帧的位置。

1,效果图

这个自定义的滑块组件可以自由设置样式和刻度位置:
  • 第1个样例使用默认样式,左侧轨道为深灰色,右侧轨道为浅灰色。同时轨道默认为每隔 10% 的位置都有一条刻度。
  • 第2个样例我们修改了左右两侧轨道的颜色和高度,刻度的颜色和宽度。同时修改刻度出现的位置。
  • 第3个样例还修改了轨道上控制器按钮的颜色。
  • 第4个样例使用图片来代替轨道上的控制按钮。

2,自定义的组件代码(MarkSlider.swift)

其实现原理是通过继承 UISlider,在 draw 方法中生成带刻度的轨道图片(UIImage),再通过 setMinimumTrackImage setMaximumTrackImage 方法设置到 Slider上。
这里要特别注意左侧轨道的 UIImage,为了避免拖动滑块时出现拉伸情况,我们还要通过 .resizableImage(withCapInsets: .zero) 方法将左侧轨道设置为不拉伸。
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
import UIKit
 
//带有刻度的自定义滑块
class MarkSlider: UISlider {
    //刻度位置集合
    var markPositions:[CGFloat] = []
    //刻度颜色
    var markColor: UIColor?
    //刻度宽度
    var markWidth: CGFloat?
    //左侧轨道的颜色
    var leftBarColor: UIColor?
    //右侧轨道的颜色
    var rightBarColor:UIColor?
    //轨道高度
    var barHeight: CGFloat?
     
    //初始化
    override init(frame: CGRect) {
        super.init(frame: frame)
         
        //设置样式的默认值
        self.markColor = UIColor(red: 106/255.0, green: 106/255.0, blue: 124/255.0,
                                 alpha: 0.7)
        self.markPositions = [10,20,30,40,50,60,70,80,90]
        self.markWidth = 1.0
        self.leftBarColor = UIColor(red: 55/255.0, green: 55/255.0, blue: 94/255.0,
                                    alpha: 0.8)
        self.rightBarColor = UIColor(red: 179/255.0, green: 179/255.0, blue: 193/255.0,
                                     alpha: 0.8)
        self.barHeight = 12
    }
     
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
     
     
    override func draw(_ rect: CGRect) {
        super.draw(rect)
 
        //得到左侧带有刻度的轨道图片(注意:图片不拉伸)
        let leftTrackImage = createTrackImage(rect: rect, barColor: self.leftBarColor!)
            .resizableImage(withCapInsets: .zero)
         
        //得到右侧带有刻度的轨道图片
        let rightTrackImage = createTrackImage(rect: rect, barColor: self.rightBarColor!)
         
        //将前面生产的左侧、右侧轨道图片设置到UISlider上
        self.setMinimumTrackImage(leftTrackImage, for: .normal)
        self.setMaximumTrackImage(rightTrackImage, for: .normal)
    }
     
    //生成轨道图片
    func createTrackImage(rect: CGRect, barColor:UIColor) -> UIImage {
        //开始图片处理上下文
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        let context: CGContext = UIGraphicsGetCurrentContext()!
         
        //绘制轨道背景
        context.setLineCap(.round)
        context.setLineWidth(self.barHeight!)
        context.move(to: CGPoint(x:self.barHeight!/2, y:rect.height/2))
        context.addLine(to: CGPoint(x:rect.width-self.barHeight!/2, y:rect.height/2))
        context.setStrokeColor(barColor.cgColor)
        context.strokePath()
         
        //绘制轨道上的刻度
        for i in 0..<self.markPositions.count {
            context.setLineWidth(self.markWidth!)
            let position: CGFloat = self.markPositions[i]*rect.width/100.0
            context.move(to: CGPoint(x:position, y: rect.height/2-self.barHeight!/2+1))
            context.addLine(to: CGPoint(x:position, y:rect.height/2+self.barHeight!/2-1))
            context.setStrokeColor(self.markColor!.cgColor)
            context.strokePath()
        }
         
        //得到带有刻度的轨道图片
        let trackImage = UIGraphicsGetImageFromCurrentImageContext()!
        //结束上下文
        UIGraphicsEndImageContext()
        return trackImage
    }
}

3,使用样例

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
import UIKit
 
class ViewController: UIViewController {
 
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //滑块1:使用默认样式、默认刻度(每10%一个刻度)
        let firstSlider = MarkSlider(frame:CGRect(x:10,y:50,width:200,height:40))
        view.addSubview(firstSlider)
         
        //滑块2:修改默认样式
        let secondSlider = MarkSlider(frame:CGRect(x:10,y:100,width:200,height:40))
        secondSlider.markColor = UIColor(white: 1, alpha: 0.5) //刻度颜色
        secondSlider.markPositions = [15,30,75] //刻度位置
        secondSlider.markWidth = 3.0 //刻度宽度
        secondSlider.leftBarColor = UIColor.orange //左轨道颜色
        secondSlider.rightBarColor = UIColor(red: 255/255.0, green: 222/255.0,
                                             blue: 0/255.0, alpha: 1.0) //右轨道颜色
        secondSlider.barHeight = 16 //轨道高度
        view.addSubview(secondSlider)
         
        //滑块3:除了修改默认样式,还改变控制器颜色
        let thirdSlider = MarkSlider(frame:CGRect(x:10,y:150,width:200,height:40))
        thirdSlider.markColor = UIColor(white: 0, alpha: 0.1)
        thirdSlider.leftBarColor = UIColor(red: 108/255.0, green: 200/255.0, blue: 0/255.0,
                                           alpha: 1.0)
        thirdSlider.rightBarColor = UIColor(red: 138/255.0, green: 255/255.0, blue: 0/255.0,
                                            alpha: 1.0)
        thirdSlider.thumbTintColor = UIColor.orange  //改变控制器颜色
        view.addSubview(thirdSlider)
         
        //滑块4:除了修改默认样式,还改变控制器图片
        let fourthSlider = MarkSlider(frame:CGRect(x:10,y:200,width:200,height:40))
        fourthSlider.markColor = UIColor(white: 0, alpha: 0.1)
        fourthSlider.leftBarColor = UIColor(red: 108/255.0, green: 200/255.0, blue: 0/255.0,
                                            alpha: 1.0)
        fourthSlider.rightBarColor = UIColor(red: 138/255.0, green: 255/255.0,
                                             blue: 0/255.0, alpha: 1.0)
        fourthSlider.setThumbImage(UIImage(named: "sliderHandle"),
                                   for: .normal) //改变控制器图片
        fourthSlider.barHeight = 4
        view.addSubview(fourthSlider)
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
源码下载hangge_1597.zip
评论0