【问题标题】:SwiftUI: prevent View from refreshing when presenting a sheetSwiftUI:在呈现工作表时防止视图刷新
【发布时间】:2020-05-23 12:02:18
【问题描述】:

我注意到 SwiftUI 在添加 sheetmodifier 时会完全刷新视图。

假设我有一个显示随机数的视图。我希望这个值是独立的并且不连接到工作表逻辑(每次我打开/关闭工作表时都不会改变),但是每次显示/关闭工作表的文本都在变化

它应该这样工作吗? @Sate的主要观点是只更新连接的视图而不是所有堆栈,我错了吗? 在呈现模式时,如何防止我的视图自行刷新?

struct ContentView: View {

    @State var active = false

    var body: some View {
        VStack {
            Text("Random text: \(Int.random(in: 0...100))")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

附: ContentView 仅调用 onAppear()/onDisappear()init()

【问题讨论】:

  • 是的,这是预期的行为。 View 是结构体,值类型,如果它的任何部分改变了,那么整个值就改变了。
  • @Asperi,我是否理解正确,如果它的任何部分发生了变化,那么整个值都会发生变化 仅因为 @State 属性而起作用。它与经典(不是 SwiftUI)swift 无关

标签: ios swift swiftui


【解决方案1】:

它需要制作独立的独立于条件的视图来实现你想要的行为,如下所示

struct RandomView: View {
    var body: some View {
        Text("Random text: \(Int.random(in: 0...100))")
    }
}

struct ContentView: View {

    @State var active = false

    var body: some View {
        VStack {
            RandomView()

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

在这种情况下,RandomView 不会重建,因为它不依赖于 active 状态。

【讨论】:

  • 像往常一样,Asperi 是正确的。本文给出了一些额外的视图相互依赖的清晰示例,以及如何将它们分解:medium.com/flawless-app-stories/…
  • 只是补充一点,对于更复杂的用例,在带有 .equatable() 修饰符的 SwiftUI 视图上使用 Equatable 协议。
【解决方案2】:

阿斯佩里伤心:

视图是结构,值类型,如果它的任何部分改变了,那么整个 值改变了

他是绝对正确的!但是为此我们有状态属性。重新创建视图时,状态的值不会改变。

这应该可以正常工作

struct ContentView: View {

    @State var active = false
    @State var number = Int.random(in: 0 ... 100)
    var body: some View {
        VStack {
            Text("Random text: \(number)")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

有什么优势?对于简单的事情,状态/绑定是最好的解决方案,毫无疑问。

import SwiftUI

struct SheetView: View {
    @Binding var randomnumber: Int
    var body: some View {
        Button(action: {
            self.randomnumber = Int.random(in: 0 ... 100)
        }) {
            Text("Generate new random number")
        }
    }
}
struct ContentView: View {

    @State var active = false
    @State var number = Int.random(in: 0 ... 100)
    var body: some View {
        VStack {
            Text("Random text: \(number)")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            SheetView(randomnumber: self.$number)
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

现在您可以在生成或不生成新随机数的情况下关闭工作表。不需要外部模型...

【讨论】:

  • 是的,你说的完全正确,但是这个问题稍微简化了一点。在实际项目中,我有以 @State 对象作为数据源的自定义视图行列表。我的问题是多次运行init() 方法。数据源没有改变,但我不需要在每次打开/关闭工作表时重新初始化单元格,因为我有一些逻辑连接到单元格 init() 方法。
  • @DmytroPashkov 在这种情况下,不要使用状态。使用一些模型,与用户界面分离。一般来说,回答这个问题:我认为我需要一些约束吗?如果没有,我不需要状态属性包装器...
猜你喜欢
  • 1970-01-01
  • 2022-10-06
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多