UISlider in Mac Catalyst updates UI too late

46 views Asked by At

I am developing a Mac Catalyst app using UIKit. I have set the "Mac Catalyst Interface" of the target to "Optimize for Mac". All UISliders in my app behave strangely as they update their UI "one interaction late": When I click on the slider track, the value of the slider changes accordingly, but the knob does not move to the appropriate position. Only when I click the second time, the knob moves to that position. But when I click on a different position on the track instead, the knob will move to the location corresponding to the previous click. What I tried:

  • Changing "isContinuous", it has no effect.
  • Listen for the "valueChanged" event and in the handler call "setNeedsLayout()" on the slider.
  • Listen for the "valueChanged" event and in the handler call "setNeedsDisplay()" on the slider.

When I change the target's "Mac Catalyst Interface" to "Scaled to match iPad", UISlider behaves as expected. But I need it to be "Optimize for Mac".

FWIW, here is my code to add a UISlider in a UIViewController, it is super basic stuff:

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    let slider = UISlider()
    view.addSubview(slider)
    slider.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      slider.heightAnchor.constraint(equalToConstant: 50),
      slider.widthAnchor.constraint(equalToConstant: 300),
      slider.centerXAnchor.constraint(equalTo: view.centerXAnchor),
      slider.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    ])
    slider.addTarget(self, action: #selector(onSlider(_:)), for: .valueChanged)
  }
  
  @objc func onSlider(_ slider: UISlider) {
//    slider.setNeedsLayout()
//    slider.setNeedsDisplay()
    print("on slider: \(slider.value)")
  }

}
1

There are 1 answers

0
Marc-André Weibezahn On

I found a suitable workaround (for me at least): Set preferredBehavioralStyle to .pad to get the responsiveness (and look) of iOS sliders. At this point they look almost identically anyway. So I wrote this tiny UISlider extension:

extension UISlider {
  static func padSlider() -> UISlider {
    let slider = UISlider()
    slider.preferredBehavioralStyle = .pad
    return slider
  }
}