0

I have a UISlider object in an iOS app, initialized with the following code.

theSlider = UISlider()

The basic functionality is all right, but what I need is to clearly handle these three events separately:

  • the event when the user starts to move the slider.
  • the event when the user is to moving the slider.
  • the event when the user stops moving the slider.

Currently I use this code:

theSlider.addTarget(self, action: #selector(sliderHandle(_:)), 
                    for: .valueChanged)

and it's OK to handle the second event. But for the first and third, I suppose I need to subclass UISlider without being sure. Any tip will be welcome.

Michel
  • 10,303
  • 17
  • 82
  • 179

2 Answers2

1

As a general note, be sure to check out the class hierarchy, e.g. the superclasses of widgets, to see what other methods are available to the widgets that inherit from them.

You don't necessarily need to subclass UISlider, but you may want to subclass it or, depending on what you're doing, UIControl, if you think re-usability would be worthwhile.

UISlider is a subclass of UIControl, which is a subclass of UIView. UIControl is a 'widgetized' UIView, in other words, insofar as it provides methods primarily that facilitate detection of user input, and support for sending events, features that would tend to be common to any UI control widget.

For movement and position detection, the UIControl class has methods beginTracking(), continueTracking(), endTracking(), cancelTracking(), isTracking(), isTouchInside(). Those are available directly from the UISlider object.

Similarly, you can explicitly trigger actions (events) with sendAction() and sendActions(), made public by UIControl thus implicitly available to UISlider.

If you don't need to subclass, you can write a "one-off" (e.g. app-specific) bit of code to utilize the aforementioned methods directly through your UISlider instance, directly tracking the 'touches' to the widget and delivering events at key positions along the slide path, or with specific behaviors you detect.

See this question, "IPhone: How to detect end of slider drag" for implementation ideas.

Apple's UIControl documentation has a subclassing notes section explaining how to use the target-action mechanism.

clearlight
  • 12,255
  • 11
  • 57
  • 75
1

UIControl.Event has many other values besides .valueChanged. .touchDowncan tell you when the user starts interacting with the slider and the pair . touchUpInside and .touchUpOutside can tell you when the user finishes dragging. Here is a playground example:

import SwiftUI
import PlaygroundSupport

class V: UIViewController {
  let slider = UISlider(frame: .init(origin: .zero, size: .init(width: 200, height: 50)))
  override func viewDidLoad() {
    super.viewDidLoad()
    slider.minimumValue = 0
    slider.maximumValue = 100
    slider.value = 50
    slider.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(slider)
    slider.addTarget(self, action: #selector(changed), for: .valueChanged)
    slider.addTarget(self, action: #selector(began), for: .touchDown)
    slider.addTarget(self, action: #selector(ended), for: .touchUpInside)
    slider.addTarget(self, action: #selector(ended), for: .touchUpOutside)
  }
  @objc private func changed(sender: UISlider) {
    print("Changed")
  }
  @objc private func began(sender: UISlider) {
    print("Began")
  }
  @objc private func ended(sender: UISlider) {
    print("Ended")
  }
}
PlaygroundPage.current.liveView = V()
Josh Homann
  • 15,933
  • 3
  • 30
  • 33