CustomTabBar 自定义选项卡视图
1. 用到的技术点
1) Generics 泛型
2) ViewBuilder 视图构造器
3) PreferenceKey 偏好设置
4) MatchedGeometryEffect 几何效果
2. 创建枚举选项卡项散列,TabBarItem.swift
import Foundation
import SwiftUI//struct TabBarItem: Hashable{
// let iconName: String
// let title: String
// let color: Color
//}///枚举选项卡项散列
enum TabBarItem: Hashable{case home, favorites, profile, messagesvar iconName: String{switch self {case .home: return "house"case .favorites: return "heart"case .profile: return "person"case .messages: return "message"}}var title: String{switch self {case .home: return "Home"case .favorites: return "Favorites"case .profile: return "Profile"case .messages: return "Messages"}}var color: Color{switch self {case .home: return Color.redcase .favorites: return Color.bluecase .profile: return Color.greencase .messages: return Color.orange}}
}
3. 创建选项卡偏好设置 TabBarItemsPreferenceKey.swift
import Foundation
import SwiftUI/// 选项卡项偏好设置
struct TabBarItemsPreferenceKey: PreferenceKey{static var defaultValue: [TabBarItem] = []static func reduce(value: inout [TabBarItem], nextValue: () -> [TabBarItem]) {value += nextValue()}
}/// 选项卡项视图修饰符
struct TabBarItemViewModifer: ViewModifier{let tab: TabBarItem@Binding var selection: TabBarItemfunc body(content: Content) -> some View {content.opacity(selection == tab ? 1.0 : 0.0).preference(key: TabBarItemsPreferenceKey.self, value: [tab])}
}extension View{/// 选项卡项视图修饰符func tabBarItem(tab: TabBarItem, selection: Binding<TabBarItem>) -> some View{modifier(TabBarItemViewModifer(tab: tab, selection: selection))}
}
4. 创建自定义选项卡视图 CustomTabBarView.swift
import SwiftUI/// 自定义选项卡视图
struct CustomTabBarView: View {let tabs: [TabBarItem]@Binding var selection: TabBarItem@Namespace private var namespace@State var localSelection: TabBarItemvar body: some View {//tabBarVersion1tabBarVersion2.onChange(of: selection) { value inwithAnimation(.easeInOut) {localSelection = value}}}
}extension CustomTabBarView{/// 自定义 tabitem 布局private func tabView1(tab: TabBarItem) -> some View{VStack {Image(systemName: tab.iconName).font(.subheadline)Text(tab.title).font(.system(size: 12, weight: .semibold, design: .rounded))}.foregroundColor(localSelection == tab ? tab.color : Color.gray).padding(.vertical, 8).frame(maxWidth: .infinity).background(localSelection == tab ? tab.color.opacity(0.2) : Color.clear).cornerRadius(10)}/// 选项卡版本1private var tabBarVersion1: some View{HStack {ForEach(tabs, id: \.self) { tab intabView1(tab: tab).onTapGesture {switchToTab(tab: tab)}}}.padding(6).background(Color.white.ignoresSafeArea(edges: .bottom))}/// 切换选项卡private func switchToTab(tab: TabBarItem){selection = tab}
}extension CustomTabBarView{/// 自定义 tabitem 布局 2private func tabView2(tab: TabBarItem) -> some View{VStack {Image(systemName: tab.iconName).font(.subheadline)Text(tab.title).font(.system(size: 12, weight: .semibold, design: .rounded))}.foregroundColor(localSelection == tab ? tab.color : Color.gray).padding(.vertical, 8).frame(maxWidth: .infinity).background(ZStack {if localSelection == tab{RoundedRectangle(cornerRadius: 10).fill(tab.color.opacity(0.2)).matchedGeometryEffect(id: "background_rectangle", in: namespace)}})}/// 选项卡版本 2private var tabBarVersion2: some View{HStack {ForEach(tabs, id: \.self) { tab intabView2(tab: tab).onTapGesture {switchToTab(tab: tab)}}}.padding(6).background(Color.white.ignoresSafeArea(edges: .bottom)).cornerRadius(10).shadow(color: Color.black.opacity(0.3), radius: 10, x: 0, y: 5).padding(.horizontal)}
}struct CustomTabBarView_Previews: PreviewProvider {static let tabs: [TabBarItem] = [.home, .favorites, .profile]static var previews: some View {VStack {Spacer()CustomTabBarView(tabs: tabs, selection: .constant(tabs.first!), localSelection: tabs.first!)}}
}
5. 创建自定义选项卡容器视图 CustomTabBarContainerView.swift
import SwiftUI/// 自定义选项卡容器视图
struct CustomTabBarContainerView<Content: View>: View {@Binding var selection: TabBarItemlet content: Content@State private var tabs: [TabBarItem] = []init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content){self._selection = selectionself.content = content()}var body: some View {ZStack(alignment: .bottom) {content.ignoresSafeArea()CustomTabBarView(tabs: tabs, selection: $selection, localSelection: selection)}.onPreferenceChange(TabBarItemsPreferenceKey.self) { value intabs = value}}
}struct CustomTabBarContainerView_Previews: PreviewProvider {static let tabs: [TabBarItem] = [ .home, .favorites, .profile]static var previews: some View {CustomTabBarContainerView(selection: .constant(tabs.first!)) {Color.red}}
}
6. 创建应用选项卡视图 AppTabBarView.swift
import SwiftUI// Generics 泛型
// ViewBuilder 视图构造器
// PreferenceKey 偏好设置
// MatchedGeometryEffect 几何效果/// 应用选项卡视图
struct AppTabBarView: View {@State private var selection: String = "Home"@State private var tabSelection: TabBarItem = .homevar body: some View {/// 默认系统的 TabView// defaultTabView/// 自定义 TabViewcustomTabView}
}extension AppTabBarView{/// 默认系统的 TabViewprivate var defaultTabView: some View{TabView(selection: $selection) {Color.red.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "house")Text("Home")}Color.blue.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "heart")Text("Favorites")}Color.orange.ignoresSafeArea(edges: .top).tabItem {Image(systemName: "person")Text("Profile")}}}/// 自定义 TabViewprivate var customTabView: some View{CustomTabBarContainerView(selection: $tabSelection) {Color.red.tabBarItem(tab: .home, selection: $tabSelection)Color.blue.tabBarItem(tab: .favorites, selection: $tabSelection)Color.green.tabBarItem(tab: .profile, selection: $tabSelection)Color.orange.tabBarItem(tab: .messages, selection: $tabSelection)}}
}struct AppTabBarView_Previews: PreviewProvider {static var previews: some View {AppTabBarView()}
}
7. 效果图:

相关文章:
CustomTabBar 自定义选项卡视图
1. 用到的技术点 1) Generics 泛型 2) ViewBuilder 视图构造器 3) PreferenceKey 偏好设置 4) MatchedGeometryEffect 几何效果 2. 创建枚举选项卡项散列,TabBarItem.swift import Foundation import SwiftUI//struct TabBarItem: Hashable{ // let ico…...
卡片翻转效果的实现思路
卡片翻转效果的实现思路 HTML 基础布局 <div class"card"><img class"face" src"images/chrome_eSCSt8hUpR.png" /><p class"back"><span>背面背景</span></p> </div>布局完成后如下所示…...
blob和ArrayBuffer格式图片如何显示
首先blob格式图片 <template> <div> <img :src"imageURL" alt"Image" /> </div> </template> <script> export default { data() { return { imageBlob: null, // Blob格式的图片 imageURL: null // 图…...
MySQL学习(四)——事务与存储引擎
文章目录 1. 事务1.1 概念1.2 事务操作1.2.1 未设置事务1.2.2 控制事务 1.3 事务四大特性1.4 并发事务问题1.5 事务隔离级别 2. 存储引擎2.1 MySQL体系结构2.2 存储引擎2.3 存储引擎的特点2.3.1 InnoDB2.3.2 MyISAM2.3.3 Memory2.3.4 区别和比较 1. 事务 1.1 概念 事务 是一组…...
3.3 Tessellation Shader (TESS) Geometry Shader(GS)
一、曲面细分着色器的应用 海浪,雪地等 与置换贴图的结合 二、几何着色器的应用 几何动画 草地等(与曲面着色器结合) 三、着色器执行顺序 1.TESS的输入与输出 输入 Patch,可以看成是多个顶点的集合,包含每个顶点的属…...
C++:超越C语言的独特魅力
W...Y的主页😊 代码仓库分享💕 🍔前言: 今天我们依旧来完善补充C,区分C与C语言的区别。上一篇我们讲了关键字、命名空间、C的输入与输出、缺省参数等知识点。今天我们继续走进C的世界。 目录 函数重载 函数重载概…...
【LeetCode】27. 移除元素
1 问题 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新…...
AWS SAP-C02教程4--身份与联合身份认证
AWS的账号和权限控制一开始接触的时候觉得很复杂,不仅IAM、Identiy Federation、organization,还有Role、Policy等。但是其实先理清楚基本一些概念,然后在根据实际应用场景去理解设计架构,你就会很快掌握这一方面的内容。 AWS的账号跟其它一些云或者说一些SAAS产品的账号没…...
Mybatis Plus入门进阶:特殊符号、动态条件、公共语句、关联查询、多租户插件
前言 Mybatis Plus入门进阶:特殊符号、动态条件、公共语句、关联查询、多租户插件 隐藏问题:批量插入saveBatch 文章目录 前言注意点动态条件xml公共语句关联查询动态表名使用自定义函数主键生成策略saveBatch插件:多租户TenantLineInnerInte…...
Webpack 什么是loader?什么是plugin?loader与plugin区别是什么?
什么是loader?什么是plugin? loader 本质为一个函数,将文件编译成可执行文件。webpack完成的工作是将依赖分析与tree shinking对于类似.vue或.scss结尾的文件无法编译理解这就需要实现一个loader完成文件转译成js、html、css、json等可执行文…...
js面向对象(工厂模式、构造函数模式、原型模式、原型和原型链)
1.封装 2. 工厂模式 function createCar(color, style){let obj new Object();obj.color color;obj.style style;return obj;}var car1 createCar("red","car1");var car2 createCar("green","car2"); 3. 构造函数模式 // 创建…...
grid网格布局,比flex方便太多了,介绍几种常用的grid布局属性
使用flex布局的痛点 如果使用justify-content: space-between;让子元素两端对齐,自动分配中间间距,假设一行4个,如果每一行都是4的倍数那没任何问题,但如果最后一行是2、3个的时候就会出现下面的状况: /* flex布局 两…...
企业如何凭借软文投放实现营销目标?
数字时代下,软文投放成为许多企业营销的主要方式,因为软文投放成本低且效果持续性强,最近也有不少企业来找媒介盒子进行软文投放,接下来媒介盒子就来给大家分享下,企业在软文投放中需要掌握哪些技巧,才能实…...
【AI】深度学习——循环神经网络
神经元不仅接收其他神经元的信息,也能接收自身的信息。 循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络,可以更方便地建模长时间间隔的相关性 常用的参数学习可以为BPTT。当输入序列比较…...
计算机网络中常见缩略词翻译及简明释要
强烈推荐OSI七层模型和TCP/IP四层模型,借用一下其中图片,版权归原作者 SW: 集线器(Hub)、交换机(SW)、路由器(router)对比区别 集线器是在物理层; 交换机&Mac地址是在数据链路层(Mac物理地址…...
UGUI交互组件ScrollView
一.ScrollView的结构 对象说明Scroll View挂有Scroll Rect组件的主体对象Viewport滚动显示区域,有Image和mask组件Content显示内容的父节点,只有个Rect Transform组件Scrollbar Horizontal水平滚动条Scrollbar Vertical垂直滚动条 二.Scroll Rect组件的属…...
【文件IO】文件系统的操作 流对象 字节流(Reader/Writer)和字符流 (InputStream/OutputStream)的用法
目录 1.文件系统的操作 (File类) 2.文件内容的读写 (Stream流对象) 2.1 字节流 2.2 字符流 2.3 如何判断输入输出? 2.4 reader读操作 (字符流) 2.5 文件描述符表 2.6 Writer写操作 (字符流) 2.7 InputStream (字节流) 2.8 OutputStream (字节流) 2.9 字节…...
计算机网络 | 数据链路层
计算机网络 | 数据链路层 计算机网络 | 数据链路层基本概念功能概述封装成帧与透明传输封装成帧透明传输字符计数法字符填充法零比特填充法违规编码法小结 差错控制差错是什么?差错从何而来?为什么要在数据链路层进行差错控制?检错编码奇偶校…...
C#,数值计算——分类与推理Gaumixmod的计算方法与源程序
1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Gaumixmod { private int nn { get; set; } private int kk { get; set; } private int mm { get; set; } private double…...
【Android】Intel HAXM installation failed!
Android Studio虚拟机配置出现Intel HAXM installation failed 如果方案一解决没有作用,就用方案二再试一遍 解决方案一: 1.打开控制面板 2.点击左侧下面最后一个程序 3.点击启用或关闭Windows功能 4.勾选Windows虚拟机监控程序平台 5.接下来重启电脑…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
