SwiftUI 文本,使用 @State 属性更改文本导致整个视图重新渲染

问题描述 投票:0回答:1

我面临着一个非常奇怪的问题,我不知道如何解决这个问题。

Text
中有一个
TabView
VStack
。现在的问题是,当我尝试根据某些
Text
属性设置
@State
的文本时。 SwiftUI 刷新所有视图,包括在
TabView
中添加的页面也被重新创建。我正在分享一个示例代码片段,这将有助于解释。

我的主要观点:

struct TestingView: View {
    
    @State private var someText: String = "Hello"
    @State private var page: Int = 0
    
    var body: some View {
        VStack {
            Text(someText + " \(page)")
            
            TabView(selection: $page) {
                ViewOne()
                    .tag(0)
                
                ViewTwo()
                    .tag(1)
                
                ViewThree()
                    .tag(2)
            }
            .tabViewStyle(.page(indexDisplayMode: .never))
        }
    }
}

选项卡视图页面:

struct ViewOne: View {
    
    init() {
        print("View one init")
    }
    
    var body: some View {
        Text("View one")
    }
}

struct ViewTwo: View {
    
    init() {
        print("View two init")
    }
    
    var body: some View {
        Text("View two")
    }
}

struct ViewThree: View {
    
    init() {
        print("View three init")
    }
    
    var body: some View {
        Text("View three")
    }
}

现在,如果你在

TabView
上滑动,它会导致
$page
发生变化,最终影响
Text
。当
Text
内的文本更改时,所有视图都会重新创建。

我的问题:

  • 是什么导致 SwiftUI 内部出现这样的行为?
  • 如何防止无意重绘视图?

我尝试为

Text
制作单独的视图并绑定
TestingView
中的值,但结果是相同的。

swiftui swiftui-tabview
1个回答
0
投票

SwiftUI 的工作原理如下:

每当视图的状态发生变化时,SwiftUI 就会将此更改安排为主线程上的内部更新任务。 状态更改由对 State 属性、Environment 变量和对象的更改、objectWillChange 发布者或对 Observable 对象的非私有属性更改来触发。

布局任务首先创建一个新的视图实例,记住视图在SwiftUI中是值类型,然后比较状态改变是否需要新的布局过程。

如果需要新的布局过程,则旧视图实例将被新视图实例替换,并检索新实例的 body 属性。

在您的示例中,通过更改

TestingView
状态属性来更改
page
的状态。这会导致在下一个布局阶段触发新的布局过程,即在
body
上调用
TestingView
属性。 这也会调用
init
ViewOne
ViewTwo
ViewThree
方法,因为这就是您的
body
实现的作用。

然而,SwiftUI 通过比较发现这些子视图没有改变,因此不会调用它们的布局方法。结果,不必要生成的视图被丢弃。

以下是您应该了解并牢记的有关 SwiftUI 的一些基本事项:

  • 视图的 init 方法可以被频繁调用,并不意味着视图也会被重新布局。
  • 视图的 init 方法应尽可能轻量级,并且不得更改任何状态变量或状态对象。
  • 如果你想调试视图的布局过程被调用的原因,你可以在视图主体中插入以下代码行:
let _ = Self._printChanges()
© www.soinside.com 2019 - 2024. All rights reserved.