UISlider - beginTracking behaviour changed on iOS 12

Hi folks,


I have noticed a strange issue on the latest version of iOS 12 beta. This has consistently been an issue on atleast previous 3 beta builds.


What we have in our code is a custom slider which is a subclass of UISlider. To enable tap events on the slider, we use the following code:


override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        return true
    }


Now this works fine on iOS 10 and iOS 11. You can slide as usual and thanks to the above code you can tap on slider and it slides automatically. However in iOS 12 this doesn't work. You have to force touch on it for tap to work.


It is easy to replicate, add a UISlider subclassed slider in one page app and add the above function in iOS 10, 11 and 12. You can see that tap works on 10 and 11 however on 12 - only force touch (long press on SE) works.


The API diff shows no change at documentation level - I am looking forward to understand what changed here. Any help appreciated.


Awaiting reply,

Rahul Mathur

Accepted Reply

@implementation XXXSliderClass

- (BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {

if(@available(iOS 12.0, *)){

CGFloat width = self.frame.size.width;

CGPoint tapPoint= [touch locationInView:self];

float fPercent = tapPoint.x/width;

int nNewValue = self.maximumValue * fPercent + 0.5;

if(nNewValue!=self.value){

self.value = nNewValue;

}

}

return YES;

}

@end

Replies

Is this in simulator or device ?


I have an app where I subclass UISlider ; there is a tapGestureRecognizer.

I have set trackPad to react to touch as a click.

=> Check you have the same setting

In simulator, either IOS 11.4 or IOS12, when I just tap on a trackpad, the slider moves


On device, I could only test with IOS11, and tap moves the slider (as for you).

Hi Claude,

The above beginTracking function implementation doesn't require tapGesture to be implemented on subclassed slider to get tap behavior - that was the benefit of using this function. I have tested the above scenario on devices.

Bumping this thread - Anyone knows what changed here?

Any update on how to fix this issue ? Because i am also facing the same issue.

@implementation XXXSliderClass

- (BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {

if(@available(iOS 12.0, *)){

CGFloat width = self.frame.size.width;

CGPoint tapPoint= [touch locationInView:self];

float fPercent = tapPoint.x/width;

int nNewValue = self.maximumValue * fPercent + 0.5;

if(nNewValue!=self.value){

self.value = nNewValue;

}

}

return YES;

}

@end

Thank you! This worked for me (Swift version):


override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {

if #available(iOS 12.0, *) {

let width = self.frame.size.width

let tapPoint = touch.location(in: self)

let fPercent = tapPoint.x/width

let nNewValue = self.maximumValue * Float(fPercent)

if nNewValue != self.value {

self.value = nNewValue

}

}

return true

}

Note that new value calculation is not correct there, this is how it should be, also added `sendAction(_:)` for extra awesomeness.


    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        let tapPoint = touch.location(in: self)
        let fraction = Float(tapPoint.x / bounds.width)
        let newValue = (maximumValue - minimumValue) * fraction + minimumValue

        if newValue != value {
            value = newValue
            sendActions(for: .valueChanged)
        }

        return true
    }