带有 @FocusState 和焦点更改处理的 SwiftUI 列表

2024-02-17

我想用一个List, @FocusState跟踪焦点,以及.onChanged(of: focus)确保当前聚焦的字段可见ScrollViewReader。问题是:当一切都设置在一起时List在滚动过程中不断重建,使得滚动不那么平滑。

我发现List当我附加时滚动重建.onChanged(of: focus)。如果我更换,问题就消失了List with ScrollView,但我喜欢的外观List,我需要部分支持,并且我需要编辑功能(例如删除、移动项目),所以我需要坚持List view.

I used Self._printChanges()为了看看是什么让主体在滚动时重建自身,输出如下:

ContentView: _focus changed.
ContentView: _focus changed.
ContentView: _focus changed.
ContentView: _focus changed.
...

附在上面的封条上没有打印任何内容.onChanged(of: focus)。下面是简化的示例,在此示例中滚动的平滑度不是问题,但是,一旦列表内容或多或少复杂,平滑滚动就会消失,这实际上是由于.onChanged(of: focus) :(

问题:是否有机会监听焦点变化而不引起列表在滚动时重建自身?

struct ContentView: View {
    enum Field: Hashable {
        case fieldId(Int)
    }
    
    @FocusState var focus: Field?
    @State var text: String = ""
    
    var body: some View {
        List {
            let _ = Self._printChanges()
            ForEach(0..<100) {
                TextField("Enter the text for \($0)", text: $text)
                    .id(Field.fieldId($0))
                    .focused($focus, equals: .fieldId($0))
            }
        }
        .onChange(of: focus) { _ in
            print("Not printed unless focused manually")
        }
    }
}

我建议考虑将列表行内容分离到独立视图中,并使用诸如焦点“选择”方法之类的方法。拥有FocusState每行的内部可防止父视图进行不必要的更新(我认为类似于预“设置”)。

使用 Xcode 13.4 / iOS 15.5 进行测试

struct ContentView: View {

    enum Field: Hashable {
        case fieldId(Int)
    }

    @State private var inFocus: Field?

    var body: some View {
        List {
            let _ = Self._printChanges()
            ForEach(0..<100, id: \.self) {
                ExtractedView(i: $0, inFocus: $inFocus)
            }
        }
        .onChange(of: inFocus) { _ in
            print("Not printed unless focused manually")
        }
    }

    struct ExtractedView: View {
        let i: Int
        @Binding var inFocus: Field?

        @State private var text: String = ""
        @FocusState private var focus: Bool     // << internal !!

        var body: some View {
            TextField("Enter the text for \(i)", text: $text)
                .focused($focus)
                .id(Field.fieldId(i))
                .onChange(of: focus) { _ in
                    inFocus = .fieldId(i)     // << report selection outside
                }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带有 @FocusState 和焦点更改处理的 SwiftUI 列表 的相关文章

随机推荐