(So we don't have to use id: .self)
extension ForEach where Data.Element: Hashable, ID == Data.Element, Content: View {
init(values: Data, content: @escaping (Data.Element) -> Content) {
self.init(values, id: \.self, content: content)
}
}
Prefixing a view with an icon, easily...
extension View {
func prefixedWithIcon(named name: String) -> some View {
HStack {
Image(systemName: name)
self
}
}
}
Then, to use...
var body: some View {
Form {
...
TextField("Username", text: $username)
.prefixedWithIcon(named: "person.circle.fill")
TextField("Email", text: $email)
.prefixedWithIcon(named: "envelope.circle.fill")
...
}
}
struct Validation<Value>: ViewModifier {
var value: Value
var validator: (Value) -> Bool
func body(content: Content) -> some View {
// Here we use Group to perform type erasure, to give our
// method a single return type, as applying the 'border'
// modifier causes a different type to be returned:
Group {
if validator(value) {
content.border(Color.green)
} else {
content
}
}
}
}
Then, to use...
TextField("Username", text: $username)
.modifier(Validation(value: username) { name in
name.count > 4
})
.prefixedWithIcon(named: "person.circle.fill")