SliderControl is a small Swift Package aiming to recreate volume and track sliders found in Apple Music on iOS 16 and later.
To use SliderControl
in UIKit projects, simply create it and add as a subview like any other view or control. It maintains an API similar to built-in UISlider
with the same properties, like value
and isContinuous
, and allows you to track the progress by employing the target-action pattern:
sliderControl.addTarget(self, action: #selector(sliderValueChanged), for: .valueChanged)
Alternatively, you can subscribe to valuePublisher
to receive value updates:
sliderCancellable = sliderControl.valuePublisher.sink { value in
...
}
To use the control in SwiftUI project, create its wrapper view called SliderControlView
:
@State private var sliderValue: Float = 0.5
var body: some View {
SliderControlView(value: $sliderValue)
}
Slider's track color can be customized by changing the defaultTrackColor
and the enlargedTrackColor
properties. By default enlargedTrackColor
property is set to nil
, so the slider won't change the track color upon interaction. However, by setting different colors, you can configure the slider to change its track color when user interacts with it.
UIKit:
sliderControl.defaultTrackColor = .quaternarySystemFill
sliderControl.enlargedTrackColor = .secondarySystemFill
SwiftUI:
SliderControlView(value: $value)
.trackColor(.gray)
// or
.trackColor(.gray, enlarged: .black)
The same customization can also be applied to progress color by changing the defaultProgressColor
and the enlargedProgressColor
properties. And again, enlargedProgressColor
property behaves in the same way as enlargedTrackColor
and is nil
by default.
UIKit:
sliderControl.defaultProgressColor = .tertiarySystemFill
sliderControl.enlargedProgressColor = .systemFill
SwiftUI:
SliderControlView(value: $value)
.progressColor(.blue)
// or
.progressColor(.blue, enlarged: .purple)
These customizations allow you to create different appearances for different states of the slider. Here's an example:
By default SliderControl
and its SwiftUI wrapper SliderControlView
provide haptic feedback when slider reaches its minimum or maximum values. This behavior can be changed by setting a custom feedback generator, or setting it to nil
to disable it completely. To make your own feedback generator, create a class that conforms to SliderFeedbackGenerator
protocol. Here's an example of custom feedback generator:
class MyFeedbackGenerator: SliderFeedbackGenerator {
private let feedbackGenerator: UINotificationFeedbackGenerator = .init()
func preapre() {
feedbackGenerator.prepare()
}
func generateMinimumValueFeedback() {
feedbackGenerator.notificationOccurred(.warning)
}
func generateMaximumValueFeedback() {
feedbackGenerator.notificationOccurred(.success)
}
}
UIKit:
sliderControl.feedbackGenerator = MyFeedbackGenerator()
// or, to disable the haptic feedback
sliderControl.feedbackGenerator = nil
SwiftUI:
SliderControlView(value: $value)
.feedbackGenerator(MyFeedbackGenerator())
// or, to disable the haptic feedback
.feedbackGenerator(nil)
This control provides its own implementation of feedback generator, so if you want to reset this behavior, use ImpactFeedbackGenerator()
with feedbackGenerator
property and SwiftUI modifier.
Just like the built-in slider, SliderControl
also supports value ranges. To specify valid value range just change the valueRange
property or pass it the initializer of SliderControlView
.
UIKit:
sliderControl.valueRange = 0...178
SwiftUI:
SliderControlView(value: $sliderValue, in: 0...178)
onEditingChanged
- Fired when user starts dragging the slider, and then fired again when users lets go of the slider;
UIKit:
sliderControl.onEditingChanged = { isEditing in
if isEditing {
// dragging began
} else {
// dragging ended
}
}
SwiftUI:
SliderControlView(value: $sliderValue) { isEditing in
if isEditing {
// dragging began
} else {
// dragging ended
}
}
SliderControl
and its SwiftUI wrapper SliderControlView
support right-to-left languages.