自定义 NavigationView 顶栏

Posted

技术标签:

【中文标题】自定义 NavigationView 顶栏【英文标题】:Custom NavigationView top bar 【发布时间】:2021-03-12 13:54:35 【问题描述】:

我想创建一个类似于上图的设计。为了创建底部的 TabView,我使用了以下代码:

import SwiftUI

struct ParentTabView: View 

    var body: some View 
    
        TabView 
            HomeView()
                .tabItem 
                    Image(systemName: "star.fill")
                    Text("Home")
                
            Text("Second Tab")
                .tabItem 
                    Image(systemName: "star.fill")
                    Text("Discover")
                
            Text("Third Tab")
                .tabItem 
                    Image(systemName: "star.fill")
                    Text("Settings")
                
        
    

和主视图

struct HomeView: View 
    var body: some View 
        NavigationView 
            Text("Home")
                .navigationBarItems(
                    trailing:
                        Button(action: 
                        ) 
                            Image(systemName: "plus")
                        
                )
                .navigationTitle("Home")
        
    

我遇到的问题是顶部导航栏,因为我无法编辑 NavigationView 以接收标题下方的其他视图。我可以设置标题并添加“加号”按钮,但不能编辑整个顶栏。

可以以这种方式自定义 NavigationView,如果不能,我如何在保持 NavigationView 提供的优势(例如 NavigationLinks 等)的同时实现该结果。

【问题讨论】:

【参考方案1】:

Apple 提供的 NavigationBar 不能完全自定义。您可能希望为此用例创建自定义导航栏。

幸运的是,我有一些时间,所以我创建了一个简单的可重复使用的导航栏,看起来像您想要的结果,请看下面。

您必须隐藏 Apple 的导航栏,并将自定义导航栏作为覆盖添加到您的导航视图(如下图所示):

这是可重用自定义导航视图的代码:

enum CustomNavigationBarItem: String, CaseIterable 
    case dashboard = "Dashboard"
    case feed = "Feed"
    case followers = "Followers"


struct CustomNavigationBar: View 
    var title: String
    var items: [CustomNavigationBarItem]
    @Binding var selectedItem: CustomNavigationBarItem
    var buttonAction: () -> ()

    var body: some View 
        VStack 
            VStack(spacing: 10) 
                CustomNavigationBarHeader(title: title, buttonAction: buttonAction)
                
                HStack(spacing: 0) 
                    ForEach(items, id: \.self)  item in
                        CustomNavigationBarItemView(text: item.rawValue, isSelected: selectedItem == item)
                            .onTapGesture 
                                selectedItem = item
                            
                    
                
            
            .background(Color(#colorLiteral(red: 0.1036974415, green: 0.1036974415, blue: 0.1036974415, alpha: 1)).edgesIgnoringSafeArea(.all))
            
            Spacer()
        
    


struct CustomNavigationBarItemView: View 
    var text: String
    var isSelected: Bool
    
    var body: some View 
        Text(text)
            .foregroundColor(isSelected ? .blue : Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
            .frame(maxWidth: .infinity)
            .padding(.vertical, 10)
            .padding(.horizontal, 6)
            .overlay(
                VStack 
                    Spacer()
                    Color.blue
                        .frame(height: 2)
                        .opacity(isSelected ? 1 : 0)
                        .animation(.default)
                
            )
    


struct CustomNavigationBarHeader: View 
    var title: String
    var buttonAction: () -> ()
    
    var body: some View 
        HStack 
            Text(title)
                .font(.title)
                .bold()
            
            Spacer()
            Button(action: buttonAction, label: 
                Image(systemName: "plus")
            )
            .font(.headline)
        
        .padding(.horizontal)
    

首页查看代码:

struct HomeView: View 
    @State private var selectedNavigationBarItem: CustomNavigationBarItem = .dashboard
    @State private var numPlusButtonClicked: Int = 0
    
    var body: some View 
        NavigationView 
            VStack 
                Text("Home")
                    
                switch selectedNavigationBarItem 
                    case .dashboard:
                        Text("Currently Showing: Dashboard") //Use your view here
                    case .feed:
                        Text("Currently Showing: Feed") //Use your view here
                    case .followers:
                        Text("Currently Showing: Followers") //Use your views here
                
                
                Text("Plus Button Clicked \(numPlusButtonClicked) times.")
            
        
        .navigationBarHidden(true)
        .overlay(
            CustomNavigationBar(title: "Home",
                                items: [.dashboard, .feed, .followers],
                                selectedItem: $selectedNavigationBarItem) 
                numPlusButtonClicked += 1 // Code executed when the "+" button gets called
            
        )
    

注意事项:

    您可以向“CustomNavigationBarItem”枚举添加更多项目 这绝不是一个完美的组件,因此请随意修改它以满足您的需求:D

祝你好运!

编辑:为 HomeView 添加代码

【讨论】:

这太不可思议了。我感激不尽! 不客气!我很高兴你喜欢它。我已经更新了我的答案以包含 HomeView 的代码

以上是关于自定义 NavigationView 顶栏的主要内容,如果未能解决你的问题,请参考以下文章

如何自定义 xamarin 表单 UWP 顶栏

如何为 NavigationView 中的项目设置自定义字体?

NavigationView中的SwiftUI自定义动画过渡?

如何在 NavigationView 中自定义项目背景和项目文本颜色?

导入presentationMode环境变量时自定义NavigationView搞砸了

如何为 NavigationView 中的单个菜单项提供自定义图标颜色?