123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //
- // MultiValueSlider.swift
- //
- // Created by Yonat Sharon on 16/09/2019.
- //
- #if canImport(SwiftUI)
- import SweeterSwift
- import SwiftUI
- /// Slider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels.
- @available(iOS 13.0, *) public struct MultiValueSlider: UIViewRepresentable {
- public typealias UIViewType = MultiSlider
- private let uiView = MultiSlider()
- @Binding var value: [CGFloat]
- public init(
- value: Binding<[CGFloat]>,
- minimumValue: CGFloat? = nil,
- maximumValue: CGFloat? = nil,
- isContinuous: Bool? = nil,
- snapStepSize: CGFloat? = nil,
- isHapticSnap: Bool? = nil,
- valueLabelPosition: NSLayoutConstraint.Attribute? = nil,
- valueLabelAlternatePosition: Bool? = nil,
- isValueLabelRelative: Bool? = nil,
- orientation: NSLayoutConstraint.Axis? = nil,
- outerTrackColor: UIColor? = nil,
- valueLabelColor: UIColor? = nil,
- valueLabelFont: UIFont? = nil,
- thumbImage: UIImage? = nil,
- showsThumbImageShadow: Bool? = nil,
- minimumImage: UIImage? = nil,
- maximumImage: UIImage? = nil,
- trackWidth: CGFloat? = nil,
- hasRoundTrackEnds: Bool? = nil,
- distanceBetweenThumbs: CGFloat? = nil,
- keepsDistanceBetweenThumbs: Bool? = nil,
- valueLabelFormatter: NumberFormatter? = nil
- ) {
- _value = value
- uiView.minimumValue =? minimumValue
- uiView.maximumValue =? maximumValue
- uiView.isContinuous =? isContinuous
- uiView.snapStepSize =? snapStepSize
- uiView.isHapticSnap =? isHapticSnap
- uiView.valueLabelPosition =? valueLabelPosition
- uiView.valueLabelAlternatePosition =? valueLabelAlternatePosition
- uiView.isValueLabelRelative =? isValueLabelRelative
- uiView.orientation =? orientation
- uiView.outerTrackColor =? outerTrackColor
- uiView.valueLabelColor =? valueLabelColor
- uiView.valueLabelFont =? valueLabelFont
- uiView.thumbImage =? thumbImage
- uiView.showsThumbImageShadow =? showsThumbImageShadow
- uiView.minimumImage =? minimumImage
- uiView.maximumImage =? maximumImage
- uiView.trackWidth =? trackWidth
- uiView.hasRoundTrackEnds =? hasRoundTrackEnds
- uiView.distanceBetweenThumbs =? distanceBetweenThumbs
- uiView.keepsDistanceBetweenThumbs =? keepsDistanceBetweenThumbs
- uiView.valueLabelFormatter =? valueLabelFormatter
- }
- public func makeUIView(context: UIViewRepresentableContext<MultiValueSlider>) -> MultiSlider {
- uiView.addTarget(context.coordinator, action: #selector(Coordinator.valueChanged), for: .valueChanged)
- return uiView
- }
- public func updateUIView(_ uiView: MultiSlider, context: UIViewRepresentableContext<MultiValueSlider>) {
- uiView.value = value
- }
- public func makeCoordinator() -> Coordinator {
- Coordinator(self)
- }
- public class Coordinator: NSObject {
- let parent: MultiValueSlider
- init(_ parent: MultiValueSlider) {
- self.parent = parent
- }
- @objc func valueChanged(_ sender: MultiSlider) {
- parent.value = sender.value
- }
- }
- }
- @available(iOS 13.0, *) public extension MultiValueSlider {
- func minimumValue(_ value: CGFloat) -> Self {
- uiView.minimumValue = value
- return self
- }
- func maximumValue(_ value: CGFloat) -> Self {
- uiView.maximumValue = value
- return self
- }
- /// snap thumbs to specific values, evenly spaced. (default = 0: allow any value)
- func snapStepSize(_ value: CGFloat) -> Self {
- uiView.snapStepSize = value
- return self
- }
- /// snap thumbs to specific values. changes `minimumValue` and `maximumValue`. (default = []: allow any value)
- func snapValues(_ value: [CGFloat]) -> Self {
- uiView.snapValues = value
- return self
- }
- /// generate haptic feedback when hitting snap steps
- func isHapticSnap(_ value: Bool) -> Self {
- uiView.isHapticSnap = value
- return self
- }
- /// show value labels next to thumbs
- func valueLabelPosition(_ value: NSLayoutConstraint.Attribute) -> Self {
- uiView.valueLabelPosition = value
- return self
- }
- /// show every other value label opposite of the value label position.
- func valueLabelAlternatePosition(_ value: Bool) -> Self {
- uiView.valueLabelAlternatePosition = value
- return self
- }
- /// value label shows difference from previous thumb value (true) or absolute value (false = default)
- func isValueLabelRelative(_ value: Bool) -> Self {
- uiView.isValueLabelRelative = value
- return self
- }
- // MARK: - Appearance
- func orientation(_ value: NSLayoutConstraint.Axis) -> Self {
- uiView.orientation = value
- return self
- }
- /// track color before first thumb and after last thumb. `nil` means to use the tintColor, like the rest of the track.
- func outerTrackColor(_ value: UIColor?) -> Self {
- uiView.outerTrackColor = value
- return self
- }
- func valueLabelColor(_ value: UIColor?) -> Self {
- uiView.valueLabelColor = value
- return self
- }
- func valueLabelFont(_ value: UIFont?) -> Self {
- uiView.valueLabelFont = value
- return self
- }
- func thumbTintColor(_ value: UIColor?) -> Self {
- uiView.thumbTintColor = value
- return self
- }
- func thumbImage(_ value: UIImage?) -> Self {
- uiView.thumbImage = value
- return self
- }
- func thumbTouchExpansionRadius(_ value: CGFloat) -> Self {
- uiView.thumbTouchExpansionRadius = value
- return self
- }
- func showsThumbImageShadow(_ value: Bool) -> Self {
- uiView.showsThumbImageShadow = value
- return self
- }
- func minimumImage(_ value: UIImage?) -> Self {
- uiView.minimumImage = value
- return self
- }
- func maximumImage(_ value: UIImage?) -> Self {
- uiView.maximumImage = value
- return self
- }
- func snapImage(_ value: UIImage?) -> Self {
- uiView.snapImage = value
- return self
- }
- func trackWidth(_ value: CGFloat) -> Self {
- uiView.trackWidth = value
- return self
- }
- func hasRoundTrackEnds(_ value: Bool) -> Self {
- uiView.hasRoundTrackEnds = value
- return self
- }
- /// when thumb value is minimum or maximum, align it's center with the track end instead of its edge.
- func centerThumbOnTrackEnd(_ value: Bool) -> Self {
- uiView.centerThumbOnTrackEnd = value
- return self
- }
- /// minimal distance to keep between thumbs (half a thumb by default)
- func distanceBetweenThumbs(_ value: CGFloat) -> Self {
- uiView.distanceBetweenThumbs = value
- return self
- }
- func keepsDistanceBetweenThumbs(_ value: Bool) -> Self {
- uiView.keepsDistanceBetweenThumbs = value
- return self
- }
- func valueLabelFormatter(_ value: NumberFormatter) -> Self {
- uiView.valueLabelFormatter = value
- return self
- }
- func valueLabelTextForThumb(_ value: ((Int, CGFloat) -> String?)?) -> Self {
- uiView.valueLabelTextForThumb = value
- return self
- }
- }
- #endif
|