DDTabBar 自定义 TabBar
概述
DDTabBar 模块底部导航栏的自定义实现,
- 支持 普通样式 与 液态玻璃(Liquid Glass)样式 双形态切换。
- 支持暗黑模式和长辈模式
- 支持Lottie,gif,png图片资源
- 支持自定义角标,小红点
- 根据接口动态更新item数量,顺序
效果
液态玻璃-暗黑
液态玻璃-白天
普通模式
长辈版
目录结构
DDTabBar/
├── Manager/ # 管理与加载
│ ├── DDTabBarManager.swift # TabBar 单例、数据与配置
│ ├── DDTabBarItemOperationBadgeView.swift # 运营角标
│ ├── TabBarCacheManager.swift # 配置缓存
│ ├── TabBarResourceLoader.swift # 图标/Lottie 资源加载
│ └── TabbarRNRouterInterceptor.swift # RN 路由拦截
├── Model/
│ ├── DDTabBarItem.swift # (预留) Item 定义
│ └── TabBarModel.swift # TabBar 与 Item 数据模型
├── Util/
│ ├── DDTaBarEnum.h # 枚举:场景、Item 类型、图片类型
│ └── DDTabBarUtil.swift # 工具:曝光埋点、数据比较等
└── View/
├── DDTabBar.swift # 主入口:双样式容器与切换逻辑
├── DDTabBarItemBadgeView.swift # 角标视图
├── DDTabBarItemContainer.swift # 单个 Tab 容器(可点击)
├── DDTabBarItemContentView.swift # Tab 内容(图标+文案+角标)
├── TabbarWebViewController.swift # Web Tab 落地页
└── README.md # 本文档
双样式架构
1. 样式类型
| 样式 | 类名 | 说明 |
|---|---|---|
| 普通样式 | DDTabBarNormalView | 全宽 TabBar,毛玻璃 + 背景图/背景色,常规布局 |
| 液态玻璃 | DDTabBarLiquidGlassView | 圆角胶囊容器,iOS 26 下使用 UIGlassEffect,支持暗黑适配 |
2. 切换条件
液态玻璃是否展示由 DDTabBar.isLiquidGlassActive() 决定:
DDLiquidGlassManager.shared.isLiquidGlassActive == true- 且 非长辈版:
!DDBasicInfoManager.shared.isAPVersion
满足时显示 DDTabBarLiquidGlassView,否则显示 DDTabBarNormalView。
3. 状态同步
- 通过通知监听并刷新当前展示的样式:
DDLiquidGlassManager.StateDidChangedNotification:液态玻璃开关变化.DDDarkModeShowDarkChanged:暗黑模式变化kChangeToAPVersionNotification:长辈版切换
- 两种视图的数据与选中索引会同时更新,保证切换样式时状态一致。
主入口实现细节(DDTabBar)
- ** 默认数据,缓存数据,接口数据 调用update时更新DDTabBarLiquidGlassView 和DDTabBarNormalView,更新时先判断内存中是否有该tab,只更新tab数据不影响飘红角标,没有则创建tab的view;
- **更新前为每个 Item 设置暗黑图(
checkDataDark/uncheckDataDark按 itemType 取本地图名)。 - 布局:
layoutSubviews中normalView.frame = bounds、liquidGlassView.frame = bounds,两套视图始终叠在同一区域,通过isHidden切换显示。 - 长辈版高度:
sizeThatFits在DDBasicInfoManager.shared.isAPVersion时高度 +17pt。
普通样式(DDTabBarNormalView)
视图层级与布局
-
子视图顺序(自底向上):
visualEffectView(全 bounds)→backgroundImageView(全 bounds)→contentView(全 bounds)。 -
Item 布局:全宽均分布局,
itemHeight默认 48。 -
首页小火箭:对第一个 item 容器附加首页“小火箭”视图(
HomeTabBarItem),用于首页特殊动效/回到顶部能力的承载。 -
暗黑:不支持暗黑
液态玻璃样式(DDTabBarLiquidGlassView)
1. 视觉与层级
- 容器:圆角胶囊,宽度
kScreenWidth - 30,水平居中,高度 62pt(containerH) - 层级(自底向上):
shadowView:暗色模糊视图,用于阴影/暗黑增强effectView:使用系统新增的玻璃效果(UIGlassEffect),并开启交互能力(interactive)以获得更自然的玻璃触感与动态反馈)contentView:放置各个tabItemsegmentControl:iOS 26UISegmentedControl具有点击拖动有放大镜效果,用于事件响应,UISegmentedControl有valueChanged,但我们还要求再次点击同一个item业务,切换到目标item时,若是拦截的需要把selectedSegmentIndex设置为上一个lastSelectedIndex
虽然给
segmentControl.insertSegment(withTitle: "", at: idx, animated: false)
但仍需要设置,不然会有灰色的背景
DispatchQueue.main.async {
for subview in self.segmentControl.subviews {
if subview is UIImageView && subview != self.segmentControl.subviews.last {
subview.alpha = 0
}
}
}
3. 暗黑与选中态
isCurrentShowDark控制:- 选中槽背景色:暗黑时为
RGBA(0x000000, 0.2),否则为gray.withAlphaComponent(0.15) - 暗黑时显示
shadowView,非暗黑时隐藏
- 选中槽背景色:暗黑时为
- Item 使用
isSupportDark = true,会使用模型中的checkDataDark/uncheckDataDark等暗黑资源。
DDTabBarItemContentView
ContentView(DDTabBarItemContentView)
- 子视图:
iconImageView(DDIconImageView,支持 Lottie/静图/Gif)、titleLabel、businessBadgeView(运营角标)、badgeView(数字/红点角标)。 - 两种展示模式(
itemData.style):- style 0(小图):图片和文字的形式。
- style 1(大图):只有一个大图;
titleLabel.isHidden = true,iconImageView.isHidden = false。
- 选中/未选:根据
selected与DDDarkModeManager.shared.isCurrentShowDark、isSupportDark选择checkResource/checkDataDark、uncheckResource/uncheckDataDark及对应文字颜色,调用iconImageView.setData(data:type:style)与iconImageView.play()。
数据与展示
1. 数据流概览
- 配置来源:
DDTabBarManager.getTabBarConfigData(scene:parmars:aipComplet:)拉取接口,经TabBarResourceLoader下载图标/Lottie 后,由dealTabBarData更新tabBarModel并调用tabBar.update(data:items:)。 - 模型:
TabBarModel:整条 Tab 配置(背景色/图、bottom_list、场景、来源等)TabBarItemModel:单个 Tab(类型、文案、选中/未选资源、链接、角标等)
与系统 UITabBar 的配合
-
DDTabBar作为自定义视图加在 TabBarController 的 tabBar 上,系统自带的 Tab 按钮需隐藏。代码中通过UITabBar的 extension 重写addGestureRecognizer,对名为_UIContinuousSelectionGestureRecognizer的类禁用; -
并暴露
recursiveFindTabButtons(in:),递归查找_UITabBarButton与_UITabButton设为isHidden = true,以及_UITabBarPlatterView隐藏,从而只展示自定义的 DDTabBar 内容。
此处会对私有属性怎混淆处理
小结
| 能力 | 说明 |
|---|---|
| 双样式 | 普通样式(全宽毛玻璃+背景)与液态玻璃样式(圆角胶囊 + iOS26 玻璃效果) |
| 切换 | 由液态玻璃开关 + 是否长辈版决定,通过通知自动刷新 |
| iOS 26 | 液态玻璃使用 UIGlassEffect + 染色层,暗黑下配合阴影与暗色选中槽 |
| 数据 | 接口 → TabBarModel/TabBarItemModel → 两套 View 同步更新与选中索引 |
| 埋点 | 点击/曝光均带 liquidGlassState 区分 liquid / other |