TL;DR
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(from: $count), in: 1...8, step: 1)
Benefits of this approach:
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 these are static extensions defined on Binding
itself.)
Here are the aforementioned extension methods...
public extension Binding {
static func convert<TInt, TFloat>(from 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>(from 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(from: $count), in: 1...8, step: 1)
}
}
.padding()
}
}
And finally, here are the results...
