paw*_*222 7 ios swift swiftui swiftui-tabview swiftui-navigationview
我有一个 TabView 和每个 Tab 项的单独 NavigationView 堆栈。它运行良好,但是当我打开任何 NavigationLink 时,仍会显示 TabView 栏。我希望它在我点击任何 NavigationLink 时消失。
struct MainView: View {
@State private var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
FirstView()
.tabItem {
Text("1")
}
.tag(0)
SecondView()
.tabItem {
Text("2")
}
.tag(1)
}
}
}
struct FirstView: View {
var body: some View {
NavigationView {
NavigationLink(destination: FirstChildView()) { // How can I open FirstViewChild with the TabView bar hidden?
Text("Go to...")
}
.navigationBarTitle("FirstTitle", displayMode: .inline)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我找到了将 TabView 放入 NavigationView 的解决方案,因此在单击 NavigationLink 后,TabView 栏被隐藏。但这会弄乱 Tab 项的 NavigationBarTitles。
struct MainView: View {
@State private var tabSelection = 0
var body: some View {
NavigationView {
TabView(selection: $tabSelection) {
...
}
}
}
}
struct FirstView: View {
var body: some View {
NavigationView {
NavigationLink(destination: FirstChildView()) {
Text("Go to...")
}
.navigationBarTitle("FirstTitle", displayMode: .inline) // This will not work now
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,为每个 TabView 项设置不同的 NavigationTabBar 的唯一方法是使用嵌套的 NavigationView。也许有一种方法可以正确实现嵌套的 NavigationViews?(据我所知,导航层次结构中应该只有一个 NavigationView)。
如何在 SwiftUI 中正确隐藏 NavigationLink 视图中的 TabView 栏?
Hik*_*and 16
我真的很喜欢上面发布的解决方案,但我不喜欢 TabBar 没有根据视图转换隐藏这一事实。实践中,当使用tabBar.isHidden时向左滑动导航返回时,结果是不可接受的。
我决定放弃原生 SwiftUI TabView 并编写自己的代码。UI 中的结果更加美观:
以下是用于达到此结果的代码:
首先定义一些视图:
struct FirstView: View {
var body: some View {
NavigationView {
VStack {
Text("First View")
.font(.headline)
}
.navigationTitle("First title")
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.yellow)
}
}
}
struct SecondView: View {
var body: some View {
VStack {
NavigationLink(destination: ThirdView()) {
Text("Second View, tap to navigate")
.font(.headline)
}
}
.navigationTitle("Second title")
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.orange)
}
}
struct ThirdView: View {
var body: some View {
VStack {
Text("Third View with tabBar hidden")
.font(.headline)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.red.edgesIgnoringSafeArea(.bottom))
}
}
Run Code Online (Sandbox Code Playgroud)
然后,创建 TabBarView (这将是您的应用程序中使用的根视图):
struct TabBarView: View {
enum Tab: Int {
case first, second
}
@State private var selectedTab = Tab.first
var body: some View {
VStack(spacing: 0) {
ZStack {
if selectedTab == .first {
FirstView()
}
else if selectedTab == .second {
NavigationView {
VStack(spacing: 0) {
SecondView()
tabBarView
}
}
}
}
.animation(nil)
if selectedTab != .second {
tabBarView
}
}
}
var tabBarView: some View {
VStack(spacing: 0) {
Divider()
HStack(spacing: 20) {
tabBarItem(.first, title: "First", icon: "hare", selectedIcon: "hare.fill")
tabBarItem(.second, title: "Second", icon: "tortoise", selectedIcon: "tortoise.fill")
}
.padding(.top, 8)
}
.frame(height: 50)
.background(Color.white.edgesIgnoringSafeArea(.all))
}
func tabBarItem(_ tab: Tab, title: String, icon: String, selectedIcon: String) -> some View {
ZStack(alignment: .topTrailing) {
VStack(spacing: 3) {
VStack {
Image(systemName: (selectedTab == tab ? selectedIcon : icon))
.font(.system(size: 24))
.foregroundColor(selectedTab == tab ? .primary : .black)
}
.frame(width: 55, height: 28)
Text(title)
.font(.system(size: 11))
.foregroundColor(selectedTab == tab ? .primary : .black)
}
}
.frame(width: 65, height: 42)
.onTapGesture {
selectedTab = tab
}
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案还允许在 TabBar 中进行大量自定义。例如,您可以添加一些通知徽章。
可能的解决方法可以基于TabBarAccessor
我对以编程方式检测 SwiftUI 中的 Tab Bar 或 TabView 高度的回答
这是选项卡项目保持中的必需修改NavigationView
。使用 Xcode 11.4 / iOS 13.4 测试
struct FirstTabView: View {
@State private var tabBar: UITabBar! = nil
var body: some View {
NavigationView {
NavigationLink(destination:
FirstChildView()
.onAppear { self.tabBar.isHidden = true } // !!
.onDisappear { self.tabBar.isHidden = false } // !!
) {
Text("Go to...")
}
.navigationBarTitle("FirstTitle", displayMode: .inline)
}
.background(TabBarAccessor { tabbar in // << here !!
self.tabBar = tabbar
})
}
}
Run Code Online (Sandbox Code Playgroud)
注意:或者当然如果FirstTabView
应该是可重用的并且可以独立实例化,那么tabBar
里面的属性应该是可选的并显式处理 ansbsent tabBar。
感谢另一个 Asperi 的回答,我能够找到一个不会破坏动画并且看起来很自然的解决方案。
struct ContentView: View {
@State private var tabSelection = 1
var body: some View {
NavigationView {
TabView(selection: $tabSelection) {
FirstView()
.tabItem {
Text("1")
}
.tag(1)
SecondView()
.tabItem {
Text("2")
}
.tag(2)
}
// global, for all child views
.navigationBarTitle(Text(navigationBarTitle), displayMode: .inline)
.navigationBarHidden(navigationBarHidden)
.navigationBarItems(leading: navigationBarLeadingItems, trailing: navigationBarTrailingItems)
}
}
}
Run Code Online (Sandbox Code Playgroud)
struct FirstView: View {
var body: some View {
NavigationLink(destination: Text("Some detail link")) {
Text("Go to...")
}
}
}
struct SecondView: View {
var body: some View {
Text("We are in the SecondView")
}
}
Run Code Online (Sandbox Code Playgroud)
计算navigationBarTitle
和navigationBarItems
动态:
private extension ContentView {
var navigationBarTitle: String {
tabSelection == 1 ? "FirstView" : "SecondView"
}
var navigationBarHidden: Bool {
tabSelection == 3
}
@ViewBuilder
var navigationBarLeadingItems: some View {
if tabSelection == 1 {
Text("+")
}
}
@ViewBuilder
var navigationBarTrailingItems: some View {
if tabSelection == 1 {
Text("-")
}
}
}
Run Code Online (Sandbox Code Playgroud)
iOS 16 有更新,您现在可以隐藏任何导航栏。在这种情况下:
NavigationLink("Click") {
Text("Next View")
.toolbar(.hidden, for: .tabBar)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3821 次 |
最近记录: |