【发布时间】:2020-11-25 17:40:35
【问题描述】:
我有一种情况,我正在使用LazyVGrid 显示来自用户照片库的图像。网格有多个部分,每个部分包含要显示的图像数组,以及关于该部分的一些元数据。
我遇到的问题是,每次用户单击一个磁贴时,会在相应的图像中切换markedForDeletion,网格中的所有视图(可见)都会重绘。这并不理想,因为在示例代码的“真实”版本中,重绘每个 Tile 会带来真正的惩罚,因为必须检索和渲染图像。
我尝试让Tile 符合Equatable,然后使用.equatable() 修饰符通知SwiftUI 不应重绘Tile,但这不起作用。
在Section 之外放置另一个.onAppear 暗示每次发生任何变化时都会重绘整个部分,但我不确定如何构造我的代码,以便将重绘昂贵的Tiles 的影响降至最低。
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel: ViewModel = ViewModel()
let columns = [
GridItem(.flexible(minimum: 40), spacing: 0),
GridItem(.flexible(minimum: 40), spacing: 0),
]
var body: some View {
GeometryReader { gr in
ScrollView {
LazyVGrid(columns: columns) {
ForEach(viewModel.imageSections.indices, id: \.self) { imageSection in
Section(header: Text("Section!")) {
ForEach(viewModel.imageSections[imageSection].images.indices, id: \.self) { imageIndex in
Tile(image: viewModel.imageSections[imageSection].images[imageIndex])
.equatable()
.onTapGesture {
viewModel.imageSections[imageSection].images[imageIndex].markedForDeletion.toggle()
}
.overlay(Color.blue.opacity(viewModel.imageSections[imageSection].images[imageIndex].markedForDeletion ? 0.2 : 0))
.id(UUID())
}
}
}
}
}
}
}
}
struct Image {
var id: String = UUID().uuidString
var someData: String
var markedForDeletion: Bool = false
}
struct ImageSection {
var id: String = UUID().uuidString
var images: [Image]
}
class ViewModel: ObservableObject {
@Published var imageSections: [ImageSection] = generateFakeData(numSections: 10, numImages: 10)
}
func generateFakeData(numSections: Int, numImages: Int) -> [ImageSection] {
var sectionsToReturn: [ImageSection] = []
for _ in 0 ..< numSections {
var imageArray: [Image] = []
for i in 0 ..< numImages {
imageArray.append(Image(someData: "Data \(i)"))
}
sectionsToReturn.append(ImageSection(images: imageArray))
}
return sectionsToReturn
}
struct Tile: View, Equatable {
static func == (lhs: Tile, rhs: Tile) -> Bool {
return lhs.image.id == rhs.image.id
}
var image: Image
var body: some View {
Text(image.someData)
.background(RoundedRectangle(cornerRadius: 20).fill(Color.blue))
.onAppear(perform: {
NSLog("Appeared - \(image.id)")
})
}
}
【问题讨论】: