SwiftUI: componente Slider

Qué es Slider

El componente Slider permite seleccionar un valor entre un mínimo y un máximo definido. Es un componente equivalente a UISlider de UIKit.

Aquí podéis consultar la documentación oficial

El componente tiene varios ‘inicializadores’ con diferentes parámetros que permiten controlar diferentes aspectos de su comportamiento:

@State var slider1: Double = 2

...

Slider(value: $slider1, in: 0...100)
@State var slider2: Double = 40

...

Slider(value: $slider2, in: 0...1000, step: 10)
@State var slider3: Double = 50

...

Slider(value: $slider3, in: -100...100, minimumValueLabel: Text("Min"), maximumValueLabel: Text("Max")) { Text("") }
  • value: variable donde se almacenará el valor actual del Slider. Es una variable de estado y se modificará conforme el valor del Slider cambie.
  • in: rango de valores permitido, entre un mínimo y un máximo.
  • step: distancia entre entre cada valor válido.
  • onEditingChanged: bloque que se llamará así cuando empiece o termine el cambio del valor del Slider.
  • minimumValueLabel: vista descriptiva para el valor mínimo del componente.
  • maximumValueLabel: vista descriptiva para el valor máximo del componente

Nota: el parámetro value es una variable de estado que usará el componente Slider para asignar el valor seleccionado. Cuando queremos usar un valor fijo (por ejemplo, por motivos de pruebas) podemos usar la función .constant(), que pertenece al struct Binding para cumplir con su implementación sin tener que declarar la variable de estado.

Cómo leer datos de un SIider

El componente Slider necesita que el valor del parámetro value sea una variable de estado de tipo Double. Esta variable de estado será la encargada de almacenar el valor actual del componente y se modificará cuando el usuario interactúe con el Slider.

struct ContentView: View {
    @State var value: Double = 2
        
    var body: some View {
        Group {
            Slider(value: $value, in: 0...10)
        }
    }
}

Por ejemplo, podemos mostrar un texto con el valor actual cuando la variable value sea mayor que 5.

struct ContentView: View {
    @State var value: Double = 2
        
    var body: some View {
        Group {
            Slider(value: $value, in: 0...10)
            if value >= 5 {
                Text("Current value: (value)")
            }
        }
    }
}

Modificadores comunes para SIider

El componente Slider comparte los mismos métodos de personalización que el componente View, y pueden ser consultados en el siguiente enlace.

Actualmente el componente no acepta muchas modificaciones sobre su aspecto visual, por lo que prácticamente no podemos personalizarlo.

accentColor

Permite modificar el color de resalto de la vista y de los componentes que esta contenga.

Slider(value: $slider1, in: -100...100, minimumValueLabel: Text("Min"), maximumValueLabel: Text("Max")) { Text("") }
    .accentColor(.green)

Podemos usar este modificador para cambiar el color de progreso del slider.

Cómo personalizar el SIider

Como hemos indicado anteriormente, la personalización del componente Slider es muy limitada en estos momentos por lo que en muchas ocasiones no podremos usar este componente.

Una forma de conseguir un Slider personalizado es exponiendo el componente UISlider de UIKit a través del protocolo UIViewRepresentable. De esta forma el resultado final será que estamos realizando una adaptación del componente UISlider para que podamos usarlo en SwiftUI, pudiendo decidir qué propiedades podemos personalizar.

import SwiftUI
import UIKit

public struct SliderCustom: UIViewRepresentable {
    final public class Coordinator: NSObject {
        var value: Binding
        
        init(value: Binding) {
            self.value = value
        }
        
        @objc func valueChanged(_ sender: UISlider) {
            self.value.wrappedValue = Double(sender.value)
        }
    }
    
    var slider: UISlider = {
        var slider = UISlider(frame: .zero)
        return slider
    }()
    
    var thumbTintColor: UIColor? = nil
    var minimumTrackTintColor: UIColor? = nil
    var maximumTrackTintColor: UIColor? = nil
    var value: Binding
    
    public init(value: Binding) {
        self.value = value
    }
    
    public func makeUIView(context: Context) -> UISlider {
        slider.thumbTintColor = thumbTintColor
        slider.minimumTrackTintColor = minimumTrackTintColor
        slider.maximumTrackTintColor = maximumTrackTintColor
        slider.value = Float(value.wrappedValue)
        
        slider.addTarget(
            context.coordinator,
            action: #selector(Coordinator.valueChanged(_:)),
            for: .valueChanged
        )
        
        return slider
    }
    
    public func updateUIView(_ uiView: UISlider, context: Context) {
        uiView.value = Float(self.value.wrappedValue)
    }
    
    public func makeCoordinator() -> Coordinator {
        Coordinator(value: value)
    }
}

public extension SliderCustom {
    func sliderThumbTintColor(_ thumbTintColor: UIColor) -> SliderCustom {
        var result = self
        result.thumbTintColor = thumbTintColor
        return result
    }
    
    func sliderMinimumTrackTintColor(_ minimumTrackTintColor: UIColor) -> SliderCustom {
        var result = self
        result.minimumTrackTintColor = minimumTrackTintColor
        return result
    }
    
    func sliderMaximumTrackTintColor(_ maximumTrackTintColor: UIColor) -> SliderCustom {
        var result = self
        result.maximumTrackTintColor = maximumTrackTintColor
        return result
    }
}

El componente SliderCustom que acabamos de definir permite personalizar algunos colores que Slider no permitía. Si queremos tener más control de personalización o de eventos solo tendremos que desarrollarlo sobre esta implementación.

El uso del componente será como cualquier otro componente de SwiftUI, y la personalización se realiza a través de los métodos definidos en la extension SliderCustom.

@State var slider3: Double = 0.7

...

SliderCustom(value: $slider3)
    .sliderThumbTintColor(.red)
    .sliderMinimumTrackTintColor(.green)
    .sliderMaximumTrackTintColor(.purple)

Ejemplo

Puedes encontrar este ejemplo en https://github.com/SDOSLabs/SwiftUI-Test bajo el apartado Slider.

Rafael Fernández,
iOS Tech Lider