How to detect the event when the user has ended the drag of a slider pointer?
-
4Use:[slider addTarget:self action:@selector(sliderStoppedDragging:) forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside]; – Henry Sou Jun 29 '18 at 06:58
-
Yesssss! ThankYOU! – Markus Nov 26 '20 at 22:36
16 Answers
If you don't need any data inbetween drag, than you should simply set:
[mySlider setContinuous: NO];
This way you will receive valueChanged
event only when the user stops moving the slider.
Swift 5 version:
mySlider.isContinuous = false
-
3This is the best answer to this question. I wish we could changed the answer to this. – M. Porooshani Sep 10 '15 at 04:34
-
1http://i.imgur.com/0Edd2xe.png?1 XCode version 6.x has this feature of setting setContinuous via IDE itself. – Abhijeet Sep 14 '15 at 11:34
-
1
-
1Xcode 7.3 Interface Builder has `Events [x] Continuous Updates` setting for UISliderView. Unchecking this sets `continuous` to false/NO. – leanne Jul 13 '16 at 22:16
-
3Great Answer. Here is the Swift 4 Code: `self.mySlider.isContinuous = false` – Marco Weber Dec 16 '17 at 11:52
-
5This is not what the author is asking. He want continuously slide, and also want to know when to stop. – andrewchan2022 Sep 05 '18 at 06:29
-
2@lbsweek: OP (author) is asking
how to detect **the end** of slider drag
. There is no much maneuvering space for free interpretation left in the wording of this question. – Rok Jarc Sep 05 '18 at 07:14 -
@RokJarc That's fine, this solution meet most developer's need according to the feedback. – andrewchan2022 Sep 05 '18 at 07:31
-
2
-
@ChewieTheChorkie: it answers OP's question: that is what SO is all about ;-) – Rok Jarc Nov 07 '18 at 14:43
-
2
-
-
2This doesn't answer the question; it only provides a workaround that was useful in this case. – Oscar Nov 17 '19 at 22:36
-
1Thankssss, you save my Fxxxing time, man! I'm struggling about which event to detect the end of drag for slider, and didn't find one. And I don't care about values during the slider change the audio track currentTime. – Zhou Haibo Jun 03 '21 at 11:21
-
@M.Porooshani Disagree; this answer makes it so you can't read values mid-drag which is a core functionality of UISlider. An ideal answer (which exists in this thread thankfully) is one that allows you to use a UISlider as expected while also being able to detect the UITouchPhaseEnded event. – Albert Renshaw Dec 28 '22 at 01:23
-
@AlbertRenshaw: OP was asking about detecting the end of slider drag. Probably because he was not interested in values between. – Rok Jarc Jan 03 '23 at 17:17
You can add an action that takes two parameters, sender and an event, for UIControlEventValueChanged:
[slider addTarget:self action:@selector(onSliderValChanged:forEvent:) forControlEvents:UIControlEventValueChanged]
Then check the phase of the touch object in your handler:
- (void)onSliderValChanged:(UISlider*)slider forEvent:(UIEvent*)event {
UITouch *touchEvent = [[event allTouches] anyObject];
switch (touchEvent.phase) {
case UITouchPhaseBegan:
// handle drag began
break;
case UITouchPhaseMoved:
// handle drag moved
break;
case UITouchPhaseEnded:
// handle drag ended
break;
default:
break;
}
}
Swift 4 & 5
slider.addTarget(self, action: #selector(onSliderValChanged(slider:event:)), for: .valueChanged)
@objc func onSliderValChanged(slider: UISlider, event: UIEvent) {
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .began:
// handle drag began
case .moved:
// handle drag moved
case .ended:
// handle drag ended
default:
break
}
}
}
Note in Interface Builder when adding an action you also have the option to add both sender and event parameters to the action.

