How can one change the FocusState of a SwiftUI app with TextFields in different child views without having View refresh which causes a bounce effect?(如何才能在不同子视图中使用TextFields更改SwiftUI应用程序的FocusState,而不需要刷新视图,从而导致反弹效果?) - IT屋-程序员软件开发
问题描述
我的问题:我希望用户能够在不弹出视图的情况下从TextField转到TextField,如下面的gif所示。
我的用例:我在多个子视图中有多个TextField和TextEditor。这些TextField是动态生成的,所以我希望FocusState是一个单独的关注点。
我在下面制作了一个示例gif和代码示例。
请查看,如有任何建议,欢迎光临。
按照评论中的建议,我做了一些更改,但对反弹没有影响:
- Using Identfiable does not change the bounce
- A single observed object or multiple and a view model does not change the bounce
我认为这来自状态更改刷新。如果不是刷新导致了反弹(正如用户在评论中建议的那样),那么什么才是呢?是否有办法在使用FocusState时停止此退回?
要重现:新建iOS app Xcode项目,并将内容视图替换为下面的代码正文。当用户从一个文本字段转到下一个文本字段时,它似乎会刷新视图,导致整个屏幕反弹。
代码示例
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)
}
}
}
推荐答案
在经历了很多次之后,我突然意识到,当使用FocusState
时,您确实应该处于ScrollView
、Form
或其他类型的贪婪视图中。即使GeometryReader
也可以。其中任何一项都将删除退回。
struct MyObject: Identifiable, Equatable {
public let id = UUID()
public var name: String
public var value: String
}
class MyObjViewModel: ObservableObject {
@Published var myObjects: [MyObject]
init(_ objects: [MyObject]) {
myObjects = objects
}
}
struct ContentView: View {
@StateObject var viewModel = MyObjViewModel([
MyObject(name: "aa", value: "1"),
MyObject(name: "bb", value: "2"),
MyObject(name: "cc", value: "3"),
MyObject(name: "dd", value: "4")
])
@State var focus: UUID?
var body: some View {
VStack {
Form {
Text("Header")
ForEach($viewModel.myObjects) { $obj in
FocusField(object: $obj, focus: $focus, nextFocus: {
guard let index = viewModel.myObjects.map( { $0.id }).firstIndex(of: obj.id) else {
return
}
focus = viewModel.myObjects.indices.contains(index + 1) ? viewModel.myObjects[index + 1].id : viewModel.myObjects[0].id
})
}
Text("Footer")
}
}
}
}
struct FocusField: View {
@Binding var object: MyObject
@Binding var focus: UUID?
var nextFocus: () -> Void
@FocusState var isFocused: UUID?
var body: some View {
TextField("Test", text: $object.value)
.onChange(of: focus, perform: { newValue in
self.isFocused = newValue
})
.focused(self.$isFocused, equals: object.id)
.onSubmit {
self.nextFocus()
}
}
}
编辑:
另外,以您所做的方式在结构中设置id
也不是一个好主意。ID应该是唯一的。它在这里可以工作,但最佳实践是UUID
。
第二次编辑:已收紧代码。
这篇关于如何才能在不同子视图中使用TextFields更改SwiftUI应用程序的FocusState,而不需要刷新视图,从而导致反弹效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何才能在不同子视图中使用TextFields更改SwiftUI应用程序的FocusState,而不需要刷新视图,从而导致反弹效果?
基础教程推荐
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01