[英]How can I pass Binding<CMMotionManager> in SwiftUI preview?
[英]How can I pass Binding<Timer> in SwiftUI?
我想將計時器從ContentView
傳遞給SecondView
,但我不知道如何管理它,因為我以前從未使用過它。
有人可以幫我解決這個問題嗎?
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
}
}
有了這個計時器聲明,您就進入了Combine
世界。 Combine
是 Apple 的響應式框架。
首先,您需要導入它:
import Combine
我已經對代碼進行了注釋,但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)
}
}
如上所述,您可以簡單地注入計時器發布者,但可能有一個更簡單的解決方案:
FirstView
已經隨着計時器的每一個滴答聲而更新。 您可以簡單地將timeRemaning
綁定傳遞給您的第二個視圖,然后它也會隨着計時器的每個滴答聲而更新(因為timeRemaining
在每個滴答聲上都會發生變化)。 然后,您可以使用.onChange(of:)觀察timeRemaining
的變化並做出反應:
struct SecondView: View {
@Binding var timeRemaining: TimeInterval
var body: some View {
Text("Hello")
.onChange(of: timeRemaining) {
if $0 < 0 {
timeRemaining = -1
}
}
}
}
您不需要傳遞綁定,因為您沒有從第二個視圖更改 contentview 的計時器。 您可以將引用傳遞給計時器發布者,然后使用.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.