下面是一个快速的示例,详细说明了这种行为。
当滑块拇指最初位于中心的左侧(例如在最小值处)时,它会向右跳跃。如果我在iOS模拟器中运行应用程序,则拇指会在第一次触摸而没有任何拖动时跳跃。拇指总是朝向轨道的中心跳跃。只有当它位于轨道的精确中心时,它才不会跳跃。即使滑块未连接到任何内容,此行为也会出现。
有没有办法禁用它?
今天遇到了这个问题。由于某种原因,您需要设置自定义缩略图,并且它有效。
[self.yourSlider setThumbImage:[UIImage imageNamed:@"customThumb"] forState:UIControlStateNormal];
与此同时,在2019年和iOS 12中出现了这个bug
一个古老的问题,但仍然是一个相关的问题。因此,尽管被接受的答案正确,但它有一个小但重要的问题——拇指触摸区域变小了,而在大多数情况下增加可触摸区域会导致新的跳跃(已尝试覆盖thumbRect(forBounds和beginTracking方法)
让我们来修复它!
因此,解决方案并不复杂,但有点不方便(需要一些图像资源),仍然比重新实现自己的滑块更容易
这个类的目的是消除UIKit的bug,即在点击时跳动的拇指。 主要的技巧是用一些图像替换原始的拇指 其他代码扩展了可点击区域,具体如下: 1)设置一个带有一些边缘透明偏移量的图像,即一个圆形在更大的矩形内
setThumbImage(thumb,for:.normal)
2)较大的图像意味着较大的拇指,结果是轨道在图像的alpha区域下可见。因此,下一步是设置最小和最大轨道图像,分别在左侧和右侧跟踪
setMinimumTrackImage(anImage, for: .normal) setMaximumTrackImage(maxSliderImage, for: .normal)
但是图像还有一些 alpha 区域,需要“隐藏”拇指的轨迹(在最小/最大值处,它是纯粹可见的)。
4)当我们有更大的拇指和视觉上减少的轨迹(相对于滑块边界宽度)时, 需要通过重写 trackRect(forBounds 方法来增加轨迹的可见部分。 我们不会有超出滑块边界的轨迹,因为最小/最大图像的一部分是透明的 5)由于目标之一是增加拇指的触摸区域,需要重写 point(inside point:, with event:) 方法来使侧面的区域可触摸
附注:不要忘记在 xcassets 中设置最小和最大滑块轨迹属性: 1)水平切片和左/右插图 2)拉伸技术
class Slider: UISlider {
/// The value is distance between an image edge and thumb,
/// Assume that's an image scheme: [...o...] so 3 dots here is imageSideOffset, where 'o' is a thumb
/// as we want to hide that zone
private let imageSideOffset: CGFloat = 30
override func awakeFromNib() {
super.awakeFromNib()
if let thumb = UIImage(named: "slider_thumb"),
let minSliderImage = UIImage(named: "min_slider_track"),
let maxSliderImage = UIImage(named: "max_slider_track") {
setThumbImage(thumb, for: .normal)
setMinimumTrackImage(minSliderImage, for: .normal)
setMaximumTrackImage(maxSliderImage, for: .normal)
clipsToBounds = true
} else {
assertionFailure("failed to load slider's images")
}
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -imageSideOffset, dy: 0).contains(point)
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let superRect = super.trackRect(forBounds: bounds)
guard let _ = self.thumbImage(for: .normal) else {
return superRect
}
return superRect.insetBy(dx: -imageSideOffset, dy: 0)
}
}