SwiftUI - 将可滚动的 TabBar 转换为静止的 TabBar

SwiftUI - Convert a scrollable TabBar into a still TabBar

目前我所遵循的教程存在问题,该教程使用 SwiftUI 创建了带下划线的选项卡栏。在当前阶段,当视图更改时,选项卡栏会随着滚动视图一起滚动,但是,我希望按钮保持空闲状态,作为正常(仍在运行)带下划线的选项卡栏,而不是发生这种情况。这是当前滑动视图时的样子:

请注意,当标签更改时,标签在标签栏内如何更改时,标签滚动滚动。我试过删除标签栏的滚动视图,但似乎无法弄清楚如何让它在屏幕内保持固定。

教程中的代码如下所示:


import SwiftUI

struct ContentView: View {
    @State var currentTab: Int = 0
    var body: some View {
        ZStack(alignment: .top) {
            TabView(selection: self.$currentTab) {
                View1().tag(0)
                View2().tag(1)
            }
            .tabViewStyle(.page(indexDisplayMode: .never))
            .edgesIgnoringSafeArea(.all)
            
            TabBarView(currentTab: self.$currentTab)
        }
    }
}

struct TabBarView: View {
    @Binding var currentTab: Int
    @Namespace var namespace
    
    var tabBarOptions: [String] = ["View 1", "View 2"]
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 20) {
                ForEach(Array(zip(self.tabBarOptions.indices,
                                  self.tabBarOptions)),
                        id: \.0,
                        content: {
                    index, name in
                    TabBarItem(currentTab: self.$currentTab,
                               namespace: namespace.self,
                               tabBarItemName: name,
                               tab: index)
                    
                })
            }
            .padding(.horizontal)
        }
        .background(Color.white)
        .frame(height: 80)
        .edgesIgnoringSafeArea(.all)
    }
}

struct TabBarItem: View {
    @Binding var currentTab: Int
    let namespace: Namespace.ID
    
    var tabBarItemName: String
    var tab: Int
    
    var body: some View {
        Button {
            self.currentTab = tab
        } label: {
            VStack {
                Spacer()
                Text(tabBarItemName)
                if currentTab == tab {
                    Color.black
                        .frame(height: 2)
                        .matchedGeometryEffect(id: "underline",
                                               in: namespace,
                                               properties: .frame)
                } else {
                    Color.clear.frame(height: 2)
                }
            }
            .animation(.spring(), value: self.currentTab)
        }
        .buttonStyle(.plain)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

帮助解决此问题将不胜感激!谢谢!!

试试这个代码。这应该解决你的问题。主要问题是您使用了 ZStack 而不是 VStack。之后,只需 fiddle 围绕您在 VStack 中构建的元素的间距和定位。 让我知道它是否创建了您想要的结果。

import SwiftUI

struct ContentView: View {
    @State var currentTab: Int = 0
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            TabBarView(currentTab: self.$currentTab)
            
            TabView(selection: self.$currentTab) {
                Text("This is view 1").tag(0)
                Text("This is view 2").tag(1)
            }
            .tabViewStyle(.page(indexDisplayMode: .never))
            .background(Color.secondary) // <<<< Remove
        }
        .edgesIgnoringSafeArea(.all)
    }
}


struct TabBarView: View {
    @Binding var currentTab: Int
    @Namespace var namespace
    
    var tabBarOptions: [String] = ["View 1", "View 2"]
    var body: some View {
        HStack(spacing: 20) {
            ForEach(Array(zip(self.tabBarOptions.indices,
                              self.tabBarOptions)),
                    id: \.0,
                    content: {
                index, name in
                TabBarItem(currentTab: self.$currentTab,
                           namespace: namespace.self,
                           tabBarItemName: name,
                           tab: index)
                
            })
        }
        .padding(.horizontal)
        .background(Color.orange) // <<<< Remove
        .frame(height: 80)
    }
}

struct TabBarItem: View {
    @Binding var currentTab: Int
    let namespace: Namespace.ID
    
    var tabBarItemName: String
    var tab: Int
    
    var body: some View {
        Button {
            self.currentTab = tab
        } label: {
            VStack {
                Spacer()
                Text(tabBarItemName)
                if currentTab == tab {
                    Color.black
                        .frame(height: 2)
                        .matchedGeometryEffect(id: "underline",
                                               in: namespace,
                                               properties: .frame)
                } else {
                    Color.clear.frame(height: 2)
                }
            }
            .animation(.spring(), value: self.currentTab)
        }
        .buttonStyle(.plain)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}