ios - @Environment dismiss 的存在导致列表在滚动时不断重建其内容

我需要构建一个 TextFields 列表,其中每个字段都与焦点 ID 相关联,以便我可以在接收到焦点时自动滚动到这样的文本字段。实际上,真正的应用程序要复杂一些,其中还包括 TextEditors 和许多其他控件。

现在,我发现如果我的 View 定义了 @Environment(\.dismiss) private var dismiss,那么在手动滚动期间列表一直在重建。如果我只是注释掉 @Environment(\.dismiss) private var dismiss 行,那么在我滚动时不会重建列表。显然,我希望能够在用户单击某个按钮时关闭我的 View 。在真正的应用程序中,情况更糟:在滚动过程中一切都滞后,我无法平滑滚动。我的 list 并不大,只有 10 件左右。

这是一个演示示例:

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink {
                DismissListView()
            } label: {
                Text("Go to see the list")
            }
        }
    }
}

struct DismissListView: View {
    @Environment(\.dismiss) private var dismiss
    
    enum Field: Hashable {
        case line(Int)
    }
    
    @FocusState private var focus: Field?
    @State private var text: String = ""
    
    var body: some View {
        ScrollViewReader { proxy in
            List {
                let _ = print("body is rebuilding")
                
                Button("Dismiss me") {
                    dismiss()
                }
                
                Section("Section") {
                    ForEach((1...100), id: \.self) {num in
                        TextField("text", text: $text)
                            .id(Field.line(num))
                            .focused($focus, equals: .line(num))
                    }
                }
            }
            .listStyle(.insetGrouped)
            .onChange(of: focus) {_ in
                withAnimation {
                    proxy.scrollTo(focus, anchor: .center)
                }
            }
        }
    }
}

问题是:

  • 为什么在定义了 @Environment(\.dismiss) private var dismiss 时手动来回滚动列表,而在未定义 dismiss 时不会发生同样的情况?
  • 是否有任何解决方法:我需要能够在焦点更改时使用 ScrollProxyReader 来聚焦任何文本字段,并且我需要能够关闭 View ,但同时我需要避免不断重建滚动过程中的列表,因为它会降低应用程序性能并且滚动变得参差不齐...

附言当定义了 dismiss 并滚动列表时,演示应用程序不断输出“body is rebuilding”,但如果任何文本字段手动获得焦点,则即使仍然定义了 dismiss,也不会再打印“body is rebuilding”。

最佳答案

  1. 我可以做出一个假设,但这实际上只是一个猜测(基于经验、观察等)。事实上,所有 WHY 都应该在 https://developer.apple.com/forums/ 上询问,例如“为什么会发生这个 sh...(bug)” (那里有苹果的工程师)或者举报给https://developer.apple.com/bug-reporting/

  2. 一个解决方案是将 dismiss 依赖部分分离到专用 View 中,以便将其从父主体中隐藏(因此不影响它)

    struct DismissView: View {
        // visible only for this view !!
        @Environment(\.dismiss) private var dismiss

        var body: some View {
            Button("Dismiss me") {
                // affects current context, so it does not matter
                // in which sub-view is called
                dismiss()           
            }
        }
    }

    var body: some View {
        ScrollViewReader { proxy in
            List {
                let _ = print("body is rebuilding")
                DismissView()   // << here !!

    // ... other code

https://stackoverflow.com/questions/72919861/

相关文章:

sass - 当我在汇总中使用 scss 时出现意外字符 '@'(请注意,您需要插件才能导入非 Ja

mermaid - 使用渲染函数时节点上的事件不调用函数

reactjs - 在进行客户端查询时,我应该如何为 Github graphql API 提供身份

python - 同时从两列中减去值( Pandas , python )

reactjs - eslint 无法加载配置 "react-app"以从中扩展

github-pages - 自定义 GitHub 页面部署说明

windows - 为什么 powershell 说 cl.exe 不被识别?

Python 修补类 - 方法 return_value 返回 MagicMock

python - 为什么这两种计算总和的方法会产生不同的运行时间

python - 名称错误 : name 'scipy' is not defined when t