CustomNavBar 自定义导航栏视图

news2024/11/25 18:49:22

1. 创建偏好设置键 CustomNavBarTitlePreferenceKey.swift

import Foundation
import SwiftUI

//@State private var showBackButton: Bool = true
//@State private var title: String = "Title" //""
//@State private var subtitle: String? = "SubTitle" //nil

/// 导航栏标题偏好设置
struct CustomNavBarTitlePreferenceKey: PreferenceKey{
    static var defaultValue: String = ""
    
    static func reduce(value: inout String, nextValue: () -> String) {
        value = nextValue()
    }
}

/// 导航栏子标题偏好设置
struct CustomNavBarSubtitlePreferenceKey: PreferenceKey{
    static var defaultValue: String? = nil
    
    static func reduce(value: inout String?, nextValue: () -> String?) {
        value = nextValue()
    }
}

/// 导航栏隐藏返回按钮偏好设置
struct CustomNavBarBackButtonHiddenPreferenceKey: PreferenceKey{
    static var defaultValue: Bool = false
    
    static func reduce(value: inout Bool, nextValue: () -> Bool) {
        value = nextValue()
    }
}

/// 扩展 View
extension View{
    /// 保存导航栏标题
    func customNavigationTitle(_ title: String) -> some View{
        preference(key: CustomNavBarTitlePreferenceKey.self, value: title)
    }
    
    /// 保存导航栏子标题
    func customNavigationSubtitle(_ subtitle: String?) -> some View{
        preference(key: CustomNavBarSubtitlePreferenceKey.self, value: subtitle)
    }
    
    /// 保存导航栏是否显示回退键
    func customNavigationBarBackButtonHidden(_ value: Bool) -> some View{
        preference(key: CustomNavBarBackButtonHiddenPreferenceKey.self, value: value)
    }
    
    /// 自定义导航栏选项
    func customNavBarItems(title: String = "", subtitle: String? = nil, backButtonHidden: Bool = false) -> some View{
        self
            .customNavigationTitle(title)
            .customNavigationSubtitle(subtitle)
            .customNavigationBarBackButtonHidden(backButtonHidden)
    }
}

2. 创建自定义导航栏视图 CustomNavBarView.swift

import SwiftUI

/// 自定义导航栏视图
struct CustomNavBarView: View {
    @Environment(\.presentationMode) var presentationMode
    let showBackButton: Bool
    let title: String //""
    let subtitle: String? //nil
    
    var body: some View {
        HStack {
            if showBackButton {
                backButton
            }
            Spacer()
            titleSection
            Spacer()
            if showBackButton {
                backButton
                    .opacity(0)
            }
        }
        .padding()
        .accentColor(.white)
        .foregroundColor(.white)
        .font(.headline)
        .background(
            Color.accentColor.ignoresSafeArea(edges: .top)
        )
    }
}

extension CustomNavBarView{
    /// 返回按钮
    private var backButton: some View{
        Button {
            presentationMode.wrappedValue.dismiss()
        } label: {
            Image(systemName: "chevron.left")
                .padding()
        }
    }
    
    /// 标题视图
    private var titleSection: some View{
        VStack(spacing: 4) {
            Text(title)
                .font(.title)
                .fontWeight(.semibold)
            if let subtitle = subtitle{
                Text(subtitle)
            }
        }
    }
}

struct CustomNavBarView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            CustomNavBarView(showBackButton: true, title: "Title", subtitle: "Subtitle")
            Spacer()
        }
    }
}

3. 创建自定义导航栏容器视图 CustomNavBarContainerView.swift

import SwiftUI

/// 自定义导航栏容器视图
struct CustomNavBarContainerView<Context: View>: View {
    let context: Context
    @State private var showBackButton: Bool = true
    @State private var title: String = ""
    @State private var subtitle: String? = nil
    init(@ViewBuilder context: () -> Context) {
        self.context = context()
    }
    
