ios SwiftUI每秒从Timer更新一个@State属性,也是每秒重绘一次整个View

xdnvmnnf  于 2023-03-31  发布在  iOS
关注(0)|答案(2)|浏览(176)

我不确定我是否正确地使用了它,但情况如下:
我有一个观点:

struct TimerView: View {
    @State private var numberOfVideos: Int
    @State private var time = ""
    private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    init(numberOfVideos: Int) {
        _numberOfVideos = State(initialValue: numberOfVideos)
    }

    var body: some View {
        Text(time)
            .onReceive(timer) { _ in
                // it is called every second
                time = "00:00"
            }
        ReportView(numberOfVideos: $numberOfVideos)
    }
}

struct ReportView: View {
    @Binding private var numberOfVideos: Int
    init(numberOfVideos: Binding<Int>) {
        // ❌ this is called every second, I don't want it.
        self._numberOfVideos = numberOfVideos
    }

    var body: some View {
        Text(String(numberOfVideos))
    }
}

使用方法:

TimerView(numberOfVideos: 5)

每秒示例化ReportView这不是我需要的。我如何解决这个问题?

tvz2xvvm

tvz2xvvm1#

在单独的视图中移动计时器逻辑,如下所示:

struct TimerView: View {
    @State private var numberOfVideos: Int
    @State private var time = ""

    init(numberOfVideos: Int) {
        _numberOfVideos = State(initialValue: numberOfVideos)
    }

    var body: some View {
        TimeText(text: $time)
        ReportView(numberOfVideos: $numberOfVideos)
            // .background(.debug)
    }
}

struct ReportView: View {
    @Binding private var numberOfVideos: Int
    init(numberOfVideos: Binding<Int>) {
        // ❌ this is called every second, I dont want it.
        self._numberOfVideos = numberOfVideos
    }

    var body: some View {
        Text(String(numberOfVideos))
    }
}

struct TimeText: View {
    @Binding var text: String
    private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
        Text(text)
            .onReceive(timer) { t in
                // it is called every second
                text = t.debugDescription
            }
    }
}
o4tp2gmn

o4tp2gmn2#

问题是您将numberOfVideos存储为ReportView上的Binding
您应该只使用Binding将可变状态注入到子视图中,当可变状态从视图内部或外部更改时,您希望重新绘制子视图。
因为你永远不会从ReportView内部改变numberOfVideos,所以你应该把它存储为一个不可变的属性。如果TimerView会更新numberOfVideos,那就会重新绘制整个TimerView,从而也会用更新后的数字创建一个新的ReportView
这可以确保每次在TimerView上更新time时不会重新创建ReportView

struct ReportView: View {
  private let numberOfVideos: Int

  init(numberOfVideos: Int) {
    self.numberOfVideos = numberOfVideos
  }

  var body: some View {
    Text(String(numberOfVideos))
  }
}

相关问题