简约同样简单:为UISlider添加显示当前值的标签(下)

版权声明:大熊猫猪·侯佩原创或翻译作品.谢绝转载! hopy https://blog.csdn.net/mydo/article/details/86686043

本文在重构的基础上,从类封装的角度重新实现UISlider的功能扩展:显示当前的值,比之前更加简单和易于维护。建议在看完上篇之后再来观赏。

上篇观赏在此 : 简约同样简单:为UISlider添加显示当前值的标签(上)

为什么要重写?

在上篇里我们已经实现了UISlider的扩展功能,已经可以用了,为什么还要费事再说它呢?

原因是:它的封装性不足,对外太开放。

在这里插入图片描述

举个栗子:UISlider上面的标签竟然放在Slider外面,这意味着标签如果需要修改外观或功能,还得到它外面去做,这显然不合理!

为了以后能够更好地重用,显然的做法是:做一个单独的类,继承于UISlider!

从零开始

新建HyValueSlider.swift文件,我们先打一个框架:

/// 带值显示的Slider控件
class HyValueSlider:UISlider{

}

现在是空空如也!

然后我们创建几个init方法:

convenience init() {
    self.init(frame: .zero)
}

override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
}

不管你从哪个初始化方法创建对象,最终都要调用setup()。

那么我们就来实现setup方法:

// Slider内部的初始化设置
private func setup(){
    valueLbl = UILabel(frame: CGRect(origin: .zero, size: thumbSize))
    valueLbl.textAlignment = .center
    valueLbl.textColor = valueTextColor
    valueLbl.font = valueTextFont
    
    valueLbl.shadowColor = .darkGray
    valueLbl.shadowOffset = CGSize(width: 0.5, height: 0.5)
    
    self.addSubview(valueLbl)
}

为了让用户有更多的定制性,我们需要对外提供接口:

private var valueLbl:UILabel!
// 值文本的颜色
var valueTextColor:UIColor = .gray{
    didSet{
        valueLbl.textColor = valueTextColor
    }
}

// 值文本的字体
var valueTextFont:UIFont = UIFont.systemFont(ofSize: 12){
    didSet{
        valueLbl.font = valueTextFont
    }
}

如上,现在用户可以随意更改标签的字体和颜色,So easy!

关于把手

因为要在Slider的把手上添加Label,所以我们需要向往常一样想办法取得它的位置和大小信息:

// 返回把手当前所在的Rect
private var thumbRect:CGRect{
    let trackRect = self.trackRect(forBounds: self.bounds)
    let thumbRect = self.thumbRect(forBounds: self.bounds, trackRect: trackRect, value: self.value)
    return thumbRect
}

// 返回把手的大小
private var thumbSize:CGSize{
    return thumbRect.size
}

这里和上篇中的实现类似,唯一不同的是:由于是在Slider自身上添加标签,所以不需要再做坐标的转换。

接着,更新Label显示更是小菜一碟:

// 更新valueLbl中显示的值
private func updateValueLbl(){
    let valueString = String(format: "%.1f", self.value)
    valueLbl.text = "\(valueString)"
}

最后我们要找准更新Label的时机。

注意在前一篇中,我们采取的办法是Hook控件的事件,在其中更新Label的位置和内容。

在这里我们无需如此,因为UISlider在每次把手被拖动时都会显式调用layoutSubviews()方法,我们只需在其中做文章即可:

// 每次拖动把手都会调用layoutSubviews()
override func layoutSubviews() {
    super.layoutSubviews()
    let rect = thumbRect
    let center = CGPoint(x: rect.midX, y: rect.midY)
    valueLbl.center = center
    updateValueLbl()
    // 需要在layoutSubviews()中将valueLbl前置,在setup()中无效
    self.bringSubview(toFront: valueLbl)
}

值得注意的是,我们需要将Label放到视图最前方,否则会被遮挡住。

结尾

这样,我们就完成了所有功能!

既简单又易于维护!

GitHub完整代码在此:

https://github.com/hopy11/HyValueSlider

感谢观赏,下次见 😉

在这里插入图片描述

没有更多推荐了,返回首页