Hello everyone. I'm building a simple Form in a Multiplatform App with SwiftUI. Originally I had something like this.
import SwiftUI
struct OnboardingForm: View {
@State var firstName: String = ""
@State var lastName: String = ""
@State var email: String = ""
@State var job: String = ""
@State var role: String = ""
var body: some View {
Form {
TextField("First Name", text: $firstName, prompt: Text("Required"))
TextField("Last Name", text: $lastName, prompt: Text("Required"))
TextField("Email", text: $email, prompt: Text("Required"))
TextField("Job", text: $job, prompt: Text("Required"))
TextField("Role", text: $role, prompt: Text("Required"))
}
}
}
#Preview {
OnboardingForm()
}
In macOS it looks ok but then in iOS it looks like this:
and it's impossible to know what each field is for if all the prompts are the same. I tried adding LabeledContent
around each text field and that solves it for iOS but then on macOS it looks like this:
The labels are shown twice and the columns are out of alignment. I think I could get around it by doing something like this:
#if os(iOS)
LabeledContent {
TextField("First Name", text: $firstName, prompt: Text("Required"))
} label: {
Text("First Name")
}
#else
TextField("First Name", text: $firstName, prompt: Text("Required"))
#endif
but it seems to me like reinventing the wheel. Is there a "correct" way to declare TextFields with labels that works for both iOS and macOS?
@alexortizl You can use a LabeledContent
and create a customLabeledContentStyle
that allows you customize the appearance.
struct CustomTextField: View {
let label: String
let prompt: String
@Binding var text: String
var body: some View {
LabeledContent(label) {
TextField(label, text: $text, prompt: Text(prompt))
}
.labeledContentStyle(.customStyle)
}
}
struct CustomLabeledContentStyle: LabeledContentStyle {
func makeBody(configuration: Configuration) -> some View {
#if os(macOS)
configuration.content
#else
HStack {
configuration.label
configuration.content
}
#endif
}
}
extension LabeledContentStyle where Self == CustomLabeledContentStyle {
static var customStyle: CustomLabeledContentStyle { CustomLabeledContentStyle() }
}
Form {
CustomTextField(label: "First Name", prompt: "Required", text: $firstName)
CustomTextField(label: "Last Name", prompt: "Required", text: $lastName)
CustomTextField(label: "Email", prompt: "Required", text: $email)
CustomTextField(label: "Job", prompt: "Required", text: $job)
CustomTextField(label: "Role", prompt: "Required", text: $role)
}