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) 方法将左侧轨道设置为不拉伸。
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,使用样例
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()
}
}
源码下载: