Search code examples
iosswiftuislider

UISlider Tracking Callout Unaligned to Thumb


I have a uislider that has a callout bubble whose center X follows above the center X of the uislider thumb.

I tested it on an iPhone 7 and it works perfectly, and it also works perfectly on other devices once the thumb is moved.

The issue I have is that on initial load, the bubble and thumb should be aligned as it does when the thumb is moved, but on a device like an iPhone 8+ or iPhone SE, the bubble's center x is off from the thumb's center x (+/- 20-ish pts).

I believe the calculation to get the two objects aligned is correct since it works fine when you actually move the thumb, but something with the initial calculation of the thumb's x is off. With some console logs, the thumb's X would initially read as 180 pts but on touch the first value is actually 201 pts. The bubble then adjusts accordingly.

I am using a custom uislider subclass for gradients and such, and that could potentially be affecting it(?) but it's confusing how it still works on touch.

Any help would be appreciated.

On viewDidLoad (leading constraint is to safe area):

distanceSlider.setValue(Float(sliderValue), animated: false)

distanceCalloutViewLeadingConstraint.constant = distanceSlider.thumbCenterX - (distanceCalloutView.center.x - distanceCalloutView.frame.minX)

On distance change:

distanceCalloutViewLeadingConstraint.constant = distanceSlider.thumbCenterX - (distanceCalloutView.center.x - distanceCalloutView.frame.minX)

Thumb center X extension:

extension UISlider {
    var thumbCenterX: CGFloat {
        let trackRect = self.trackRect(forBounds: frame)
        let thumbRect = self.thumbRect(forBounds: bounds, trackRect: trackRect, value: value)
        return thumbRect.midX
    }
}

Solution

  • Try setting below line in viewDidLayoutSubviews(). It looks like the view in with slider is added is not properly layout its size.

    distanceCalloutViewLeadingConstraint.constant = distanceSlider.thumbCenterX - (distanceCalloutView.center.x - distanceCalloutView.frame.minX)
    

    Why are you using custom image and adjusting according to slider value. You can directly use

    func setThumbImage(_ image: UIImage?, for state: UIControl.State) check the reference apple doc link https://developer.apple.com/documentation/uikit/uislider/1621336-setthumbimage