ios - 带有部分和滑动操作的 SwiftUI 列表一次加载所有行

考虑以下代码示例(您可以下载 here ):

struct Item: Identifiable {
    var id = UUID()
    var name: String
}

struct Row: View {

    var item: Item
    static var counter = 0

    init(item: Item) {
        self.item = item

        Row.counter += 1
        print(Row.counter)
    }

    var body: some View {
        Text(item.name)
    }
}

struct ContentView: View {

    @State var items = (1...1000).map { Item(name: "Item \($0)") }

    var body: some View {
        List {
            ForEach(items) {
                Row(item: $0)
                    .swipeActions(edge: .leading) {
                        Button("Action", action: {})
                    }
            }
        }
    }
}

运行此代码会打印出从 121 的数字,大约是屏幕上可见的行数。

现在,如果我将 ForEach 语句包装在 Section 中,则打印出数字 11000 .因此,没有单元格重用,所有行都被一次加载。

Section {
    ForEach(items) {
        Row(item: $0)
            .swipeActions(edge: .leading) {
                Button("Action", action: {})
            }
    }
}

如果我删除滑动操作,则会打印出数字 118

Section {
    ForEach(items) {
        Row(item: $0)
    }
}

这是已知问题还是我做错了什么?

最佳答案

即使没有滑动操作,我也遇到了这个问题。我使用 .insetGroup 样式为列表创建了一个新的 SectionView,直到 Apple 修复它。缺点是部分页眉和页脚与原始 View 不同。

它已经过测试并适用于 iOS 15 和 16。

struct LazySection<Element, Row: View>: View where Element: Equatable, Element: Identifiable {

    // source: https://medium.com/devtechie/round-specific-corners-in-swiftui-d23ceee08188
    struct RoundedCorner: Shape {
        var radius: CGFloat = .infinity
        var corners: UIRectCorner = .allCorners

        func path(in rect: CGRect) -> Path {
            let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
            return Path(path.cgPath)
        }
    }

    let elements: [Element]
    var header: String?
    var footer: String?
    @ViewBuilder let row: (_ element: Element) -> Row

    var body: some View {

        if let header = header {
            HeaderFooter(header, isHeader: true)
                .textCase(.uppercase)
        }

        if let first = elements.first,
           let last = elements.last {

            if first == last {
                row(first)
                    .listRowBackground(
                        Rectangle()
                            .foregroundColor(Color(uiColor: .secondarySystemGroupedBackground))
                            .clipShape(RoundedCorner(radius: 10))
                    )
            } else {
                row(first)
                    .listRowBackground(
                        Rectangle()
                            .foregroundColor(Color(uiColor: .secondarySystemGroupedBackground))
                            .clipShape(RoundedCorner(radius: 10, corners: [.topLeft, .topRight]))
                    )
                ForEach(elements.dropFirst().dropLast()) { element in
                    row(element)
                }
                row(last)
                    .listRowBackground(
                        Rectangle()
                            .foregroundColor(Color(uiColor: .secondarySystemGroupedBackground))
                            .clipShape(RoundedCorner(radius: 10, corners: [.bottomLeft, .bottomRight]))
                    )
            }
        }

        if let footer = footer {
            HeaderFooter(footer, isHeader: false)
        }
    }

    func HeaderFooter(_ title: String, isHeader: Bool) -> some View {
        VStack(alignment: .leading) {
            if isHeader == true {
                Spacer()
            }
            Text(title)
                .font(.footnote)
            if isHeader == false {
                Spacer()
            }
        }
        .foregroundColor(.init(uiColor: .secondaryLabel))
        .listRowBackground(Color(uiColor: .systemGroupedBackground))
        .listRowSeparator(.hidden)
    }
}

在给定的代码示例中使用它 Item 必须符合 Equatable。

struct Item: Identifiable, Equatable {
    var id = UUID()
    var name: String
}

struct Row: View {

    var item: Item
    static var counter = 0

    init(item: Item) {
        self.item = item

        Row.counter += 1
        print(Row.counter)
    }

    var body: some View {
        Text(item.name)
    }
}

struct ContentView: View {

    @State var items = (1...1000).map { Item(name: "Item \($0)") }

    var body: some View {
        List {
            LazySection(elements: items) { element in
                Row(item: element)
            }
        }
    }
}

https://stackoverflow.com/questions/71806868/

相关文章:

python - 以两种方式遍历列表但无法理解行为

javascript - OpenSea 错误 - 请使用 providerUtils.standa

html - 如何用 CSS 连接大写单词?

node.js - 在 Github 操作中获取错误 : connect ECONNREFUSED

c# - 触发 SelectedIndexChanged 后列表框在视觉上卡住

reactjs - 组件 Prop 中不兼容的函数参数

javascript - 如何为 MUI DataGrid 中的每一行添加一个序列号?

java - 使用 'fib(N) = [Phi^N – phi^N]/Sqrt[5]' 公式计算

javascript - 在 Promise.all 中 react setState

python - 使用 Pandas Align 时,时间序列数据帧返回错误 - valueErro