Article / 2026/05/29

UISlider 完整API指南

UISlider 是 iOS 开发中用于选择数值范围的控件,常用于音量控制、进度条、设置数值等场景。

🚀 UISlider 完整API指南

UISlider 是 iOS 开发中用于选择数值范围的控件,常用于音量控制、进度条、设置数值等场景。

基础属性

数值相关属性

// 当前值
var value: Float { get set }

// 最小值(默认 0.0)
var minimumValue: Float { get set }

// 最大值(默认 1.0)
var maximumValue: Float { get set }

// 是否连续触发事件(默认 true)
var isContinuous: Bool { get set }

交互状态属性

// 是否正在被用户拖拽(只读)
var isTracking: Bool { get }

// 当前的触摸对象(只读)
var currentTouch: UITouch? { get }

// 是否启用用户交互(继承自 UIControl)
var isEnabled: Bool { get set }

// 是否高亮状态(继承自 UIControl)
var isHighlighted: Bool { get set }

// 是否被选中(继承自 UIControl)
var isSelected: Bool { get set }

外观相关属性

// 滑块颜色(滑块左边部分的颜色)
var minimumTrackTintColor: UIColor? { get set }

// 滑道颜色(滑块右边部分的颜色)
var maximumTrackTintColor: UIColor? { get set }

// 滑块按钮颜色
var thumbTintColor: UIColor? { get set }

图片相关属性

// 左侧图标
var minimumValueImage: UIImage? { get set }

// 右侧图标
var maximumValueImage: UIImage? { get set }

核心方法

设置数值

// 设置值(带动画)
func setValue(_ value: Float, animated: Bool)

// 示例
slider.setValue(0.5, animated: true)

自定义滑块外观

// 设置滑块按钮图片
func setThumbImage(_ image: UIImage?, for state: UIControl.State)

// 设置左侧滑道图片
func setMinimumTrackImage(_ image: UIImage?, for state: UIControl.State)

// 设置右侧滑道图片  
func setMaximumTrackImage(_ image: UIImage?, for state: UIControl.State)

// 示例
slider.setThumbImage(UIImage(named: "custom_thumb"), for: .normal)
slider.setMinimumTrackImage(UIImage(named: "min_track"), for: .normal)
slider.setMaximumTrackImage(UIImage(named: "max_track"), for: .normal)

获取自定义图片

// 获取滑块按钮图片
func thumbImage(for state: UIControl.State) -> UIImage?

// 获取左侧滑道图片
func minimumTrackImage(for state: UIControl.State) -> UIImage?

// 获取右侧滑道图片
func maximumTrackImage(for state: UIControl.State) -> UIImage?

获取组件位置和尺寸

// 获取滑道区域
func trackRect(forBounds bounds: CGRect) -> CGRect

// 获取滑块按钮区域
func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect

// 示例
let trackFrame = slider.trackRect(forBounds: slider.bounds)
let thumbFrame = slider.thumbRect(forBounds: slider.bounds, 
                                 trackRect: trackFrame, 
                                 value: slider.value)

触摸和交互方法

// 开始跟踪触摸(可重写)
func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool

// 继续跟踪触摸(可重写)  
func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool

// 结束跟踪触摸(可重写)
func endTracking(_ touch: UITouch?, with event: UIEvent?)

// 取消跟踪触摸(可重写)
func cancelTracking(with event: UIEvent?)

// 检查点是否在控件内(可重写)
func point(_ point: CGPoint, inside view: UIView, with event: UIEvent?) -> Bool

可访问性属性

// 可访问性标签
var accessibilityLabel: String? { get set }

// 可访问性值
var accessibilityValue: String? { get set }

// 可访问性提示
var accessibilityHint: String? { get set }

// 可访问性特征
var accessibilityTraits: UIAccessibilityTraits { get set }

// 可访问性增量
func accessibilityIncrement()

// 可访问性减量  
func accessibilityDecrement()

事件处理

监听数值变化

// 添加事件监听
slider.addTarget(self, 
                action: #selector(sliderValueChanged(_:)), 
                for: .valueChanged)

@objc func sliderValueChanged(_ sender: UISlider) {
    print("当前值: \(sender.value)")
}

