这是一个带有2个标签的应用程序的非常简单的示例。在这两个选项卡上,我都有“当前月份”的简单自定义选择器。该选择器位于单独的DateView.swift中。
在每个标签上,我都有一个文本,可从选择器中读取数据(我将使用它来过滤每个标签上的列表)。
我想做什么:
更改日期应该在全球范围内有效。在一个标签上更改月份后,我应该在另一个标签上看到本月。
如何使其工作?目前,我正在使用ObservableObject。我执行错了吗? ObservableObject只是一种方式绑定,而我需要双向绑定吗?我应该改用EnvironmentObject吗?
这是我到目前为止的代码:
ContentView.swift
import SwiftUI
struct ContentView: View {
@State private var selection = 0
var body: some View {
TabView(selection: $selection){
FirstTabView()
.tabItem {
VStack {
Image("first")
Text("First")
}
}
.tag(0)
SecondTabView()
.tabItem {
VStack {
Image("second")
Text("Second")
}
}
.tag(1)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
FirstTabView.swift
import SwiftUI
struct FirstTabView: View {
@ObservedObject var selectedMonth = SelectedDate()
var body: some View {
NavigationView {
VStack {
DateView(selectedMonth: selectedMonth)
Text("\(selectedMonth.selectedMonth)")
.padding()
}
.navigationBarTitle("First Tab")
}
}
}
struct FirstTabView_Previews: PreviewProvider {
static var previews: some View {
FirstTabView()
}
}
SecondTabView.swift
import SwiftUI
struct SecondTabView: View {
@ObservedObject var selectedMonth = SelectedDate()
var body: some View {
NavigationView {
VStack {
DateView(selectedMonth: selectedMonth)
Text("\(selectedMonth.selectedMonth)")
.padding()
}
.navigationBarTitle("Second Tab")
}
}
}
struct SecondTabView_Previews: PreviewProvider {
static var previews: some View {
SecondTabView()
}
}
DateView.swift
import SwiftUI
class SelectedDate: ObservableObject {
@Published var selectedMonth: Date = Date()
}
struct DateView: View {
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.setLocalizedDateFormatFromTemplate("yyyy MMMM")
return formatter
}()
@ObservedObject var selectedMonth = SelectedDate()
var body: some View {
HStack {
Image(systemName: "chevron.left")
.frame(width: 50, height: 50)
.contentShape(Rectangle())
.onTapGesture {
self.changeMonthBy(-1)
}
Spacer()
Text("\(selectedMonth.selectedMonth, formatter: Self.dateFormat)")
Spacer()
Image(systemName: "chevron.right")
.frame(width: 50, height: 50)
.contentShape(Rectangle())
.onTapGesture {
self.changeMonthBy(1)
}
}
.padding(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5))
.background(Color.yellow)
}
func changeMonthBy(_ months: Int) {
if let selectedMonth = Calendar.current.date(byAdding: .month, value: months, to: selectedMonth.selectedMonth) {
self.selectedMonth.selectedMonth = selectedMonth
}
}
}
struct DateView_Previews: PreviewProvider {
struct BindingTestHolder: View {
@State var testItem: Date = Date()
var body: some View {
DateView()
}
}
static var previews: some View {
BindingTestHolder()
}
}
答案 0 :(得分:1)
我应该改用EnvironmentObject吗?
是的,如果您需要全局 的内容,那么EnvironmentObject
是正确的选择。
所以
struct ContentView: View {
@State private var selection = 0
// declare & create here (or use below alternates)
var selectedMonth = SelectedDate()
// alternates
//@EnvironmentObject var selectedMonth: SelectedDate
//@StateObject var selectedMonth = SelectedDate() // << Xcode12/SwiftUI2
var body: some View {
TabView(selection: $selection){
FirstTabView()
.tabItem {
VStack {
Image("first")
Text("First")
}
}
.tag(0)
SecondTabView()
.tabItem {
VStack {
Image("second")
Text("Second")
}
}
.tag(1)
}
// << inject here (not needed if above @EnvironmentObject is used
.environmentObject(selectedMonth)
}
}
如果未使用,则不需要选项卡中的EnvironmentObject对象,因为它是通过层次结构自动传输的
struct FirstTabView: View {
var body: some View {
NavigationView {
VStack {
DateView()
// ..other code
struct SecondTabView: View {
var body: some View {
NavigationView {
VStack {
DateView()
// ..other code
最后在哪里使用
struct DateView: View {
// only declared, and will be injected here automatically
@EnvironmentObject var selectedMonth: SelectedDate
// .. other code