    var body: some View {
        VStack(spacing: 0) {
            CustomNavBarView(showBackButton: showBackButton, title: title, subtitle: subtitle)
            context
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
         // 监听偏好值
        .onPreferenceChange(CustomNavBarTitlePreferenceKey.self) { value in
            self.title = value
        }
        .onPreferenceChange(CustomNavBarSubtitlePreferenceKey.self) { value in
            self.subtitle = value
        }
        .onPreferenceChange(CustomNavBarBackButtonHiddenPreferenceKey.self) { value in
            self.showBackButton = !value
        }
    }
}

struct CustomNavBarContainerView_Previews: PreviewProvider {
    static var previews: some View {
        CustomNavBarContainerView {
            ZStack {
                Color.green.ignoresSafeArea()
                Text("Hello world")
                    .foregroundColor(.white)
                    .customNavigationTitle("Title")
                    .customNavigationSubtitle("Subtitle")
                    .customNavigationBarBackButtonHidden(true)
            }
        }
    }
}

4. 创建自定义导航视图 CustomNavView.swift

import SwiftUI

/// 自定义导航视图
struct CustomNavView<Content: View>: View {
    /// 泛型
    let context: Content
    
    init(@ViewBuilder context: () -> Content) {
        self.context = context()
    }
    
    var body: some View {
        NavigationView {
            CustomNavBarContainerView {
                context
            }
        }
        .navigationViewStyle(.stack)
    }
}

extension UINavigationController{
    open override func viewDidLoad() {
        super.viewDidLoad()
        // 手势识别器交互代理置为 nil,进入下一个导航页面,从左往右滑,能够移除当前页面
       interactivePopGestureRecognizer?.delegate = nil
    }
}

struct CustomNavView_Previews: PreviewProvider {
    static var previews: some View {
        CustomNavView {
            Color.red.ignoresSafeArea()
        }
    }
}

5. 创建自定义导航视图链接到下一个视图 CustomNavLink.swift

import SwiftUI

/// 自定义导航视图链接下个视图
struct CustomNavLink<Label: View, Destination: View>: View {
    
    let destination: Destination
    let lable: Label
    
    init(@ViewBuilder destination: () -> Destination, @ViewBuilder label: () -> Label) {
        self.destination = destination()
        self.lable = label()
    }
    
    var body: some View {
        NavigationLink {
            CustomNavBarContainerView {
                destination
            }
            .navigationBarHidden(true)
            
        } label: {
            lable
        }
    }
}

struct CustomNavLink_Previews: PreviewProvider {
    static var previews: some View {
        // 自定义导航试图
        CustomNavView {
            CustomNavLink {
                Text("Destination")
            } label: {
                Text("CLICK ME")
            }
        }
    }
}

6. 创建应用导航栏视图 AppNavBarView.swift

import SwiftUI

/// 应用导航栏视图
struct AppNavBarView: View {
    var body: some View {
        /// 系统默认导航栏
        //defaultNavBavView
        /// 自定义导航栏
        customNavBavView
    }
}

/// 扩展 View
extension AppNavBarView{
    /// 系统默认导航栏
    private var defaultNavBavView: some View{
        NavigationView {
            ZStack {
                Color.green
                    .ignoresSafeArea()
                NavigationLink {
                    Text("Destination")
                        .navigationTitle("Title2")
                        .navigationBarBackButtonHidden(false)
                } label: {
                    Text("Navigate")
                        .foregroundColor(.black)
                }
            }
            .navigationTitle("Nav title here")
        }
    }
    
