🎚️

SwiftUIでInt値を扱うSliderの作成

2023/10/02に公開

概要

image

参考

実装

import SwiftUI

struct IntSlider<Label>: View where Label: View {
    
    @Binding private var value: Int
    
    private let bounds: ClosedRange<Double>
    private let step: Int
    private let label: () -> Label
        
    private var intProxy: Binding<Double> {
        Binding<Double>(
            get: {
                Double(value)
            }, set: {
                value = Int($0)
            })
    }
    
    var body: some View {
        
        Slider(value: self.intProxy,
               in: self.bounds,
               step: Double.Stride(self.step)) {
            label()
        } minimumValueLabel: {
            Text("\(Int(self.bounds.lowerBound))")
        } maximumValueLabel: {
            Text("\(Int(self.bounds.upperBound))")
        }
    }
    
    init(
        value: Binding<Int>,
        in bounds: ClosedRange<Double> = 0...10,
        step: Int = 0,
        @ViewBuilder label: @escaping () -> Label = { EmptyView() }
    ) {
        self._value = value
        self.bounds = bounds
        self.step = step
        self.label = label
    }
}

#Preview {    
    @State var refreshRate = 50
    
    return IntSlider(value: $refreshRate,
                     in: 45...120,
                     step: 5) {
        Text("Refresh rate")
    }.padding()
}

呼び出し例

import SwiftUI

struct ContentView: View {
    
    @State var refreshRate = 50
    
    var body: some View {
        Form {
            Section {
                VStack {
                    HStack {
                        Text("リフレッシュレート")
                        Spacer()
                        Text("\(refreshRate)フレーム / 秒")
                            .monospacedDigit()
                            .foregroundStyle(.secondary)
                    }
                    IntSlider(value: $refreshRate,
                              in: 45...120,
                              step: 5) {
                        Text("Refresh rate")
                    }.padding(.horizontal)
                    
                }
            } header: {
                Text("Advanced")
            }
        }
    }
}

#Preview {
    ContentView()
}

Discussion