Skip to content

Latest commit

 

History

History
302 lines (238 loc) · 9.95 KB

Usage.md

File metadata and controls

302 lines (238 loc) · 9.95 KB

Usage

A slider consists of a handle that the user moves between two extremes of a linear “track”. The ends of the track represent the minimum and maximum possible values. As the user moves the handle, the slider updates its bound value.

Single value

The following example shows a slider bound to the speed value in increments of 5. As the slider updates this value, a bound Text view shows the value updating.

Speed

@State private var speed = 50.0

var body: some View {
    CompactSlider(value: $speed, in: 0...100, step: 5) {
        Text("Speed")
        Spacer()
        Text("\(Int(speed))")
    }
}

When used by default, the range of possible values is 0.0...1.0:

@State private var value = 0.5

var body: some View {
    CompactSlider(value: $value) {
        Text("Value")
        Spacer()
        String(format: "%.2f", value)
    }
}

Using the direction: parameter you can set the direction in which the slider will indicate the selected value:

Direction

@State private var value = 0.5

var body: some View {
    CompactSlider(value: $value, direction: .center) {
        Text("Center")
        Spacer()
        String(format: "%.2f", value)
    }
}

Range values

The slider allows you to retrieve a range of values. This is possible by initialising the slider with the parameters from: and to:.

The following example asks for a range of working hours:

Range Values

@State private var lowerValue: Double = 8
@State private var upperValue: Double = 17

var body: some View {
    HStack {
        Text("Working hours:")
        CompactSlider(from: $lowerValue, to: $upperValue, in: 6...20, step: 1) {
            Text("\(zeroLeadingHours(lowerValue))\(zeroLeadingHours(upperValue))")
            Spacer()
        }
    }
}

private func zeroLeadingHours(_ value: Double) -> String {
    let hours = Int(value) % 24
    return "\(hours < 10 ? "0" : "")\(hours):00"
}

Styling

The slider supports changing appearance and behaviour. In addition to the standard style, the Prominent style is also available.

To implement your own style, you need to implement the CompactSliderStyle protocol, which contains many parameters that allow you to define the view according to user events. The styles are implemented in the same pattern as ButtonStyle.

Configuration

CompactSliderStyleConfiguration properties:

Configuration

The following example shows how to create your own style and use the configuration:

public struct CustomCompactSliderStyle: CompactSliderStyle {
    public func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(
                configuration.isHovering || configuration.isDragging ? .orange : .black
            )
            .background(
                Color.orange.opacity(0.1)
            )
            .accentColor(.orange)
            .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

public extension CompactSliderStyle where Self == CustomCompactSliderStyle {
    static var `custom`: CustomCompactSliderStyle { CustomCompactSliderStyle() }
}

And now we can apply it:

@State private var value: Double = 0.5

var body: some View {
    CompactSlider(value: $value) {
        Text("Custom Style")
        Spacer()
        Text(String(format: "%.2f", value))
    }
    .compactSliderStyle(.custom)
}

custom1@2x

Secondary Appearance

The slider consists of several secondary elements, which can also be defined within their own style or directly for the slider.

  1. The .compactSliderSecondaryColor modifier allows you to set the color and opacity for the secondary slider elements. You can simply change the base color for secondary elements: .compactSliderSecondaryColor(.orange).

  2. Using the other signature of the modifier: `.compactSliderSecondaryColor', the color can be set individually for each secondary element.

  3. Another modifier .compactSliderSecondaryAppearance gives you the ability to change the ShapeStyle for the progress view.

Let's take the previous example and change the secondary elements:

public struct CustomCompactSliderStyle: CompactSliderStyle {
    public func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(
                configuration.isHovering || configuration.isDragging ? .orange : .black
            )
            .background(
                Color.orange.opacity(0.1)
            )
            .accentColor(.orange)
            .compactSliderSecondaryColor(
                .orange,
                progressOpacity: 0.2,
                handleOpacity: 0.5,
                scaleOpacity: 1,
                secondaryScaleOpacity: 1
            )
            .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

Custom Style 1

Now change the solid color of the progress view to a gradient using the `compactSliderSecondaryAppearance' modifier:

public struct CustomCompactSliderStyle: CompactSliderStyle {
    public func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(
                configuration.isHovering || configuration.isDragging ? .orange : .black
            )
            .background(
                Color.orange.opacity(0.1)
            )
            .accentColor(.orange)
            .compactSliderSecondaryAppearance(
                progressShapeStyle: LinearGradient(
                    colors: [.orange.opacity(0), .orange.opacity(0.5)],
                    startPoint: .leading,
                    endPoint: .trailing
                ),
                focusedProgressShapeStyle: LinearGradient(
                    colors: [.yellow.opacity(0.2), .orange.opacity(0.7)],
                    startPoint: .leading,
                    endPoint: .trailing
                ),
                handleColor: .orange,
                scaleColor: .orange,
                secondaryScaleColor: .orange
            )
            .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

Custom Style 2

One of the slider parameters allows you to control the visibility of the handle. For this gradient example, it can be disabled:

CompactSlider(value: $value, handleVisibility: .hidden) {
    Text("Custom Style")
    Spacer()
    Text(String(format: "%.2f", value))
}
.compactSliderStyle(.custom)

Custom Style

Prominent Style

Prominent style allows for a more dramatic response for the selected value. It requires two colors, which determine the accent color depending on the progress of the selected value. You can also optionally apply a background gradient based on these colors.

Prominent Style

@State private var chooseSide: Double = 0.5
@State private var temperature: Double = 20

var body: some View {
    VStack(alignment: .leading, spacing: 24) {
        // 1.
        CompactSlider(value: $chooseSide, direction: .center) {
            Text("Red")
            Spacer()
            Text("Blue")
        }
        .compactSliderStyle(
            .prominent(
                lowerColor: .red,
                upperColor: .blue
            )
        )
        
        // 2.
        HStack {
            Text("Temperature:")
            CompactSlider(value: $temperature, in: -10...30, step: 2) {}
                .compactSliderStyle(
                    .prominent(
                        lowerColor: .blue,
                        upperColor: .orange,
                        useGradientBackground: true
                    )
                )
            Text("\(Int(temperature))")
                .frame(width: 50, alignment: .trailing)
        }
    }
}

Advanced Layout

The slider provides a state that can be used for more advanced layouts. To do this, you must subscribe for state changes via bindings.

CompactSliderState

CompactSliderState

In the following example, we will show the value in the progress position:

@State private var value: Double = 0.5
@State private var sliderState: CompactSliderState = .zero

var body: some View {
    ZStack {
        CompactSlider(value: $value, state: $sliderState) {}
        
        Text("\(Int(100 * value))%")
            .foregroundColor(.white)
            .padding(6)
            .background(
                Capsule().fill(Color.blue)
            )
            .offset(x: sliderState.dragLocationX.lower)
            .allowsHitTesting(false)
    }
}

Advanced Layout