簡體   English   中英

SwiftUI 帶有部分和滑動操作的列表一次加載所有行

[英]SwiftUI List with Section and Swipe Actions loads all rows at once

考慮以下代碼示例(您可以在此處下載):

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 修復它。 缺點是 header 和頁腳部分與原始視圖不相等。

它已經過測試並與 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(.white)
                            .clipShape(RoundedCorner(radius: 10))
                    )
            } else {
                row(first)
                    .listRowBackground(
                        Rectangle()
                            .foregroundColor(.white)
                            .clipShape(RoundedCorner(radius: 10, corners: [.topLeft, .topRight]))
                    )
                ForEach(elements.dropFirst().dropLast()) { element in
                    row(element)
                }
                row(last)
                    .listRowBackground(
                        Rectangle()
                            .foregroundColor(.white)
                            .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)
    }
}

將它與您給定的代碼示例項目一起使用必須符合 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)
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM