我正在尝试学习SwiftUI,并且将开发一个带有标签视图的简单应用,并在这些视图之间共享核心运动数据。
主要思想是创建运动管理器对象(如here),并在所有视图中使用传感器值。
ContentView.swift
:
import SwiftUI
struct ContentView: View {
@State private var selection = 1
@State private var viewNames : [String] = ["View1", "View2"]
var body: some View {
TabView(selection: $selection){
View1(viewName: $viewNames[0]).tag(0)
View2(viewName: $viewNames[1]).tag(1)
}
}
}
View1.swift
:
import SwiftUI
struct View1 : View {
@Binding var viewName : String
var body: some View {
Text("First View")
.font(.title)
.foregroundColor(Color.gray)
.tabItem {
VStack {
Image(systemName: "star")
Text(viewName)
}
}
}
}
View2.swift
:
struct View2 : View {
@Binding var viewName : String
var body: some View {
VStack {
Text("Second View")
.font(.title)
.foregroundColor(Color.green)
.padding(.top)
View21(motionManager: MotionManager())
}.tabItem {
VStack {
Image(systemName:"heart")
Text(viewName)
}
}
}
}
View21.swift
struct View21 : View {
@ObservedObject var motionManager : MotionManager
@State private var showDetails = false
var body: some View{
Text(String(format: "%.2f", motionManager.x))
}
使用这些代码,我可以在View21
中使用传感器数据,但是无法在以上层次结构的视图中访问数据。
此外,我在ContentView中创建了@ObservedObject
(例如here),并将其传递给所有视图。我的应用程序可以在模拟器中运行,但不能在实际设备上运行。
我可以看到传感器数据正在更改,但是无法切换选项卡视图。
我尝试使用@EnvironementObject
代替@ObservedObject
,但是行为是相同的。
非常感谢您为我的问题提供的帮助和建议。 祝福
答案 0 :(得分:1)
好的,Paulw11是对的,您可能想将ObservableObject注入到环境中,然后在每个要访问该实例的视图中,只需使用@EnvironmentObject属性包装器添加一个属性。下面,我汇总了我能想到的最简单的示例,以便您可以了解其工作原理。
import SwiftUI
import Combine
class ManagerPlaceholder: ObservableObject {
@Published var propertyOne: Double = 1.0
@Published var propertyTwo: Double = 2.0
func action() {
propertyOne = Double.random(in: 0.0..<100.00)
propertyTwo = Double.random(in: 0.0..<100.00)
}
}
struct ContentView: View {
@EnvironmentObject var manager: ManagerPlaceholder
var body: some View {
TabView {
Subview()
.tabItem { Label("First", systemImage: "hexagon.fill") }
.tag(1)
Subview()
.tabItem { Label("Second", systemImage: "circle.fill") }
.tag(2)
}
}
}
struct Subview: View {
@EnvironmentObject var manager: ManagerPlaceholder
var body: some View {
VStack {
Text("Prop One: \(manager.propertyOne)").padding()
Text("Prop Two: \(manager.propertyTwo)").padding()
Button("Change", action: manager.action).padding()
}
}
}
上面是
请注意,两个视图都有一个@EnvironmentObject var manager: ManagerPlaceholder
。您没有直接设置该属性。该行表示您要引用环境中的ManagerPlaceholder实例。环境是SwiftUI为您管理的一种“存储池”。您可以向其添加对象的实例,然后在需要该对象的子视图中对其进行引用。
因此,为确保在环境中,请在实例化视图(可以是选项卡视图或任何超级视图)时将其添加。因此,例如,在您的_NAME_App.swift(对于iOS 14目标)或SceneDelegate.swift(对于iOS 13目标)中,您可以这样实例化视图:
ContentView().environmentObject(ManagerPlaceholder())
如果您运行上面的代码,则单击“更改”按钮时将看到它随机设置了两个属性,并且当您来回切换时,两个子视图将看到完全相同的值,因为它们都引用相同的值实例。
如有任何不清楚之处,请随时发表评论。