如何避免在状态变量更新时呈现不相关的视图

时间:2020-07-28 00:56:55

标签: swiftui

我创建了两个三角形,单击时要分别为每个三角形上色。 @State变量是在PaintView内部创建的,该变量创建一个包含单个路径的Shape。

triangles

我看到的行为是,每当我单击一个形状时,它都会重新创建两个形状,而不是仅创建一个我正在点击的形状(我可以根据print观察到这一点已添加到BuildShape)。

现在,我的理解是,每当状态发生变化时,SwiftUI都会重新渲染包含该@State及其子视图的整个View,但是由于我的形状处于不相关的不同视图中,为什么SwiftUI重新渲染它们两个?

此图显示了视图如何相互关联:

views

例如,当我点击底部三角形时,会发生以下情况:

  1. 当我第一次点击底部的三角形时,SwiftUI会重新创建底部的三角形两次,并重新创建顶部的三角形一次
Path: 0 0 m 100 100 l 200 0 l
Path: 100 100 m 0 200 l 200 200 l
Path: 100 100 m 0 200 l 200 200 l
  1. 当我再次点击底部三角形(以及其他次数)时,SwiftUI会重新创建底部三角形一次,并重新创建顶部三角形一次
Path: 0 0 m 100 100 l 200 0 l
Path: 100 100 m 0 200 l 200 200 l

这是我正在使用的代码:

import SwiftUI
import UIKit


struct BuildShape: Shape {
    let path: Path
    
    func path(in rect: CGRect) -> Path {
        print("Path:", path)
        return path
    }
}

struct PaintView: View {
    let path: Path
    @State var color = Color.black
    
    var body: some View {
        BuildShape(path: path)
            .fill(self.color)
            .onTapGesture(count: 1) {
                self.color = Color.blue
        }
    }
}


struct DrawView: View {
    var triangle1Path: Path {
        var path = Path()
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: 100, y: 100))
        path.addLine(to: CGPoint(x: 200, y: 0))
        return path
    }
    var triangle2Path: Path {
        var path = Path()
        path.move(to: CGPoint(x: 100, y: 100))
        path.addLine(to: CGPoint(x: 0, y: 200))
        path.addLine(to: CGPoint(x: 200, y: 200))
        return path
    }
    
    var body: some View {
        ZStack {
            PaintView(path: triangle1Path)
            PaintView(path: triangle2Path)
        }
    }
}

1 个答案:

答案 0 :(得分:0)

包含三角形的视图是重叠的(因为它们在ZStack中),并且由于默认情况下视图不是不透明的,因此更改一个视图会影响结果外观,因此请在ZStack中全部重绘。

ZStack {
    PaintView(path: triangle1Path)
    PaintView(path: triangle2Path)
}

demo1

例如将它们放入VStack中,您将看到只有重击才能重绘,因为渲染引擎现在知道视图是独立的。

VStack {
    PaintView(path: triangle1Path)
    PaintView(path: triangle2Path)
}

demo2