I have list of custom fields in a custom form view. The form view is loaded in the content view, which will inform the form view to move to the next field, when the user taps on "Next" button.
The question is how the form view will make the next custom field focused, when the moveToNextField()
function called?
This is how my form looks like
Here’s the code for the custom field
enum InputFieldType {
case text, number, dropdown
}
struct CustomField: View {
let tag: Int
let type: InputFieldType
let title: String
var dropdownItems: Array<String> = []
var placeholder: String = ""
@State var text: String = ""
@State var enabled: Bool = true
@FocusState private var focusField: Bool
private let dropdownImage = Image(systemName: "chevron.down")
@State private var showDropdown: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 8.0) {
Text(title)
.foregroundColor(.gray)
.frame(alignment: .leading)
ZStack(alignment: .leading) {
// The placeholder view
Text(placeholder).foregroundColor( enabled ? .gray.opacity(0.3) : .gray.opacity(0.5))
.opacity(text.isEmpty ? 1 : 0)
.padding(.horizontal, 8)
// Text field
TextField("", text: $text)
.disabled(!enabled)
.frame(height: 44)
.textInputAutocapitalization(.sentences)
.foregroundColor(.white)
.padding(.horizontal, 8)
.keyboardType( type == .number ? .decimalPad : .default)
.focused($focusField)
}.background(Color.red.opacity(0.1))
.cornerRadius(5)
}
}
}
Here’s the code for the form view
struct FormView: View {
func moveToNextField() -> Bool {
return false
}
var body: some View {
VStack {
ScrollView(.vertical) {
VStack(spacing: 24) {
CustomField(tag: 0, type: .text, title: "First name", placeholder: "John", text: "", enabled: false)
CustomField(tag: 1, type: .text, title: "Surname", placeholder: "Mike", text: "")
CustomField(tag: 2, type: .text, title: "Gender (Optional)", placeholder: "Optional", text: "")
CustomField(tag: 3, type: .dropdown, title: "Body type", dropdownItems: ["1", "2", "3"], placeholder: "Skinny", text: "")
CustomField(tag: 4, type: .number, title: "Year of birth", placeholder: "2000", text: "")
Spacer()
}
}
}.onTapGesture {
}
.background(Color.clear)
.padding(.horizontal, 16)
}
}
The code in the Content view
struct ContentView: View {
let formView = FormView()
var body: some View {
VStack {
Spacer(minLength: 30)
formView
.padding(.vertical)
Button("Next") {
if formView.moveToNextField() {
return
}
// validate the form
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .center)
.background(Color.secondary)
.cornerRadius(5)
.padding(.horizontal, 16)
Spacer(minLength: 20)
}.background(Color.primary)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().preferredColorScheme(.dark)
}
}
2
Answers
I found my issue, I was using
@State
to track the current focused field, which is getting reset every time the view changes.So I had to us
@ObservableObject
with@Published
property.Here is my final working code.
Custom field
Form view
Content view
Declare a FocusState var for each field. Then turn on the state of the field where you want to move the focus.