- 2,562
- 1
- 18
- 11
-
2
-
3thanks @RoiMulia, I don't remember where I first saw it, I've been using in sliders for years. I sometimes use it to ignore the change on UITouchPhaseEnded since the value tends to jump when the user lifts their finger. – Devin Pitcher Aug 30 '16 at 03:49
-
Is this a robust way to handle it? What if there are multiple events in `allTouches` which belong to different phases? – David Mar 09 '17 at 23:03
-
-
2
-
I wrote some code in case : .move and .end, now what happen is slider thumb Image is not moving smoothly.With out any stuff in .move and , .end slider is moving smoothly. – Malleswari Jan 04 '18 at 12:36
-
@Malleswari as you move the slider the .moved case will gets called continuously (i.e. many many times) on the main thread as the slider position updates. So you don't want to do any processor or I/O intensive work in the .move case. – Devin Pitcher Jan 05 '18 at 00:37
-
But my slider is not smooth. I am calling slider like this progressSlider.addTarget(self, action: #selector(sliderTouchEvents), for: UIControlEvents.valueChanged) – Malleswari Jan 05 '18 at 06:48
-
@Malleswari what are you doing inside the .move case? You shouldn't do anything that affects the state of the slider or that takes more than a few milliseconds to process. – Devin Pitcher Jan 05 '18 at 16:00
-
4This is a great solution, however it has an issue with touch cancelling. Despite there being a "cancelled" event in the touchEvent enum, it is not fired when the touch is cancelled. Therefore I recommend also adding a listener for the touchCancel event from the Slider. This should cover all possibilities. – bnussey Jul 19 '18 at 19:30
-
@Malleswari You can declare this: private var renderTimer = Timer() And then use where you need it as: self.renderTimer = Timer( timeInterval: 0.1, target: self, selector: #selector(AudioMessageCell.renderTimerCycle), userInfo: nil, repeats: true ) Where you can actually change timeInterval, lower it to 0,01 for example, to get your slider moving smoother. – timetraveler90 Jun 18 '19 at 12:23
-
3I saw that sometimes the phase can go: began, stationary, moved, but then never ended nor cancelled. This is problematic for my use case as I expected every interaction to end or be canceled. The fix is noted above: use a separate touch cancel target/action. – Jordan H Jan 28 '20 at 04:00
-
2Also note that `allTouches` will be `nil` when incrementing/decrementing the value with VoiceOver. – Jordan H Jan 28 '20 at 04:49
-
Unfortunately, this does not work in Catalyst, where event is uninitialized and hence allTouches is nil. Any workaround? – Victor Engel Nov 27 '21 at 19:49
-
Probably worth also considering `UITouchPhaseCancelled`. I haven't tested, but if it's anything like GestureRecognizers then the following flow would fail: Drag a slider then simultaneously tap a notification dropdown which exits the app mid-drag thus ending the drag without `UITouchPhaseEnded` being called. – Albert Renshaw Dec 28 '22 at 01:27
I use the "Touch Up Inside" and "Touch up outside" notifications.
Interface Builder:
Connect both notifications in the Interface Builder to your receiving method. The method could look like this:
- (IBAction)lengthSliderDidEndSliding:(id)sender {
NSLog(@"Slider did end sliding... Do your stuff here");
}
In code:
If you want to wire it programatically you would have something like this in your viewWillAppear (or wherever it fits you) call:
[_mySlider addTarget:self
action:@selector(sliderDidEndSliding:)
forControlEvents:(UIControlEventTouchUpInside | UIControlEventTouchUpOutside)];
The receiving method would look like this:
- (void)sliderDidEndSliding:(NSNotification *)notification {
NSLog(@"Slider did end sliding... Do your stuff here");
}

- 1,446
- 8
- 20
Swift 5 and Swift 4
Add target for
touchUpInside
andtouchUpOutside
events. You can do it either programatically or from storyboard. This is how you do it programaticallyslider.addTarget(self, action: #selector(sliderDidEndSliding), for: [.touchUpInside, .touchUpOutside])
Write your function to handle the end of slider drag
func sliderDidEndSliding() { print("end sliding") }

- 5,526
- 5
- 42
- 67
-
-
This doesn't detect whether or not a drag has ever happened necessarily, and can be triggered by simply tapping without dragging. – Chewie The Chorkie Nov 06 '18 at 16:25
Since UISlider
is a subclass of UIControl
, you can set a target and action for its UIControlEventTouchUpInside
.
If you want to do it in code, it looks like this:
[self.slider addTarget:self action:@selector(dragEndedForSlider:)
forControlEvents:UIControlEventTouchUpInside];
That will send you a dragEndedForSlider:
message when the touch ends.
If you want to do it in your nib, you can control-click your slider to get its connections menu, and then drag from the “Touch Up Inside” socket to the target object.
You should also add a target and action for UIControlEventTouchUpOutside
and for UIControlEventTouchCancel
.

- 375,296
- 67
- 796
- 848
-
1@rob mayoff Sorry but you do need to use UIControlEventTouchUpOutside. Otherwise the selector won't be called if your finger is not on slider when you finish dragging. – user3164248 Apr 11 '15 at 07:15
-
2
-
Can confirm that you *do* need to also register a handler for UIControlEventTouchUpOutside in iOS 9. – lmirosevic Jun 09 '16 at 14:40
-
I was never able to invoke `UIControlEventTouchCancel` handler in iOS 9. But I'm able to invoke `UIControlEventTouchUpInside` and `UIControlEventTouchUpOutside` only. – petrsyn Sep 29 '16 at 13:36
-
The answer taking two parameters, above, does not work in Catalyst. See my comment there. This answer does, though. – Victor Engel Nov 27 '21 at 19:58
You can use:
- (void)addTarget:(id)target action:(SEL)action
forControlEvents:(UIControlEvents)controlEvents
to detect when the touchDown and touchUp events occur in UISlider

- 79,884
- 17
- 117
- 140

- 3,010
- 19
- 34
Swift 3 answer
I had same problem and eventually got this to work, so maybe it will help somebody. Connect your_Slider to 'Value Changed' in storyboard and when slider moved "Slider Touched" actioned and when let go "Slider Released".
@IBAction func your_Slider(_ sender: UISlider) {
if (yourSlider.isTracking) {
print("Slider Touched")
} else {
print("Slider Released")
}
}

- 107
- 1
- 8
-
2Good solution, but careful because Slider Released is called when begin dragging **and** end dragging – Guy Daher May 10 '17 at 15:36
-
Swift 3.1
Sometimes you will want the slider's drag events to fire continuously, but have the option of executing different code depending on whether the slider is still being dragged or has just finished being dragged.
To do this, I've expanded on Andy's answer above that makes use of the slider's isTracking
property. I needed to record two states: sliderHasFinishedTracking
and sliderLastStoredValue
.
My code correctly:
doesn't fire an action upon starting drag
fires the action if the user only nudges the slider with a single tap (meaning that
isTracking
remainsfalse
)
class SliderExample: UIViewController {
var slider: UISlider = UISlider()
var sliderHasFinishedTracking: Bool = true
var sliderLastStoredValue: Float!
override func loadView() {
super.loadView()
slider.minimumValue = 100.0
slider.maximumValue = 200.0
slider.isContinuous = true
slider.value = 100.0
self.sliderLastStoredValue = slider.value
slider.addTarget(self, action: #selector(respondToSlideEvents), for: .valueChanged)
// add your slider to the view however you like
}
func respondToSlideEvents(sender: UISlider) {
let currentValue: Float = Float(sender.value)
print("Event fired. Current value for slider: \(currentValue)%.")
if(slider.isTracking) {
self.sliderHasFinishedTracking = false
print("Action while the slider is being dragged ⏳")
} else {
if(self.sliderHasFinishedTracking && currentValue == self.sliderLastStoredValue){
print("Slider has finished tracking and its value hasn't changed, " +
"yet event was fired anyway. ") // No need to take action.
} else {
self.sliderHasFinishedTracking = true
print("Action upon slider drag/tap finishing ⌛️")
}
}
self.sliderLastStoredValue = currentValue
}
}

- 5,839
- 1
- 46
- 60
In Swift 4 you can use this function
1 Frist step:- Adding the target in slider
self.distanceSlider.addTarget(self, action: #selector(self.sliderDidEndSliding(notification:)), for: ([.touchUpInside,.touchUpOutside]))
2 Second step:- Create a function
@objc func sliderDidEndSliding(notification: NSNotification)
{
print("Hello-->\(distanceSlider.value)")
}

- 2,484
- 2
- 21
- 39

- 892
- 10
- 16
Maybe you should add target for UIControlEventTouchUpInside、UIControlEventTouchUpOutside、UIControlEventTouchCancel events.
I met the same problem before , because i don't add target for UIControlEventTouchCancel event.

- 17
- 1
RxSwift:
self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside])
.bind(to: self.viewModel.endSlidingSlider)
.disposed(by: self.disposeBag)

- 5,977
- 3
- 50
- 55
Create an action and outlet for the slider (or you can typecast sender from action to UISlider), and in the UI Uncheck the Continuous Updates check box. This way we will get the slider value only when slider stops dragging.
@IBAction func actionSlider(_ sender: Any) {
let value = sliderSpeed.value.rounded()
}

- 146
- 9
I had similar issue recently. Here is what I did in Swift:
theSlider.continuous = false;
The code that holds this continuous value reads:
public var continuous: Bool // if set, value change events are generated
// any time the value changes due to dragging. default = YES
The default seems to be YES (true). Setting it it to false does the thing you want.

- 3,645
- 1
- 24
- 40
Try like this
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 10.0;
[customSlider addTarget:self action:@selector(changeSlider:) forControlEvents:UIControlEventValueChanged];
-(void)changeSlider:(id)sender{
UISlider *slider=(UISlider *)sender;
float sliderValue=(float)(slider.value );
NSLog(@"sliderValue = %f",sliderValue);
}

- 1,292
- 11
- 20
-
That sends the action every time the slider's thumb moves, not just when the drag has ended. – rob mayoff Feb 22 '12 at 07:02