I currently have following custom component that wraps and styles a default TextField
from swift ui. I came across an issue where I now need to re-use this where @Binding
is no longer just String, but rather, can be a number like int or double, thus underlying TextField
needs to change and take in TextField(value: ..., formatter: ...)
instead of just text
.
I can turn all of the modifiers into a custom modifier and apply it to relevant text fields to apply the styling, but am wondering if there is a solution where I can keep this as a custom component and instead allow TextInputSmall
to take in and pass down all possible permutations of TextField arguments, for example
TextInputSmall("", text: $someString)
and TextInputSmall("", value: $someNumber, formatter: .number)
struct TextInputSmall: View {
// Public Variables
var accentColor = Color._orange
@Binding var text: String
// Private Variables
@FocusState private var focused: Bool
// Body
var body: some View {
TextField(
"",
text: $text
)
.font(...)
.foregroundStyle(...)
.accentColor(...)
.focused($focused)
.submitLabel(.done)
.frame(...)
.padding(...)
.background(...)
}
}
You can basically "steal" the declarations of TextField
and its initialisers and put them into your own code. Add a TextField
property in your wrapper, and in each initialiser, initialise that property by creating a TextField
using the corresponding initialiser.
Here is an example for init(_:text:)
and init(_:value:format)
:
struct CustomTextField<Label: View>: View {
let textField: TextField<Label>
init(_ title: LocalizedStringKey, text: Binding<String>) where Label == Text {
textField = TextField(title, text: text)
}
init<F>(_ title: LocalizedStringKey, value: Binding<F.FormatInput>, format: F)
where F: ParseableFormatStyle, F.FormatOutput == String, Label == Text {
textField = TextField(title, value: value, format: format)
}
var body: some View {
textField
.padding(10)
// ...add your own styling...
}
}
That said, this is quite tedious if you want to have all the combinations of TextField.init
. IMO, using a ViewModifier
like you suggested is the more idiomatic and correct solution.