我创建了一个像素一样的矩形的LazyVGrid。我想用一个延迟的颜色部分或全部,以便在填充期间执行一个simil动画,但性能非常糟糕,我认为它刷新所有的矩形每次更新。
守则
struct Pixel: Identifiable, Hashable {
var id: Int
var isColored: Bool
}
class Model: ObservableObject {
@Published var pixels: [Pixel]
init(totalPixels: Int) {
pixels = (1...totalPixels).map{ Pixel(id: $0, isColored: false)}
}
func pixelsRange(num:Int, clusterDimension:Int) -> [Pixel]{
return Array(pixels[(num-1)*clusterDimension..<clusterDimension*num])
}
func startFillingAllAnimated() {
for idx in pixels.indices {
let addTime = idx
DispatchQueue.main.asyncAfter(deadline: .now() + Double(addTime) * 0.1) {
self.pixels[idx].isColored = true
}
}
}
}
struct TotalView: View {
static var totalPixels = 1280
@StateObject var model = Model(totalPixels: totalPixels)
var clusterDimension = 16
static let bigSpacing:CGFloat = 2
let bigColumns = [
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing),
GridItem(.flexible(), spacing: bigSpacing)
]
@State var numToBeColored: Int = 8
var body: some View {
VStack {
Button("start") {
model.startFillingAllAnimated()
}
ScrollView {
LazyVGrid(columns: bigColumns, alignment: .center, spacing: 2){
ForEach(0..<TotalView.totalPixels/clusterDimension, id: \.self) { num in
ClusterView(pixels: $model.pixels, clusterNumber: num, clusterDimension: clusterDimension, color: .red)
}
}
}
.padding(.horizontal, 4)
}
}
}
struct ClusterView: View {
@Binding var pixels: [Pixel]
let clusterNumber: Int
let clusterDimension: Int
let color: Color
static let spacing:CGFloat = 2
static let boxDimension:CGFloat = 9
let columns = [
GridItem(.fixed(boxDimension), spacing: spacing),
GridItem(.fixed(boxDimension), spacing: spacing),
GridItem(.fixed(boxDimension), spacing: spacing),
GridItem(.fixed(boxDimension), spacing: spacing)
]
var body: some View {
LazyVGrid(columns: columns, alignment: .center, spacing: ClusterView.spacing) {
ForEach(pixels[clusterNumber*clusterDimension..<clusterDimension*(clusterNumber+1)], id: \.self) { pixel in
Rectangle()
.aspectRatio(1.0, contentMode: .fit)
.border(color)
.foregroundColor(pixel.isColored ? color:.clear)
}
}
}
}
struct TotalView_Previews: PreviewProvider {
static var previews: some View {
TotalView()
}
}
试着用这个来改变你的方法:
func startFillingAllAnimated() {
DispatchQueue.global().async {
for idx in self.pixels.indices {
Thread.sleep(forTimeInterval: 0.03)
DispatchQueue.main.async {
self.pixels[idx].isColored = true
}
}
}
}