自定义 NavigationView 顶部栏

Custom NavigationView top bar

我想创建一个类似于上图的设计。为了创建底部的 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 等)的同时实现该结果。

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
            }
        )
    }
}

备注:

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

祝你好运!

编辑:为 HomeView 添加了代码