Swift - 实现自定义的Slider滑块组件(轨道上带有刻度标记)
我之前过一篇关于 UISlider 的文章:Swift - 滑块(UISlider)的用法,介绍了 UISlider 的使用方法以及样式的修改。但如果我们想在背景轨道上标注一些刻度线,这个功能 UISlider 原生是没有提供的。
本文演示如何通过继承 UISlider,实现一个支持显示刻度线的滑块组件。比如我们可以在轨道的 1/4、1/2、3/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() } } |
