# SliderWithLabel

[swift](../../swift)⟩ [custom](..) ⟩ [control]() ⟩ <mark style="color:purple;">`SliderWithLabel`</mark>&#x20;

{% hint style="info" %}
可自訂<mark style="color:yellow;">標題</mark>與<mark style="color:yellow;">數值格式</mark>的 [Slider](../../swiftui/control/slider)。
{% endhint %}

![](https://1830103165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M5-JmwCZMKh_d7RfBaN%2Fuploads%2Fb62jf26MIE6lb1zD7xAB%2Fslider%20with%20label.jpeg?alt=media\&token=b002af33-8960-46bf-a9d1-7658b5e490df)

{% tabs %}
{% tab title="💈範例" %}
```swift
// (defaults) in: 0...1, step: nil, specifier: "%.2f"
SliderWithLabel(         
    value: $t            
) { Text("寬度(0-1)：") } // title label

SliderWithLabel(
    value: $m, in: 100...200, step: 1, // step = 1
    specifier: "%.0f"                  // integer
) { Text("音量(0-200)：") }             // title label

SliderWithLabel(
    value: $n, in: 0...100, step: 5,   // step = 5
    specifier: "%.0f"                  // integer
) { Text("音量(0,5...100)：") }
```
{% endtab %}

{% tab title="💾 程式" %}
```swift
import SwiftUI
import GeometryKit

struct SliderWithLabel<
    V: BinaryFloatingPoint & _FormatSpecifiable, 
    TitleLabel: View 
//    ValueLabel: View
>: View where V.Stride: BinaryFloatingPoint {
    
    @Binding var value: V
    
    let `in`: ClosedRange<V>
    let step: V.Stride?
    var min: V { `in`.lowerBound }
    var max: V { `in`.upperBound }
    var t: V { (value - min)/(max - min) }
    
    let specifier: String    // like "%.0f"
    
    /*@ViewBuilder*/ let titleLabel: () -> TitleLabel
    
    let knobWidth: CGFloat = 28
    let yOffset: CGFloat = -16
    
    init(value: Binding<V>, in bounds: ClosedRange<V>, step: V.Stride? = nil, specifier: String = "%.0f", titleLable: @escaping () -> TitleLabel = {Text("Untitled")}){
        self._value = value
        self.in = bounds
        self.step = step
        self.specifier = specifier
        self.titleLabel = titleLable
    }
      
    var body: some View {
        HStack {
            titleLabel()
            sliderWithValueLabel
        }
        .padding(.top, 30)
    }// body
    
    // slider
    @ViewBuilder var slider: some View {
        if let step = step {
            Slider(value: $value, in: `in`, step: step)
        } else {
            Slider(value: $value, in: `in`)
        }
    }
    
    // slider + value label
    var sliderWithValueLabel: some View {
        slider
            .background { 
                GeometryReader { geo in
                    Text("\(value, specifier: specifier)")
                        // ⭐️ position label directly
                        .position(geo.size[CGFloat(t), 0])    // GeometryKit
                        .offset(y: yOffset)           // move upward
                }//GeometryReader
                .padding(.horizontal, knobWidth/2)    // ⭐️ knob half width
            }// slider.background
    }// sliderWithValueLabel
    
}// ValueSlider
```

📁 Examples & Previews

```swift
// value slider example
private struct SliderWithLabelExample: View {
    
    @State var m: CGFloat = 150    // 100, 101 ... 200 (integer)
    @State var t: CGFloat = 0.8    // 0 ... 1          (decimal)
    @State var n: CGFloat = 25     // 0, 5, ... 100    (integer)
    
    var body: some View {
        VStack {
            Spacer()
            Form {
                
                SliderWithLabel(         // in       : 0...1  (default)
                    value: $t            // step     : nil    (default) 
                ) { Text("寬度(0-1)：") } // specifier: "%.2f" (default)
                
                SliderWithLabel(
                    value: $m, in: 100...200, step: 1, // step = 1
                    specifier: "%.0f"                  // integer
                ) { Text("音量(0-200)：") }
                    .frame(maxWidth: 500)
                
                SliderWithLabel(
                    value: $n, in: 0...100, step: 5,   // step = 5
                    specifier: "%.0f"                  // integer
                ) { Text("音量(0,5...100)：") }
                    .accentColor(.red)
                
            }// Form
            Spacer()
        }
    }// body
}// ValueSliderExample

// ------------- Previews --------------

// previews
struct SliderWithLabel_Previews: PreviewProvider {
    static var previews: some View {
        SliderWithLabelExample()
    }
}
```
{% endtab %}

{% tab title="⬆️ 需要" %}
* [geometrykit](../package/geometrykit "mention")：利用 <mark style="color:blue;">`size[x, y]`</mark> 的語法來計算[位置](../../swiftui/view/layout/position)。
{% endtab %}

{% tab title="👥 相關" %}
* <mark style="color:purple;">`SliderWithLabel`</mark>：
  * 使用 [binding](../../swiftui/view/state/binding/binding "mention") 變數。
  * 是一個[自製的](..) [slider](../../swiftui/control/slider "mention")。
* [label-position](../../swiftui/control/slider/label-position "mention")：講解<mark style="color:yellow;">如何擺放數值標籤</mark>的細節。
{% endtab %}
{% endtabs %}