// 监听拖拽开始
slider.addTarget(self, 
                action: #selector(sliderTouchDown(_:)), 
                for: .touchDown)

// 监听拖拽结束
slider.addTarget(self, 
                action: #selector(sliderTouchUp(_:)), 
                for: [.touchUpInside, .touchUpOutside])

常用控制事件

.valueChanged      // 值改变时触发
.touchDown         // 开始触摸时触发  
.touchUpInside     // 在控件内部释放时触发
.touchUpOutside    // 在控件外部释放时触发
.touchCancel       // 触摸被取消时触发

完整使用示例

基础音量控制器

class VolumeController: UIViewController {
    @IBOutlet weak var volumeSlider: UISlider!
    @IBOutlet weak var volumeLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupVolumeSlider()
    }
    
    private func setupVolumeSlider() {
        // 设置数值范围
        volumeSlider.minimumValue = 0.0
        volumeSlider.maximumValue = 1.0
        volumeSlider.value = 0.5
        
        // 设置外观
        volumeSlider.minimumTrackTintColor = .systemBlue
        volumeSlider.maximumTrackTintColor = .systemGray
        volumeSlider.thumbTintColor = .white
        
        // 设置图标
        volumeSlider.minimumValueImage = UIImage(systemName: "speaker.fill")
        volumeSlider.maximumValueImage = UIImage(systemName: "speaker.wave.3.fill")
        
        // 监听变化
        volumeSlider.addTarget(self, 
                              action: #selector(volumeChanged(_:)), 
                              for: .valueChanged)
        
        // 初始化标签
        updateVolumeLabel()
    }
    
    @objc private func volumeChanged(_ sender: UISlider) {
        updateVolumeLabel()
        // 设置实际音量
        // AVAudioSession.sharedInstance().outputVolume = sender.value
    }
    
    private func updateVolumeLabel() {
        volumeLabel.text = String(format: "%.0f%%", volumeSlider.value * 100)
    }
}

视频播放进度条

class VideoProgressSlider: UISlider {
    
    override func awakeFromNib() {
        super.awakeFromNib()
        setupAppearance()
    }
    
    private func setupAppearance() {
        // 设置进度条颜色
        minimumTrackTintColor = .red
        maximumTrackTintColor = UIColor.white.withAlphaComponent(0.3)
        thumbTintColor = .red
        
        // 自定义滑块大小
        setThumbImage(createThumbImage(), for: .normal)
        
        // 设置范围
        minimumValue = 0.0
        maximumValue = 1.0
    }
    
    private func createThumbImage() -> UIImage? {
        let size = CGSize(width: 20, height: 20)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(UIColor.red.cgColor)
        context?.fillEllipse(in: CGRect(origin: .zero, size: size))
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image
    }
}

自定义滑块样式

extension UISlider {
    
    // 设置圆形滑块
    func setCircularThumb(radius: CGFloat, color: UIColor) {
        let thumbImage = createCircularImage(radius: radius, color: color)
        setThumbImage(thumbImage, for: .normal)
        setThumbImage(thumbImage, for: .highlighted)
    }
    
    // 设置滑道高度
    func setTrackHeight(_ height: CGFloat) {
        let trackImage = createTrackImage(height: height, color: .clear)
        setMinimumTrackImage(trackImage, for: .normal)
        setMaximumTrackImage(trackImage, for: .normal)
    }
    
    private func createCircularImage(radius: CGFloat, color: UIColor) -> UIImage? {
        let size = CGSize(width: radius * 2, height: radius * 2)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fillEllipse(in: CGRect(origin: .zero, size: size))
        
        // 添加阴影
        context?.setShadow(offset: CGSize(width: 0, height: 2), blur: 4, color: UIColor.black.withAlphaComponent(0.3).cgColor)
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image
    }
    
    private func createTrackImage(height: CGFloat, color: UIColor) -> UIImage? {
        let size = CGSize(width: 1, height: height)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fill(CGRect(origin: .zero, size: size))
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image?.resizableImage(withCapInsets: .zero)
    }
}

补充的重要属性和方法

继承自 UIControl 的属性

