当前位置: 首页 > 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.接下来重启电脑…...

B站视频下载终极指南:BilibiliDown的完整使用教程

B站视频下载终极指南&#xff1a;BilibiliDown的完整使用教程 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/Bi…...

基于PLC的智能饲喂系统设计:开启现代养殖自动化新篇章

基于PLC的智能饲喂系统设计 本设计包括设计报告&#xff0c;任务书&#xff0c;模拟工程仿真。本设计的制作智能饲喂是现代物流系统的重要组成部分&#xff0c;是代替人工饲喂的可行性计划&#xff0c;由自动控制与管理系统、配料系统、送料系统、自动统计系统、触摸屏监控系统…...

【操作系统】第三章 内存管理(一)

第三章 内存管理 3.1 内存管理概念 3.1.1 内存管理的基本原理和要求 内存管理的主要功能&#xff1a; 内存空间的分配与回收。[连续分配管理方式](#3.1.2 连续分配管理方式)和非连续分配管理方式&#xff08;分页、分段&#xff09;地址转换&#xff1a;实现逻辑地址到物理…...

嵌入式开发中的静态代码分析工具与应用

嵌入式代码静态分析工具深度解析1. 静态代码分析技术概述1.1 传统编译器的局限性标准C语言编译器通常只能检测代码中的语法错误和部分潜在缺陷&#xff0c;对于程序架构设计和逻辑层面的问题往往无能为力。这种局限性在嵌入式开发中尤为明显&#xff0c;因为嵌入式系统对代码质…...

DeepSeek LintCode 3867 · 范围内的数字计数 public int digitsCount(int d, int low, int high)

LintCode 3867 范围内的数字计数 问题分析 计算在区间 [low, high] 中&#xff0c;数字 d 出现的次数。 核心思想&#xff1a;使用数位DP或前缀和思想 • count(low, high) count(0, high) - count(0, low-1) 方法一&#xff1a;逐位统计法&#xff08;推荐&#xff09;AC pu…...

staticFunctional:嵌入式零堆内存的std::function替代方案

1. staticFunctional&#xff1a;嵌入式系统中零动态内存开销的 std::function 替代方案1.1 设计动因与工程痛点在资源受限的嵌入式系统&#xff08;如 ARM Cortex-M0/M4、AVR、ESP32、Teensy 系列&#xff09;中&#xff0c;std::function的标准实现存在根本性兼容障碍。其典型…...

终极指南:如何在Windows电脑上直接安装Android应用

终极指南&#xff1a;如何在Windows电脑上直接安装Android应用 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer APK Installer是一款专为Windows系统设计的Android应用安…...

Nexus | 连接预测和决策:数据驱动优化的进展和挑战

文章信息论文题目为《Bridging prediction and decision: Advancesand challenges in data-driven optimization》&#xff0c;该文于2025年发表于《Nexus》期刊上。摘要数据驱动方法通过将预测与决策相结合&#xff0c;彻底改变了传统的优化方法。文章探讨了三种关键方法 ——…...

基于AI多因子与流动性模型的黄金再定价分析:4500关口修复后的“黄金坑”是否成立?

摘要&#xff1a;本文通过引入AI多因子定价模型&#xff0c;结合流动性压力识别算法、资金流向追踪系统与宏观变量建模&#xff0c;对黄金从5602美元回落至4099美元后的市场行为进行分析&#xff0c;重点解析抛售驱动逻辑、相关性漂移及4500美元关口的再定价机制。一、AI趋势重…...

Kali 2023最新版安装Fluxion避坑指南:从git clone到镜像源全流程

Kali 2023最新版安装Fluxion避坑指南&#xff1a;从git clone到镜像源全流程 如果你正在学习网络安全渗透测试&#xff0c;Fluxion绝对是一个值得掌握的Wi-Fi安全审计工具。作为Kali Linux生态中最受欢迎的无线网络测试套件之一&#xff0c;它通过智能化的交互界面让复杂的攻击…...