我需要建立一个文本字段列表,其中每个字段都与焦点id关联,以便在收到焦点时自动滚动到这样的文本字段.实际上,真正的应用程序要复杂一些,它还包括文本编辑器和许多其他控件.

现在,我发现如果我的视图定义了@Environment(\.dismiss) private var dismiss,那么列表在手动滚动期间一直在重建.如果我只是注释掉第@Environment(\.dismiss) private var dismiss行,那么当我滚动时就不会重建列表.显然,当用户单击某个按钮时,我希望能够关闭我的视图.在真正的应用程序中,情况甚至更糟:在滚动过程中,所有内容都滞后,我无法平滑滚动.我的 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时,在手动来回滚动期间重建列表,而当未定义Disclose时,不会发生同样的情况?
  • 有什么解决方法吗:当焦点改变时,我需要能够使用ScrollProxyReader来聚焦任何文本字段,并且我需要能够关闭视图,但同时我需要避免在滚动期间不断重建列表,因为它会降低应用程序性能,滚动变得参差不齐...

P、 当定义解除并滚动列表时,美国演示应用程序不断输出"body is rebuilding",但如果任何文本字段手动获得焦点,则即使解除仍定义,也不再打印"body is rebuilding".

推荐答案

  1. 我可以做一个假设,但那实际上是一个猜测(基于经验、观察等).事实上,所有WHYs个问题,比如"为什么会发生这个错误……",都应该在https://developer.apple.com/forums/个问题上提问(那里有苹果的工程师),或者向https://developer.apple.com/bug-reporting/报告

  2. 一种解决方案是将dismiss个从属零件分离到专用视图中,以便将其从父实体中隐藏(因此不会影响它)

    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

Ios相关问答推荐

在金属中设置纹理的UV坐标以编程方式变形纹理

如何将Safari调试器附加到Turbo-iOS原生应用中的模拟器

有没有办法将滚动视图RTL(阿拉伯语)与Ltr动画一起使用?

许多文本字段的性能问题

在 SwiftUI 中以编程方式插入内嵌图像

如何结合`@dynamicMemberLookup`和`ExpressibleByStringInterpolation`来实现方法链?

在iOS中使用Swift,即时更改应用语言后,立即改变外观会出现问题

部分保留 UITextField 中的占位符

无法在 CollectionView 中禁用部分弹跳 - 组合布局

iOS - 判断开发者模式是否开启 (Swift)

SwiftUI 中的偏移量和按钮有问题吗?

SwiftUI 文本字段代理绑定代码忽略空格不起作用?

TextField 重复输入 SwiftUI

Xcode 14 弃用了位码 - 但为什么呢?

iOS:应用程序在安装应用程序时未征求用户许可.每次都获得 kCLAuthorizationStatusNotDetermined - Objective-c & Swift

为信用卡输入格式化 UITextField,例如 (xxxx xxxx xxxx xxxx)

以编程方式创建按钮并设置背景图像

如果我的分发证书过期会怎样?

ARC - __unsafe_unretained 的含义?

zoom UIButton 动画 - Swift