iOS - 首次触摸 UISlider 时跳跃

20
我已经在使用Xcode 5.1开发iOS应用程序时,向应用程序添加了一个UISlider,但是无法摆脱以下令人讨厌的行为。当我第一次触碰拇指时,它会跳动一小段距离。
下面是一个快速的示例,详细说明了这种行为。
当滑块拇指最初位于中心的左侧(例如在最小值处)时,它会向右跳跃。如果我在iOS模拟器中运行应用程序,则拇指会在第一次触摸而没有任何拖动时跳跃。拇指总是朝向轨道的中心跳跃。只有当它位于轨道的精确中心时,它才不会跳跃。即使滑块未连接到任何内容,此行为也会出现。
有没有办法禁用它?

这是纯粹的模拟器现象吗?你手头有设备可以试一下吗?如果只是模拟器的问题,你应该笑笑并忽略它。鼠标光标不是一个又大又胖的手指,也许模拟器在某种程度上进行了补偿。 - matt
不,我在iPad上测试时也会出现这种情况。我只是提到模拟器是为了强调“跳跃”不是因为我无意中在iPad屏幕上移动手指所导致的。 - user3501984
我简直不敢相信我以前从未注意过这一点(除非它是新的iOS 7.1行为)! - matt
8
好的,这是已知问题并且有解决方案:https://dev59.com/xWEi5IYBdhLWcg3w2POB - matt
1
太棒了!非常感谢,不确定我是如何错过那个其他答案的。 - user3501984
显示剩余5条评论
2个回答

4

今天遇到了这个问题。由于某种原因,您需要设置自定义缩略图,并且它有效。

[self.yourSlider setThumbImage:[UIImage imageNamed:@"customThumb"] forState:UIControlStateNormal];

1

与此同时,在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)拉伸技术

change slicing attributes

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)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接