My Problem: I want the user to be able to go from Textfield to TextField without the view bouncing as shown in the gif below.
My Use Case: I have multiple TextFields and TextEditors in multiple child views. These TextFields are generated dynamically so I want the FocusState to be a separate concern.
I made an example gif and code sample below.
Please check it out, any suggestions appreciated.
As suggested in the comments I made some changes with no effect to the bounce:
- Using Identfiable does not change the bounce
- A single observed object or multiple and a view model does not change the bounce
I think this is from the state change refresh. If it's not the refresh causing the bounce(as the user suggests in the comments) what is? Is there a way to stop this bounce while using FocusState?
To Reproduce: Create a new iOS app xcode project and replace the content view with this code body below. It seems to refresh the view when the user goes from one textfield to the next textfield causing a bounce of the whole screen.
Code Example
import SwiftUI
struct MyObject: Identifiable, Equatable {
var id: String
public var value: String
init(name: String, value: String) {
self.id = name
self.value = value
}
}
struct ContentView: View {
@State var myObjects: [MyObject] = [
MyObject(name: "aa", value: "1"),
MyObject(name: "bb", value: "2"),
MyObject(name: "cc", value: "3"),
MyObject(name: "dd", value: "4")
]
@State var focus: MyObject?
var body: some View {
VStack {
Text("Header")
ForEach(self.myObjects) { obj in
Divider()
FocusField(displayObject: obj, focus: $focus, nextFocus: {
guard let index = self.myObjects.firstIndex(of: $0) else {
return
}
self.focus = myObjects.indices.contains(index + 1) ? myObjects[index + 1] : nil
})
}
Divider()
Text("Footer")
}
}
}
struct FocusField: View {
@State var displayObject: MyObject
@FocusState var isFocused: Bool
@Binding var focus: MyObject?
var nextFocus: (MyObject) -> Void
var body: some View {
TextField("Test", text: $displayObject.value)
.onChange(of: focus, perform: { newValue in
self.isFocused = newValue == displayObject
})
.focused(self.$isFocused)
.submitLabel(.next)
.onSubmit {
self.nextFocus(displayObject)
}
}
}