    /// 自定义导航栏
    private var customNavBavView: some View{
        CustomNavView {
            ZStack {
                Color.orange.ignoresSafeArea(edges: .bottom)
                CustomNavLink {
                    Text("Destination")
                        .customNavBarItems(title: "Second Screen", subtitle: "Subtitle should be showing!!!")
                } label: {
                    Text("Navigate")
                }
            }
            .customNavBarItems(title: "New Title", subtitle: "Subtitle", backButtonHidden: true)
        }
    }
}

struct AppNavBarView_Previews: PreviewProvider {
    static var previews: some View {
        AppNavBarView()
    }
}

7. 效果图:

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1089721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

树莓派部署.net core网站程序

1、发布你的项目 使用mobaxterm上传程序 回到mobaxterm,f进入目录输入&#xff1a; cd webpublish 运行程序&#xff1a;dotnet WebApplication1.dll 访问地址为&#xff1a;http://localhost:5000,尝访问如下&#xff1a; 已经出现 返回的json&#xff0c;证明是可以访问的…

阿里云服务器通用型规格族20个实例规格性能特点和适用场景汇总

阿里云服务器ECS通用型规格族属于独享型云服务器&#xff0c;实例采用固定CPU调度模式&#xff0c;实例的每个CPU绑定到一个物理CPU超线程&#xff0c;实例间无CPU资源争抢&#xff0c;实例计算性能稳定且有严格的SLA保证&#xff0c;在性能上会更加稳定&#xff0c;高负载情况…

AI:38-基于深度学习的抽烟行为检测

随着人工智能的迅猛发展,它在各个领域展现出了广泛的应用潜力。其中,基于深度学习的抽烟行为检测技术引起了人们的极大兴趣。这项技术利用计算机视觉和深度学习算法,能够自动检测和监测人们的抽烟行为,为烟草控制和公共卫生提供了新的手段。本文将深入探讨基于深度学习的抽…

01-网络篇-网络分层和常见网络协议

常使用的网络有广域网&#xff08;WAN&#xff09;、城域网、局域网&#xff08;LAN&#xff09;&#xff0c;一般我们遇到的场景是广域网和局域网&#xff0c;广域网就是常说的外网&#xff0c;而局域网一般用于学校、公司等场合。在家庭路由器中对应WAN口和LAN口。网络是极为…

Windows 定时备份 pg 数据库,定时删除

目录 1. 写个备份脚本2. Windows 添加定时任务3. 使用备份的 SQL 还原数据 1. 写个备份脚本 备份数据库脚本&#xff1a; pgBacks.bat ECHO OFF :: 用于启用扩展功能。在使用enableextensions选项后&#xff0c;批处理脚本可以使用扩展命令和特性 setlocal enableextensions…

Sprint framework Day08:Spring的@Autowired注解

前言 当使用注解和 XML 配置结合时&#xff0c;可以使用注解 Autowired、Qualifier 和 Primary 来实现自动装配并进行依赖注入。 一、了解 Autowired、Qualifier 和 Primary 注解 Autowired 注解&#xff1a;用于自动装配依赖。在需要进行依赖注入的地方&#xff0c;添加 Auto…

Jetpack:006-如何使用输入框

文章目录 1. 概念介绍2. 使用方法2.1 TextField2.2 OutlinedTextField 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中文本组件扩展相关的内容&#xff0c;本章回中主要介绍输入框组件。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01; 1. 概念介…

C++笔记--基于C++实现NMS算法

1--完整代码 // g nms.cpp -stdc11 -o nms_test // ./nms_test#include <iostream> #include <vector> #include <algorithm>// 锚框结构体 struct BoundingBox{float x, y, width, height, score; };class NMS{ public:NMS(){};// 非极大值抑制函数std::ve…

华为云云耀云服务器L实例评测|华为云耀云服务器L实例私有库搭建verdaccio(八)

九、华为云耀云服务器L实例私有库搭建verdaccio&#xff1a; Verdaccio 是一个简单的、零配置本地私有 npm 软件包代理注册表。Verdaccio 开箱即用&#xff0c;拥有自己的小型数据库&#xff0c;能够代理其它注册表&#xff08;例如 npmjs.org&#xff09;&#xff0c;缓存下载…

Linux桌面环境(桌面系统)

早期的 Linux 系统都是不带界面的&#xff0c;只能通过命令来管理&#xff0c;比如运行程序、编辑文档、删除文件等。所以&#xff0c;要想熟练使用 Linux&#xff0c;就必须记忆很多命令。 后来随着 Windows 的普及&#xff0c;计算机界面变得越来越漂亮&#xff0c;点点鼠标…

接口测试文档

接口测试的总结文档 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者之前的区别与联系。但该部分只交代了怎么做和如何做&#xff1f;并没有解释为什么要做&#xff1f; 第二部分&#xff1a;主要介绍为什…

企业云盘推荐:哪个更适合您的需求?

企业云盘因其便捷易用的特点&#xff0c;已成为现代企业办公的热门工具之一。 首先&#xff0c;企业云盘提供了可靠的数据存储。与传统的本地存储方式相比&#xff0c;企业云盘将数据存储在云服务器上&#xff0c;具有强大的数据冗余和备份机制&#xff0c;确保数据的安全性和…

【专题】并查集判断冲突

&#xff08;1&#xff09;题目 P1955 [NOI2015] 程序自动分析 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) &#xff08;2&#xff09;解决思路 先排序&#xff0c;把所有e1的操作放在前面&#xff0c;然后再进行e0的操作。在进行e1的操作的时候&#xff0c;我们只要把它…

笔试、面试总结(网络安全与渗透测试)

什么是同源策略&#xff1f; 为了防止不同域在用户浏览器中彼此干扰&#xff0c;浏览器对从不同来源&#xff08;域&#xff09;收到的内容进行隔离。浏览器不允许任何旧有脚本访问一个站点的 cookie&#xff0c;否则 &#xff0c;会话容易被劫持。只有发布 cookie 的站点能够…

用servlet实现一个简单的猜数字游戏。

需要两个页面&#xff0c;一个jsp页面&#xff08;guess.jsp&#xff09;和servlet页面&#xff08;servlet&#xff09;。 一.jsp页面 在jsp页面中需要实现&#xff1a; 1.创建随机数并且保存在session中。 2.做个form表单提交猜的数字给servlet页面。 <%page import&…

电提示找不到api-ms-win-crt-runtime-l1-1-0.dll怎么办,分享快速解决办法

如果在电脑中提示api-ms-win-crt-runtime-l1-1-0.dll找不到或丢失的情况&#xff0c;大家可以来看看这篇文章&#xff0c;能够快速解决api-ms-win-crt-runtime-l1-1-0.dll丢失的问题&#xff0c;一起来看看都有什么办法解决吧。 一&#xff0e;api-ms-win-crt-runtime-l1-1-0.d…

判断多个多边形是否连通(方法一:原理)

重点&#xff1a; 1.将多边形一个一个拎出来判断&#xff0c;以1为开始&#xff0c;后续如果连接&#xff0c;就加入序列&#xff0c;以2开始判断&#xff0c;以此为序。

Python 机器学习入门之逻辑回归

系列文章目录 第一章 Python 机器学习入门之线性回归 第一章 Python 机器学习入门之梯度下降法 第一章 Python 机器学习入门之牛顿法 第二章 Python 机器学习入门之逻辑回归 逻辑回归 系列文章目录前言一、逻辑回归简介二、逻辑回归推导1、问题2、Sigmoid函数3、目标函数3.1 让…

【C语言】对文件的输入输出

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C语言初步学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读1. 什么是文件1.1 程序文件1.2 数据文件1.3 数据流1.4 文件名 2. 文件的分类3. 文件缓冲区4. 文件的打开和关闭4.1 文…

IDEA插件推荐:TabColor

国庆假期&#xff0c;闲来无事&#xff0c;笔者自己开发了一个简易的IDEA插件。 TabColor 这是一个IDEA插件。通过改变核心Tab的颜色&#xff0c;将开发者从一堆Tab的迷茫中解放&#xff01; 安装 IDEA插件安装界面&#xff0c;搜索TabColor&#xff0c;进行安装。从浏览器下…