I have a view with with an Int property named "score" that I want to adjust with a slider.
struct IntSlider: View {
@State var score:Int = 0
var body: some View {
VStack{
Text(score.description)
Slider(value: $score, in: 0.0...10.0, step: 1.0)
}
}
}
But SwiftUI's Slider only works with doubles/floats.
How can I make it work with my integer?
As an alternative to the other answers on this page, I propose a solution which leverages type-constrained, generic extension methods to simplify the call site. Here's an example of all you have to do:
Slider(value: .convert($count), in: 1...8, step: 1)
It automatically converts any Int
type (e.g. Int
, Int8
, Int64
) to any Float
type (e.g. Float
, Float16
, CGFloat
, Double
), and vice versa thanks to generics/overloads.
Once you have added the extension to your project (or in a package referenced by your project), you simply call .convert
at any binding site and it 'just works.'
There is nothing else needed to use it (i.e. no 'proxy' structs, vars or other local items to clutter your view.) You simply use it directly inline (see above.)
When in any place that takes a Binding
, simply type .
and code-completion will automatically suggest convert
as an option. This works because each extension method is both defined on Binding
, and it returns a Binding
(i.e. Self
) as its result type, thus making it discoverable to the auto-complete system. (This is true for any such static methods on any type.)
Here are the aforementioned extension methods...
public extension Binding {
static func convert<TInt, TFloat>(_ intBinding: Binding<TInt>) -> Binding<TFloat>
where TInt: BinaryInteger,
TFloat: BinaryFloatingPoint{
Binding<TFloat> (
get: { TFloat(intBinding.wrappedValue) },
set: { intBinding.wrappedValue = TInt($0) }
)
}
static func convert<TFloat, TInt>(_ floatBinding: Binding<TFloat>) -> Binding<TInt>
where TFloat: BinaryFloatingPoint,
TInt: BinaryInteger {
Binding<TInt> (
get: { TInt(floatBinding.wrappedValue) },
set: { floatBinding.wrappedValue = TFloat($0) }
)
}
}
...and here's a playground-ready demonstration showing them in use.
(Note: Don't forget to also copy over the extension methods above!)
struct ConvertTestView: View {
@State private var count: Int = 1
var body: some View {
VStack{
HStack {
ForEach(1...count, id: \.self) { n in
Text("\(n)")
.font(.title).bold().foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.blue)
}
}
.frame(maxHeight: 64)
HStack {
Text("Count: \(count)")
Slider(value: .convert($count), in: 1...8, step: 1)
}
}
.padding()
}
}
And finally, here are the results...