代码之家  ›  专栏  ›  技术社区  ›  soleil

不要重新绘制某些视图结构

  •  1
  • soleil  · 技术社区  · 10 月前

    考虑以下代码,该代码在屏幕上绘制一个由随机颜色的矩形组成的网格,其中一个圆圈通过响应计时器向右移动:

    struct ContentView: View {
        let width: CGFloat = 400
        let height: CGFloat = 400
        let spacing: CGFloat = 8.0
        let numRows = 20
        var tileSize: CGFloat {
            height / 5
        }
        
        let timer = Timer.publish(every: 3.0, on: .main, in: .common).autoconnect()
        @State private var circleX: CGFloat = 0.0
        
        var body: some View {
            let numColumns = Int(tileSize)
            
            ZStack {
                Grid(horizontalSpacing: spacing, verticalSpacing: spacing) {
                    ForEach(0..<numRows, id: \.self) { rowIndex in
                        GridRow {
                            ForEach(0..<numColumns, id: \.self) { colIndex in
                                Rectangle()
                                    .fill(Color.random)
                                    .frame(width: tileSize, height: tileSize)
                            }
                        }
                    }
                }
                
                
                Circle()
                    .fill(.red)
                    .frame(width:50, height: 50)
                    .offset(x: circleX, y: 0)
                    
            }
            .onReceive(timer) { time in
                circleX += 10
            }
            
        }
    }
    
    #Preview {
        ContentView()
    }
    
    extension Color {
        static var random: Color {
            Color(red: .random(in: 0...1),
                  green: .random(in: 0...1),
                  blue: .random(in: 0...1))
        }
    }
    

    问题是,我不希望矩形改变颜色。我想让它们从一个随机的颜色开始,并保持这种状态。目前发生的情况是,每次定时器启动时,矩形都会得到一种新的颜色。整个视图正在重新渲染,尽管我只是更改了应用于圆的特性。我试着把 .onReceive 修改器,但这没有帮助。

    1 回复  |  直到 10 月前
        1
  •  1
  •   Sweeper    10 月前

    为随机着色的矩形提取一个单独的视图。在那里,您可以初始化 @State 转换为随机颜色。

    struct RandomlyColoredRectangle: View {
        @State var color = Color.random
        
        var body: some View {
            Rectangle()
                .fill(color)
        }
    }
    

    这是因为的初始化程序 状态 属性在视图的每个生命周期中仅一次。


    或者,符合 Equatable :

    struct RandomlyColoredRectangle: View, Equatable {
        // since this struct has no properties, the automatically generated '=='
        // always returns true
    
        var body: some View {
            Rectangle()
                .fill(Color.random)
        }
    }
    

    和使用 RandomlyColoredRectangle 这样地:

    RandomlyColoredRectangle().equatable()
    

    equatable() 使视图仅在新的 随机彩色矩形 与旧的不平等 随机彩色矩形 。自从我们 == 始终返回true,视图永远不会更新。

    推荐文章