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 - 添加第二个轨迹栏