[英]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: {})
}
}
}
}
}
運行此代碼會打印出數字1
到21
,因此大約是屏幕上可見的行數。
現在,如果我將ForEach
語句包裝在Section
中,則會打印出數字1
到1000
。 因此,沒有單元重用,所有行都一次加載。
Section {
ForEach(items) {
Row(item: $0)
.swipeActions(edge: .leading) {
Button("Action", action: {})
}
}
}
如果我取消滑動操作,則會打印出數字1
到18
。
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.