An iOS-16-styled slider.
Available on iOS 13 and later. Supports RTL.
Slyderin.Demo.mov
Use Swift Package Manager to add it to your project. On how to use Swift Package Manager, read this: https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app
import Slyderin
into your source file, and add a Slider
object to your view:
import Slyderin
class ViewController: UIViewController {
private weak var slider: Slider!
// ......
func loadView() {
super.loadView()
let slider = Slider()
view.addSubview(slider)
// your layout code......
}
// ......
}
The size of the Slider
is not intrinsic, meaning it won't have a size of its own. You have to prevent its size or position from being ambiguous. For example, if you set a bottom constraint for it, you then have to set a top constraint or a height constraint for it, too.
A Slider
has a built-in padding of 20px on each side by default, to increase the touch area. This causes the slider to be indented. For example, if you want a slider to fit in some view with a 20px padding on each side:
slider.fillSuperview(padding: 20)
Then you will find the paddings have become 40px, due to the extra built-in 20px paddings. The built-in 20px padding is there for the touch area. The recommendation is to keep it and reduce your outer padding to 0px:
slider.fillSuperview(padding: 0)
However, if you do want to change the paddings, they are in its directionalLayoutMargins
.
Set the slider's valueChangeHandler
or call onValueChange(_:)
to receive value changes:
Slider()
.height(50)
.onValueChange {
// new value $0 received
}
Slyderin uses Slyderin.ThumblessSlider
by default. You can change its initializer's parameters to more-or-less do some customizations:
Slider(
slider: ThumblessSlider(
direction: .bottomToTop,
scaling: .both(onAxis: 1.05, againstAxis: 1.15),
cornerRadius: .fixed(12),
visualEffect: UIBlurEffect(style: .systemMaterialDark)
)
)
-
direction
determines whether the slider is horizontal or vertical and how the track is filled, e.g.,:leadingToTrailing
. The slider is horizontal and the track is filled from the leading side to the trailing side when the user slides in leading-to-trailing direction. This is the default direction.bottomToTop
. The slider is vertical and the track is filled from bottom to top when the user slides upwards.
-
scaling
. The slider expands its size when responding to user inputs. This parameter specifies the expanding ratio. If you set it to.both(onAxis: 1.05, againstAxis: 1.15)
, for a horizontal slider, its becomes 1.05 times wider and 1.15 times taller. Defaults to (1, 1). -
cornerRadius
provides 2 different modes of corner radius:full
, the corner radius equals half the length against thedirection
's axis. For a horizontal slider with a height of 20px, the corner radius is 10px.fixed(CGFloat)
, a fixed corner radius.
-
visualEffect
specifies the visual effect of the unfilled track.
There is a new animation parameter on the way.
Slider
supports 2 different modes of tracking. Specify it when initializing:
Slider(options: [.tracks( /* .onTranslation, .onLocation or .onLocationOnceMoved */ )])
- The default tracking behavior is
.onTranslation
. In this mode, the slider cares about the finger's movements and distances, instead of its position. It's the same as Safari video player progress bar in iOS 16. - The other modes (
.onLocation
/.onLocationOnceMoved
), the thumb (the filled track) moves to where the finger is. Specifically, under.onLocationOnceMoved
mode, the slider won't start tracking until the finger moves.
You can specify a slider when initializing Slider
, as long as it is Slidable
:
init(slider: Slidable = DefaultSlider(), options: [Option] = [])
Slider
respects some of the standard UIKit parameters:
tintColor
changes the color of the filled track. Inherited from the superview by default.directionalLayoutMargins
determines the slider's margins from its touch-responsive area. Defaults to 20px each side.semanticContentAttribute
determines whether the slider should flip when the interface layout direction is right-to-left. Defaults tounspecifed
, which means it flips. Changes to this value won't apply until the next time theSlider
is added to superview.overrideUserInterfaceStyle
determines the blur effect is light or dark, if you have not specify a light or dark one.
There is also a built-in UISlider
subclass: Slyderin.UIKitSlider
, which, unfortunately, supports only the leading-to-trailing direction:
Slider(slider: UIKitSlider())
Built-in.UISlider.mov
You can implement your own Slidable
:
public protocol Slidable: AnyObject where Self: UIView {
var direction: Direction { get }
func fit(_ viewModel: Slider.ViewModel)
}
extension Slider {
public struct ViewModel {
public var maximumValue: Double = 1
public var minimumValue: Double = 0
public var value: Double = 0
public var interacting: Bool = false
}
}
Slidable
is a simple protocol. Your implementation should provides the direction it supports (or support multiple directions) and update itself according to the value changes.