iPhone : How to detect the end of slider drag?
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
How to detect when user finished moving Range slider in Swift
To detect when user finished moving the range slider you can add a controlevent to your slider , you can add it programatically :
mySlider.addTarget(self, action: "sliderDidEndSliding:", forControlEvents: .UIControlEventTouchUpInside)
then you have to do your logic the recieving methode .
func sliderDidEndSliding(sender: UISlider) {
}
How to handle a slider in 3 phases?
UIControl.Event has many other values besides .valueChanged
. .touchDown
can 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()
How can I track when value changed AND when dragging stopped?
The term for the solution you are trying to find is called "Debouncing". The idea is that you coalesce frequent calls to the same method and only execute the method once the calls have stopped for a period of time. Debouncing is a great way to improve the user experience when you are taking in a lot of user input quickly and must do a relatively heavy workload on that input. Only executing the work when the user has completed their input saves the cpu from doing too much work and slowing the app down. Some examples might be moving a view when the user scrolls the page, updating a table view when the user enters a search term or making network calls after a series of button taps.
An example showing how one may implemented it with a UISlider
is shown below in a playground. You can copy and paste the example into an empty playground to give it a try.
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
// Timer to record the length of time between debounced calls
var timer: Timer? = nil
override func loadView() {
super.loadView()
let view = UIView()
view.backgroundColor = .white
// Set up the slider
let slider = UISlider(frame: CGRect(x: 100, y: 100, width: 200, height: 50))
slider.minimumValue = 0
slider.maximumValue = 100
slider.isContinuous = true
slider.addTarget(self, action: #selector(sliderValueDidChange(_:)), for: .valueChanged)
self.view.addSubview(slider)
}
@objc func sliderValueDidChange(_ sender: UISlider) {
// Coalesce the calls until the slider valude has not changed for 0.2 seconds
debounce(seconds: 0.2) {
print("slider value: \(sender.value)")
}
}
// Debounce function taking a time interval to wait before firing after user input has stopped
// and a function to execute when debounce has stopped being called for a period of time.
func debounce(seconds: TimeInterval, function: @escaping () -> Swift.Void ) {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: false, block: { _ in
function()
})
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
PlaygroundPage.current.needsIndefiniteExecution = true
The meat of the example is this function:
func debounce(seconds: TimeInterval, function: @escaping () -> Swift.Void ) {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: false, block: { _ in
function()
})
}
Here every time debounce
is called it invalidates a timer and then schedules a new timer to call the function
passed in. This ensures that the function
is not called until enough time has elapsed to not have the timer invalidated.
How to detect that a UISlider has been tapped using RubyMotion?
To get notified when the slider has been changed, you need to set up the target/action
.
The target
is the object containing the method you want called, and the action
is the
method you want called. I called my action
sliderValueChanged:
. You can choose anything. Be sure to append the colon to the name because that tells it to send a pointer to the sender which is the UISlider
object. You need the sender so that you can ask for the value of the slider.
If you don't set a minimumValue
and maximumValue
for the slider, the values will range from 0.0
to 1.0
.
def viewDidLoad
slider = UISlider.alloc.initWithFrame([[20, 70], [260, 40]])
slider.addTarget(self, action:'sliderValueChanged:', forControlEvents:UIControlEventValueChanged)
self.view.addSubview(slider)
end
def sliderValueChanged(sender)
puts sender.value
end
As shown, sliderValueChanged
will get called continuously as the user moves the slider. To be notified only when the user stops touching the slider, set:
slider.continuous = no
Now, if you want a clickable slider that moves the thumb to where you click, then you need to add a UITapGestureRecognizer
to the slider. This code demonstrates this:
def viewDidLoad
slider = UISlider.alloc.initWithFrame([[50, 50], [200, 40]])
tapGestureRecognizer = UITapGestureRecognizer.alloc.initWithTarget(self, action:'sliderTapped:')
tapGestureRecognizer.numberOfTapsRequired = 2
slider.addGestureRecognizer(tapGestureRecognizer)
slider.continuous = false
slider.minimumValue = 77
slider.maximumValue = 129
slider.addTarget(self, action:'sliderValueChanged:', forControlEvents:UIControlEventValueChanged)
self.view.addSubview(slider)
end
# This is called when the slider changes either from taps or from moving the thumb
def handle_new_slider_value(value)
puts "New slider value: #{value}"
end
def sliderValueChanged(slider)
handle_new_slider_value(slider.value)
end
# These were determined empirically by setting the thumb to the minimum and
# then clicking on the center and printing out gestureRecognizer.locationInView(slider).x
# and then repeating for the maximum.
SLIDER_MIN = 11
SLIDER_MAX = 189
def sliderTapped(gestureRecognizer)
if gestureRecognizer.state == UIGestureRecognizerStateEnded
slider = gestureRecognizer.view
x = gestureRecognizer.locationInView(slider).x
# Uncomment this to determine values for SLIDER_MIN/SLIDER_MAX
# puts x
x = SLIDER_MIN if x < SLIDER_MIN
x = SLIDER_MAX if x > SLIDER_MAX
slider_min_val = slider.minimumValue
slider_max_val = slider.maximumValue
# Convert from the location in the view to the slider value
slider.value = slider_min_val + (x - SLIDER_MIN) / (SLIDER_MAX - SLIDER_MIN) * (slider_max_val - slider_min_val)
handle_new_slider_value(slider.value)
end
end
Note that this code moves the slider on a double tap. I had trouble with just a single tap because if you move the thumb quickly, the code treats it as a tap and snaps the thumb back to its starting position. Set tapGestureRecognizer.numberOfTapsRequired = 1
to play around with the single tap.
iOS how to make slider stop at discrete points
To make the slider "stick" at specific points, your viewcontroller should, in the valueChanged method linked to from the slider, determine the appropriate rounded from the slider's value and then use setValue: animated: to move the slider to the appropriate place. So, if your slider goes from 0 to 2, and the user changes it to 0.75, you assume this should be 1 and set the slider value to that.
Related Topics
iOS Autolayout: Two Buttons of Equal Width, Side by Side
Upload Image to the PHP Server from iOS
Convert Mkcoordinateregion to Mkmaprect
Uidevice Currentdevice Model Possible Values
How to Build a Url with Query Parameters Containing Multiple Values for the Same Key in Swift
How to Detect Whether I Have iPhone 2G,3G,3Gs
How to Display Clickable Links in Uitextview
How to Add Cgpoint Objects to an Nsarray the Easy Way
Uiview Backgroundcolor Disappears When Uitableviewcell Is Selected
Simulator Slow-Motion Animations Are Now On
Get the Current View Controller from the App Delegate
The Maximum Number of Apps for Free Development Profiles Has Been Reached. Xcode 11.5
Attempting to Load the View of a View Controller While It Is Deallocating... Uisearchcontroller