// 控件状态
var state: UIControl.State { get }

// 内容垂直对齐
var contentVerticalAlignment: UIControl.ContentVerticalAlignment { get set }

// 内容水平对齐  
var contentHorizontalAlignment: UIControl.ContentHorizontalAlignment { get set }

// 所有触摸对象
var allTouches: Set<UITouch>? { get }

// 所有事件
var allEvents: Set<UIControl.Event> { get }

语义化内容属性

// 语义化内容属性(支持从右到左的语言)
var semanticContentAttribute: UISemanticContentAttribute { get set }

// 有效的用户界面布局方向
var effectiveUserInterfaceLayoutDirection: UIUserInterfaceLayoutDirection { get }

外观代理属性

// 外观代理设置(类方法)
class func appearance() -> Self
class func appearance(whenContainedInInstancesOf containerTypes: [UIAppearanceContainer.Type]) -> Self

// 示例:全局设置所有 UISlider 的外观
UISlider.appearance().minimumTrackTintColor = .systemBlue
UISlider.appearance().maximumTrackTintColor = .systemGray
UISlider.appearance().thumbTintColor = .white

层级和变换属性

// 图层属性(继承自 UIView)
var layer: CALayer { get }

// 变换矩阵
var transform: CGAffineTransform { get set }

// 用户交互
var isUserInteractionEnabled: Bool { get set }

// 是否支持多点触控
var isMultipleTouchEnabled: Bool { get set }

// 是否独占触摸
var isExclusiveTouch: Bool { get set }

1. 离散值滑块

class DiscreteSlider: UISlider {
    var stepValue: Float = 1.0
    
    override func setValue(_ value: Float, animated: Bool) {
        let roundedValue = round(value / stepValue) * stepValue
        super.setValue(roundedValue, animated: animated)
    }
    
    override var value: Float {
        get {
            return super.value
        }
        set {
            let roundedValue = round(newValue / stepValue) * stepValue
            super.value = roundedValue
        }
    }
}

2. 双向滑块(范围选择)

class RangeSlider: UIView {
    private let trackLayer = CALayer()
    private let lowerThumbLayer = CALayer()
    private let upperThumbLayer = CALayer()
    
    var minimumValue: Float = 0.0
    var maximumValue: Float = 1.0
    var lowerValue: Float = 0.2
    var upperValue: Float = 0.8
    
    // 实现双向滑块逻辑...
}

3. 垂直滑块

class VerticalSlider: UISlider {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2)
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2)
    }
}

常见问题和解决方案

1. 滑块拖拽时不够灵敏

// 增加滑块的触摸区域
override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
    let thumbRect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
    return thumbRect.insetBy(dx: -10, dy: -10) // 扩大触摸区域
}

2. 自定义滑道圆角

override func trackRect(forBounds bounds: CGRect) -> CGRect {
    var trackRect = super.trackRect(forBounds: bounds)
    trackRect.size.height = 8.0 // 自定义滑道高度
    return trackRect
}

override func layoutSubviews() {
    super.layoutSubviews()
    // 设置圆角
    layer.cornerRadius = 4.0
    layer.masksToBounds = true
}

3. 监听拖拽状态

private var isTracking = false

override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
    isTracking = true
    return super.beginTracking(touch, with: event)
}

override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
    isTracking = false
    super.endTracking(touch, with: event)
    
    // 拖拽结束后的处理
    print("拖拽结束,最终值: \(value)")
}

最佳实践

  1. 性能优化: 对于连续更新的场景,考虑使用 isContinuous = false 来减少事件触发频率
  2. 可访问性: 为滑块设置合适的 accessibilityLabelaccessibilityValue
  3. 用户体验: 提供视觉反馈,比如haptic feedback或声音提示
  4. 数值验证: 始终验证滑块的数值范围,避免越界问题
// 可访问性设置
slider.accessibilityLabel = "音量控制"
slider.accessibilityValue = "\(Int(slider.value * 100))%"

// Haptic反馈
let impactFeedback = UIImpactFeedbackGenerator(style: .light)
impactFeedback.impactOccurred()

Giscus 未启用:请在 src/site.config.ts 中配置 repoId 与 categoryId。