SwiftUI:更改基于 NavigationBarTitle 的 TabbedView 标签的更好方法
SwiftUI: Better way of changing NavigationBarTitle based TabbedView label
我 终于 弄清楚如何根据 TabbedView
中的当前选项卡使用 [=13= 更改我的 NavigationView
的标题],但我很确定这不是解决问题的方法:
struct SomeTabbedView : View {
@State private var selection = 0
@State private var title = "First"
var body: some View {
NavigationView {
TabbedView(selection: $selection) {
ContentView()
.tabItemLabel(
Text("First")
).tag(0).onAppear{
self.title = "First"
}
OtherView()
.tabItemLabel(
Text("Second")
).tag(1).onAppear{
self.title = "Second"
}
}.navigationBarTitle(Text(title))
}
}
}
简而言之,这严重违反了 DRY 原则。如果我们决定更改第一个视图,例如字符串 "First",当前的实现将需要在三个不同的地方重复。
我想过初始化一个字典数组并遍历 View: Label
对,但我不仅不确定这是正确的方法,而且我不确定如何继续实施它。也可以只包含一个带有标签的数组,但是如果我们想要更改视图的顺序,这会造成另一个违规行为。
您的顶级视图应该是 TabbedView
,并且每个选项卡都应该有自己的 NavigationView
。这没有解决 "First" 用于 .navigationBarTitle
和 .tabItemLabel
的事实,但它们实际上是两个不同的东西,可以不同。
struct SomeTabbedView : View {
@State private var selection = 0
var body: some View {
TabbedView(selection: $selection) {
NavigationView {
ContentView()
.navigationBarTitle(Text("First"))
}
.tabItemLabel(Text("First"))
.tag(0)
NavigationView {
OtherView()
.navigationBarTitle(Text("Second"))
}
.tabItemLabel(Text("Second"))
.tag(1)
}.edgesIgnoringSafeArea(.top)
}
}
我有一个类似的问题并通过创建一个类似于 SwiftUI 中所做的视图包装器解决了它。
这基本上只是将 DRYness 添加到 :
struct NavigationTab<Title, Content>: View where Title: StringProtocol, Content: View {
var title: Title
var content: () -> Content
var body: some View {
NavigationView {
content()
.navigationBarTitle(Text(title))
}
.tabItemLabel(Text(title))
}
}
我省略了标记,因为对我来说,在父视图中定义这些标记更有意义。你可以这样使用它:
struct SomeTabbedView: View {
@State private var selection = 0
var body: some View {
TabbedView(selection: $selection) {
NavigationTab(title: "First") {
ContentView()
}
.tag(0)
NavigationTab(title: "Second") {
OtherView()
}
.tag(1)
}
}
}
如果您想在选项卡标签上方添加图像等其他详细信息,这显然会变得更加复杂,因为 .navigationBarTitle()
需要一个 Text 实例。
我 终于 弄清楚如何根据 TabbedView
中的当前选项卡使用 [=13= 更改我的 NavigationView
的标题],但我很确定这不是解决问题的方法:
struct SomeTabbedView : View {
@State private var selection = 0
@State private var title = "First"
var body: some View {
NavigationView {
TabbedView(selection: $selection) {
ContentView()
.tabItemLabel(
Text("First")
).tag(0).onAppear{
self.title = "First"
}
OtherView()
.tabItemLabel(
Text("Second")
).tag(1).onAppear{
self.title = "Second"
}
}.navigationBarTitle(Text(title))
}
}
}
简而言之,这严重违反了 DRY 原则。如果我们决定更改第一个视图,例如字符串 "First",当前的实现将需要在三个不同的地方重复。
我想过初始化一个字典数组并遍历 View: Label
对,但我不仅不确定这是正确的方法,而且我不确定如何继续实施它。也可以只包含一个带有标签的数组,但是如果我们想要更改视图的顺序,这会造成另一个违规行为。
您的顶级视图应该是 TabbedView
,并且每个选项卡都应该有自己的 NavigationView
。这没有解决 "First" 用于 .navigationBarTitle
和 .tabItemLabel
的事实,但它们实际上是两个不同的东西,可以不同。
struct SomeTabbedView : View {
@State private var selection = 0
var body: some View {
TabbedView(selection: $selection) {
NavigationView {
ContentView()
.navigationBarTitle(Text("First"))
}
.tabItemLabel(Text("First"))
.tag(0)
NavigationView {
OtherView()
.navigationBarTitle(Text("Second"))
}
.tabItemLabel(Text("Second"))
.tag(1)
}.edgesIgnoringSafeArea(.top)
}
}
我有一个类似的问题并通过创建一个类似于 SwiftUI 中所做的视图包装器解决了它。
这基本上只是将 DRYness 添加到
struct NavigationTab<Title, Content>: View where Title: StringProtocol, Content: View {
var title: Title
var content: () -> Content
var body: some View {
NavigationView {
content()
.navigationBarTitle(Text(title))
}
.tabItemLabel(Text(title))
}
}
我省略了标记,因为对我来说,在父视图中定义这些标记更有意义。你可以这样使用它:
struct SomeTabbedView: View {
@State private var selection = 0
var body: some View {
TabbedView(selection: $selection) {
NavigationTab(title: "First") {
ContentView()
}
.tag(0)
NavigationTab(title: "Second") {
OtherView()
}
.tag(1)
}
}
}
如果您想在选项卡标签上方添加图像等其他详细信息,这显然会变得更加复杂,因为 .navigationBarTitle()
需要一个 Text 实例。