Search code examples
swiftuisliderswift3xcode8-beta6

Workaround for UISlider bug introduced in XCode 8 Beta 6?


I'm migrating some code to XCode 8 Beta 6, that was working pretty well until XCode 8 Beta 1 inclusively (it was migrated previously from 7.3). Everything is working, except for a new strange behavior with the sliders when using a custom thumb image bigger than the original slider's built-in one:

override func viewDidLoad() {
    super.viewDidLoad()
    sliderBuggy.setThumbImage(UIImage(named: "actionRobotDelay.png"), for: UIControlState())
}
  • Correct behavior: Before Beta 6, once I set the new thumb image, the tracking area was automatically adjusted and the user can slide it from any point inside the image (note: I'm testing on a real iPad mini, not a simulator, and I did not try with iPhone at all).

  • What's happening now: After changing the image, it looks just fine, but the tracking area that allows the user to slide it is still the small one from the original slider's built-in image. This is absolutely annoying from a users's perspective.

What I have tried so far:

  1. Subclassing and overriding thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect. Sadly, after debugging, I found that the method was returning the correct new CGRect, so changing it has not effect.

  2. Overriding touchesBegan to evaluate where the slider is seeing the touch event, so as a possible workaround I could start the tracking manually. But touchesBegan showed clearly that the touch event was only received on the small area that belonged to the original image.

Any idea about a different possible workaround, before I just go and write my own slider class from scratch will be welcome.


Solution

  • Subclass and munge hit-testing to do what the slider should have been doing (who knows why it isn't doing it?):

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let tr = self.trackRect(forBounds: self.bounds)
        if tr.contains(point) { return self }
        let r = self.thumbRect(forBounds: self.bounds, trackRect: tr, value: self.value)
        if r.contains(point) { return self }
        return nil
    }