[英]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?有人可以帮我解决这个问题吗?
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")
}
}
}
}
}
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
是一个遥远的领域,最好阅读有关它的文档,阅读一些教程并尝试一些事情。
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.