UISlider 拇指中心位于轨道的起点和终点

Posted

技术标签:

【中文标题】UISlider 拇指中心位于轨道的起点和终点【英文标题】:UISlider with thumb center over the start and end of track 【发布时间】:2016-11-09 08:10:22 【问题描述】:

UISlider 的默认行为是它的拇指不在轨道的开始/结束处。如下:

我想修改它的行为以获得:

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

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

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

【问题讨论】:

嗨,现在我面临同样的问题,但用户界面不同,没有拇指图像(在 xib 中给拇指颜色以清除)。现在,如果我将滑块值设置为 0,最小值将最小为 4 到 6 个像素,我不能设置零和最大值。如果您找到解决方案,请帮助我。 嗨,如何在滑块的开始和结束处添加垂直线?我尝试添加 minTrackImage/maxTrackImage 但它们的轨道空间很大。可以分享一下解决方法吗? 【参考方案1】:

UISlider 类有一个方法thumbRect(forBounds:trackRect:value:),您可以覆盖该方法来控制滑块缩略图的绘制矩形。因此,假设这个空间是 5 个点(可能会因您使用的拇指图像而异),我们可以执行以下操作:

    子类 UISlider 并覆盖 thumbRect(forBounds:trackRect:value:) 以将我们自己挂钩到进程中 定义 thumbSpace(我假设它是 5),我们可以从 thumbSpace 计算起始偏移量(滑块前 5 个点)和结束偏移量(滑块后 5 个点)。 计算与当前值、minValue 和 maxValue 相关的拇指平移(换句话说,根据当前值,我们稍微移动拇指以覆盖我们不想显示的空间) 将一个移位的矩形(应用 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)
    

【讨论】:

滑动时效果很好,但是当您再次抓住拇指接近一个极限时,它会很快跳到另一个值,有什么线索可以解决这个问题吗?【参考方案2】:

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)
    

【讨论】:

【参考方案3】:

当最小值为

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
    

【讨论】:

以上是关于UISlider 拇指中心位于轨道的起点和终点的主要内容,如果未能解决你的问题,请参考以下文章

iOS Swift - UISlider - 添加第二个轨迹栏

具有清晰背景的 UISlider 拇指图像在其后面显示轨道

在透明拇指图像后面隐藏 UISlider 轨道

如何在不移动滑块拇指色调的情况下将多种颜色应用于uislider轨道?

在 UIslider 轨道上获取事件

UISlider 的 minView 超出了它的边界和拇指的中心