简体   繁体   English

我怎样才能通过绑定<timer>在 SwiftUI 中?</timer>

[英]How can I pass Binding<Timer> in SwiftUI?

I would like to pass a timer from ContentView to SecondView , but I don't know how to manage it because I never used it before.我想将计时器从ContentView传递给SecondView ,但我不知道如何管理它,因为我以前从未使用过它。

Can someone figure this out for me?有人可以帮我解决这个问题吗?

ContentView内容视图

struct ContentView: View {
    @State private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
    @State private var timeRemaining = 10
    
    
    var body: some View {
        NavigationView {
            VStack {
                Text("\(timeRemaining)")
                    .onReceive(timer) { _ in
                        if timeRemaining > 0 {
                            timeRemaining -= 1
                        }
                    }
                
                NavigationLink {
                    SecondView(timer: ???) // <-- What should i pass here?
                } label: {
                    Text("Change View")
                }
            }
        }
    }
}

SecondView第二视图

struct SecondView: View {
    @Binding var timer: ??? // <-- What type?
    @State private var timeRemaining = 5
    
    var body: some View {
        Text("Hello")
            .onReceive(timer) { _ in
                if timeRemaining > 0 {
                    timeRemaining -= 1
                }
            }
    }
}

struct SecondView_Previews: PreviewProvider {
    static var previews: some View {
        SecondView(timer: ???) // <-- Same thing here in SecondView preview
    }
}

With this timer declaration you are in the Combine world.有了这个计时器声明,您就进入了Combine世界。 Combine is the reactive framework from Apple. Combine是 Apple 的响应式框架。

First you would need to import it:首先,您需要导入它:

import Combine

I have commented the code but Combine is a far field and it probably would be best to read the documentation about it, read some tutorials and try some things out.我已经对代码进行了注释,但Combine是一个遥远的领域,最好阅读有关它的文档,阅读一些教程并尝试一些事情。

documentation文件

struct ContentView: View {
    // The typ here is Publishers.Autoconnect<Timer.TimerPublisher>
    // But we can erase it and the result will be a Publisher that emits a date and never throws an error: AnyPublisher<Date,Never>
    @State private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common)
        .autoconnect()
        .eraseToAnyPublisher()
    @State private var timeRemaining = 10
    
    
    var body: some View {
        NavigationView {
            VStack {
                Text("\(timeRemaining)")
                    .onReceive(timer) { _ in
                        if timeRemaining > 0 {
                            timeRemaining -= 1
                        }
                    }
                
                NavigationLink {
                    // pass the publisher on
                    SecondView(timer: timer)
                } label: {
                    Text("Change View")
                }
            }
        }
    }
}

struct SecondView: View {
    //You don´t need binding here as this view never manipulates this publisher
    var timer: AnyPublisher<Date,Never>
    @State private var timeRemaining = 5
    
    var body: some View {
        Text("Hello")
            .onReceive(timer) { _ in
                if timeRemaining > 0 {
                    timeRemaining -= 1
                    print(timeRemaining)
                }
            }
    }
}

struct SecondView_Previews: PreviewProvider {
    // Creating a static private var should work here !not tested!
    @State static private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common)
        .autoconnect()
        .eraseToAnyPublisher()
    static var previews: some View {
        SecondView(timer: timer)
    }
}

You could simply inject the timer publisher, as suggested above, but there may be an even simpler solution:如上所述,您可以简单地注入计时器发布者,但可能有一个更简单的解决方案:

FirstView is already updating with every tick of the timer. FirstView已经随着计时器的每一个滴答声而更新。 You could simply pass a timeRemaning binding to your second view and then it too would just update with every tick of the timer (because timeRemaining changes on each tick).您可以简单地将timeRemaning绑定传递给您的第二个视图,然后它也会随着计时器的每个滴答声而更新(因为timeRemaining在每个滴答声上都会发生变化)。 You can then observe and react to changes of timeRemaining using .onChange(of:) :然后,您可以使用.onChange(of:)观察timeRemaining的变化并做出反应:

struct SecondView: View {
    @Binding var timeRemaining: TimeInterval

    var body: some View {
        Text("Hello")
           .onChange(of: timeRemaining) {
               if $0 < 0 { 
                   timeRemaining = -1
               }
           }
    }
}
               

You don't need to pass a binding, Since you are not mutating timer of contentview from the second view.您不需要传递绑定,因为您没有从第二个视图更改 contentview 的计时器。 You can just pass the reference to the timer publisher and then subscribe to it using .onReceive() .您可以将引用传递给计时器发布者,然后使用.onReceive()订阅它。

import Combine // here

struct ContentView: View {
    let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect().eraseToAnyPublisher() //<= Here
    @State private var timeRemaining = 10
    
    
    var body: some View {
        NavigationView {
            VStack {
                Text("\(timeRemaining)")
                    .onReceive(timer) { _ in
                        if timeRemaining > 0 {
                            timeRemaining -= 1
                        }
                    }
                
                NavigationLink {
                    SecondView(timer: timer)
                } label: {
                    Text("Change View")
                }
            }
        }
    }
}

struct SecondView: View {
    let timer: AnyPublisher<Date, Never> // Here
    @State private var timeRemaining = 5
    
    var body: some View {
        VStack {
            Text("Hello")
                .onReceive(timer) { _ in
                    if timeRemaining > 0 {
                        timeRemaining -= 1
                    }
                }
            Text("time remaining \(timeRemaining)")
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM