带有拇指中心的UISlider在赛道的开始和结束

时间:2016-11-09 08:10:23

标签: ios uikit uislider

UISlider的默认行为是它的拇指不以轨道的开头/结尾为中心。如下所示:

default UISlider

我想修改它的行为:

desired slider

拇指的中心位于开始或结束位置。

我试图用空UIView覆盖开始/结束。效果是看起来几乎没问题,但拇指有阴影,在某些位置显示我的黑客(我可以忍受),但是我的 hacky 视图覆盖了一点拇指并抓住了它触摸事件(即使禁用了用户交互)。

所以我想我需要在拇指和轨道之间打包我的 hacky 视图。可能没有操纵其内部视图。有什么想法吗?

3 个答案:

答案 0 :(得分:2)

UISlider类具有方法thumbRect(forBounds:trackRect:value:),您可以重写该方法以控制滑块的拇指图像的绘制矩形。因此,假设此空间为5点(可能会因您使用的拇指图像而异),我们可以执行以下操作:

  1. 子类UISlider并重写thumbRect(forBounds:trackRect:value:)以将自己吸引到流程中
  2. 定义thumbSpace(我假定为5),然后从thumbSpace中计算出开始偏移量(滑块前5点)和结束偏移量(滑块后5点)。
  3. 计算相对于当前值,minValue和maxValue的拇指平移(换句话说,基于当前值,我们将拇指略微移动以覆盖我们不想显示的空间)
  4. 将移位后的矩形(应用x转换后)返回给super方法以进行常规计算

完整的代码应如下所示:

class CustomSlider: UISlider {
    let defaultThumbSpace: Float = 5
    lazy var startingOffset: Float = 0 - defaultThumbSpace
    lazy var endingOffset: Float = 2 * defaultThumbSpace

    override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
        let xTranslation =  startingOffset + (minimumValue + endingOffset) / maximumValue * value
        return super.thumbRect(forBounds: bounds,
                               trackRect: rect.applying(CGAffineTransform(translationX: CGFloat(xTranslation),
                                                                          y: 0)),
                               value: value)
    }
}

答案 1 :(得分:0)

像我这样的懒人的Swift 5版本:)

class CustomSlider: UISlider {

private let trackHeight: CGFloat = 8

override func trackRect(forBounds bounds: CGRect) -> CGRect {
    let point = CGPoint(x: bounds.minX, y: bounds.midY)
    return CGRect(origin: point, size: CGSize(width: bounds.width, height: trackHeight))
}

private let thumbWidth: Float = 52
lazy var startingOffset: Float = 0 - (thumbWidth / 2)
lazy var endingOffset: Float = thumbWidth

override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
    let xTranslation =  startingOffset + (minimumValue + endingOffset) / maximumValue * value
    return super.thumbRect(forBounds: bounds, trackRect: rect.applying(CGAffineTransform(translationX: CGFloat(xTranslation), y: 0)), value: value)
}
}

答案 2 :(得分:0)

当最小值 < 0 时,Mostafa 和 ergunkocak 的解决方案对我来说失败了。这就是我最终使用的:

class CustomSlider: UISlider {
    var customThumbSpacing: CGFloat?

    override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
        if let customThumbSpacing = customThumbSpacing {
            let minOrigin = super.thumbRect(forBounds: bounds, trackRect: rect, value: minimumValue).origin.x
            let maxOrigin = super.thumbRect(forBounds: bounds, trackRect: rect, value: maximumValue).origin.x
            let defaultFrame = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
            
            let newOrigin = defaultFrame.origin.x.map(
                from: minOrigin...maxOrigin,
                to: minOrigin-customThumbSpacing...maxOrigin+customThumbSpacing)
                        
            return CGRect(x: newOrigin,
                          y: defaultFrame.origin.y,
                          width: defaultFrame.width,
                          height: defaultFrame.height)
        } else {
            return super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
        }
    }
}

extension CGFloat {
    func map(from: ClosedRange<CGFloat>, to: ClosedRange<CGFloat>) -> CGFloat {
        let result = ((self - from.lowerBound) / (from.upperBound - from.lowerBound)) * (to.upperBound - to.lowerBound) + to.lowerBound
        return result
    }
}