当前位置: 首页 > news >正文

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. 创建枚举选项卡项散列&#xff0c;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)

一、曲面细分着色器的应用 海浪&#xff0c;雪地等 与置换贴图的结合 二、几何着色器的应用 几何动画 草地等&#xff08;与曲面着色器结合&#xff09; 三、着色器执行顺序 1.TESS的输入与输出 输入 Patch&#xff0c;可以看成是多个顶点的集合&#xff0c;包含每个顶点的属…...

C++:超越C语言的独特魅力

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 今天我们依旧来完善补充C&#xff0c;区分C与C语言的区别。上一篇我们讲了关键字、命名空间、C的输入与输出、缺省参数等知识点。今天我们继续走进C的世界。 目录 函数重载 函数重载概…...

【LeetCode】27. 移除元素

1 问题 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新…...

AWS SAP-C02教程4--身份与联合身份认证

AWS的账号和权限控制一开始接触的时候觉得很复杂,不仅IAM、Identiy Federation、organization,还有Role、Policy等。但是其实先理清楚基本一些概念,然后在根据实际应用场景去理解设计架构,你就会很快掌握这一方面的内容。 AWS的账号跟其它一些云或者说一些SAAS产品的账号没…...

Mybatis Plus入门进阶:特殊符号、动态条件、公共语句、关联查询、多租户插件

前言 Mybatis Plus入门进阶&#xff1a;特殊符号、动态条件、公共语句、关联查询、多租户插件 隐藏问题&#xff1a;批量插入saveBatch 文章目录 前言注意点动态条件xml公共语句关联查询动态表名使用自定义函数主键生成策略saveBatch插件&#xff1a;多租户TenantLineInnerInte…...

Webpack 什么是loader?什么是plugin?loader与plugin区别是什么?

什么是loader&#xff1f;什么是plugin&#xff1f; loader 本质为一个函数&#xff0c;将文件编译成可执行文件。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;让子元素两端对齐&#xff0c;自动分配中间间距&#xff0c;假设一行4个&#xff0c;如果每一行都是4的倍数那没任何问题&#xff0c;但如果最后一行是2、3个的时候就会出现下面的状况&#xff1a; /* flex布局 两…...

企业如何凭借软文投放实现营销目标?

数字时代下&#xff0c;软文投放成为许多企业营销的主要方式&#xff0c;因为软文投放成本低且效果持续性强&#xff0c;最近也有不少企业来找媒介盒子进行软文投放&#xff0c;接下来媒介盒子就来给大家分享下&#xff0c;企业在软文投放中需要掌握哪些技巧&#xff0c;才能实…...

【AI】深度学习——循环神经网络

神经元不仅接收其他神经元的信息&#xff0c;也能接收自身的信息。 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一类具有短期记忆能力的神经网络&#xff0c;可以更方便地建模长时间间隔的相关性 常用的参数学习可以为BPTT。当输入序列比较…...

计算机网络中常见缩略词翻译及简明释要

强烈推荐OSI七层模型和TCP/IP四层模型,借用一下其中图片&#xff0c;版权归原作者 SW: 集线器&#xff08;Hub&#xff09;、交换机&#xff08;SW&#xff09;、路由器&#xff08;router&#xff09;对比区别 集线器是在物理层; 交换机&Mac地址是在数据链路层(Mac物理地址…...

UGUI交互组件ScrollView

一.ScrollView的结构 对象说明Scroll View挂有Scroll Rect组件的主体对象Viewport滚动显示区域&#xff0c;有Image和mask组件Content显示内容的父节点&#xff0c;只有个Rect Transform组件Scrollbar Horizontal水平滚动条Scrollbar Vertical垂直滚动条 二.Scroll Rect组件的属…...

【文件IO】文件系统的操作 流对象 字节流(Reader/Writer)和字符流 (InputStream/OutputStream)的用法

目录 1.文件系统的操作 (File类) 2.文件内容的读写 (Stream流对象) 2.1 字节流 2.2 字符流 2.3 如何判断输入输出&#xff1f; 2.4 reader读操作 (字符流) 2.5 文件描述符表 2.6 Writer写操作 (字符流) 2.7 InputStream (字节流) 2.8 OutputStream (字节流) 2.9 字节…...

计算机网络 | 数据链路层

计算机网络 | 数据链路层 计算机网络 | 数据链路层基本概念功能概述封装成帧与透明传输封装成帧透明传输字符计数法字符填充法零比特填充法违规编码法小结 差错控制差错是什么&#xff1f;差错从何而来&#xff1f;为什么要在数据链路层进行差错控制&#xff1f;检错编码奇偶校…...

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 如果方案一解决没有作用&#xff0c;就用方案二再试一遍 解决方案一&#xff1a; 1.打开控制面板 2.点击左侧下面最后一个程序 3.点击启用或关闭Windows功能 4.勾选Windows虚拟机监控程序平台 5.接下来重启电脑…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...