How to detect the event when the user has ended the drag of a slider pointer?
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
Events [x] Continuous Updates
setting for UISliderView. Unchecking this sets continuous
to false/NO. –
Whiskey self.mySlider.isContinuous = false
–
Kindly 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
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.
allTouches
which belong to different phases? –
Sidras isContinuous = true
in your UISlider
. –
Hoagy allTouches
will be nil
when incrementing/decrementing the value with VoiceOver. –
Deason 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. –
Zymogen 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");
}
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") }
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
.
UISlider
has changed since I wrote this answer. –
Aekerly UIControlEventTouchCancel
handler in iOS 9. But I'm able to invoke UIControlEventTouchUpInside
and UIControlEventTouchUpOutside
only. –
Seif You can use:
- (void)addTarget:(id)target action:(SEL)action
forControlEvents:(UIControlEvents)controlEvents
to detect when the touchDown and touchUp events occur in UISlider
I think you need the control event UIControlEventTouchUpInside
.
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")
}
}
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
}
}
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)")
}
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()
}
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.
RxSwift:
self.slider.rx.controlEvent([.touchUpInside, .touchUpOutside])
.bind(to: self.viewModel.endSlidingSlider)
.disposed(by: self.disposeBag)
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.
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);
}
© 2022 - 2024 — McMap. All rights reserved.