2

我正在尝试学习 SwiftUI,我将开发一个带有选项卡视图的简单应用程序,并在这些视图之间共享核心运动数据。

主要思想是创建一个运动管理器对象(如这里)并在所有视图中使用传感器值。

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,但无法访问上述层次结构中视图中的数据。

此外,我@ObservedObject在 ContentView 中创建(如此)并将其传递给所有视图。我的应用程序在模拟器中工作,但它不在真实设备上。我可以看到传感器数据发生变化,但无法切换选项卡视图。我尝试使用@EnvironementObject而不是@ObservedObject,但行为是相同的。

对于我的问题的任何帮助和提示,我将非常感谢。最良好的祝愿

4

1 回答 1

2

好的,所以 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()
        }
    }
    
}

所以上面是

  • 一个简单的 ObservableObject - 它所做的只是设置两个具有随机值的 Doubles(注意您要观察的属性标记为 @Published)
  • 选项卡视图
  • 一个简单的子视图

请注意,两个视图都有一个@EnvironmentObject var manager: ManagerPlaceholder. 您不直接设置该属性。该行表示您要引用环境中的 ManagerPlaceholder 实例。环境是 SwiftUI 为您管理的一种存储“池”。您可以向其中添加对象的实例,然后在需要它的子视图中引用它。

因此,为了确保它在实例化视图(可以是选项卡视图或任何超级视图)时添加它的环境中。因此,例如在您的 _NAME_App.swift(对于 iOS 14 目标)或 SceneDelegate.swift(对于 iOS 13 目标)中,您可以像这样实例化您的视图:

ContentView().environmentObject(ManagerPlaceholder())

如果你运行上面的代码,你会看到当你点击 Change 按钮时,它会随机设置两个属性,当你来回切换时,两个子视图会看到完全相同的值,因为它们都引用同一个实例。

如果有任何不清楚的地方,请随时发表评论。

于 2020-08-24T21:20:46.417 回答