🎚️
SwiftUIでInt値を扱うSliderの作成
概要
- SwiftUIのSliderではInt型を扱えない。
- そこで内部で
Binding<Double>
を経由させ、表側ではInt
を扱えるようなカスタムのSliderを作成する。
参考
実装
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