更新记录

1.0.2(2026-08-19)

更新文档描述

1.0.1(2026-08-19)

  • 修复:vue / nvue tab 页混用时,切换 tab 会偶发把 tabBar 误隐藏。
  • 文档:补全 readme 中 setupGlassTabBar 全部参数(含 midButton 各字段)的示例与说明

平台兼容性

uni-app(4.66)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× × × × × 13 ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

glass-tabbar 液态玻璃 tabBar

基于 UTS 的 iOS 26 Liquid Glass(液态玻璃) 底部 tabBar 插件。

  • ✅ iOS 26+:系统级 UITabBar + Liquid Glass,支持中间凸起按钮
  • ✅ iOS < 26 / Android:自动降级,继续使用 pages.json 原生 tabBar
  • ✅ 兼容 vuenvue(可混用,例如首页 nvue、其余 tab 页 vue)
  • ✅ 附带 JS 业务封装,开箱接入 switchTab / 二级页隐藏
  • 安全区增强为可选功能setGlassSafeArea),默认不强制处理
  • ✅ tabBar 挂载在独立高层级浮层窗口上,跨页面切换不闪烁、不被遮挡

本插件为 App 端 UTS 原生能力。调试请使用包含本插件的自定义调试基座;Mac 真机可走 Xcode 本地编译。


一、目录说明

uni_modules/glass-tabbar
├── package.json
├── readme.md
├── changelog.md
├── license.md
├── js_sdk/
│   └── index.js              # 业务封装(推荐使用)
└── utssdk/
    ├── interface.uts         # API 声明
    ├── app-ios/              # iOS 原生实现
    └── app-android/          # Android 空实现(降级)

二、快速开始(推荐 js_sdk)

1. 保持 pages.json 原生 tabBar

插件不会替换你的 pages.json 配置。低版本系统仍依赖原生 tabBar;iOS 26 会在运行时 hideTabBar 并绘制玻璃 tabBar。

2. 首个 tab 页初始化(完整参数示例)

下面示例用到了 setupGlassTabBar 支持的全部参数,实际接入按需精简即可(大多数字段都是可选的)。

import {
  setupGlassTabBar,
  handleGlassTabPageShow,
  handleGlassTabPageHide
} from '@/uni_modules/glass-tabbar/js_sdk/index.js'

export default {
  onShow() {
    setupGlassTabBar({
      // 初始选中索引,默认 0
      current: 0,
      // 未选中 / 选中颜色(十六进制),默认 #7A7E83 / #007AFF
      color: '#7A7E83',
      selectedColor: '#007AFF',
      // 是否启用左右滑动切 tab,默认 true;
      // 用系统 UITabBar 自身的选择动画时建议关闭,避免和自定义手势冲突
      enableSwipe: false,
      // tab 列表,顺序必须与 pages.json 的 tabBar.list 保持一致
      list: [
        {
          text: '首页',
          // icon / activeIcon:iOS SF Symbol 名称;不传 activeIcon 则选中态复用 icon,仅切换颜色
          icon: 'house',
          activeIcon: 'house.fill',
          pagePath: 'pages/home/index'
        },
        {
          text: '发现',
          // iconPath / selectedIconPath:本地图片,优先级高于 icon;
          // 建议原图约 25×25pt(@2x 50px / @3x 75px),插件会自动按比例缩放到标准 tab 尺寸;
          // 不传 selectedIconPath 则复用 iconPath,仅切换为 selectedColor
          iconPath: 'static/image/discover.png',
          selectedIconPath: 'static/image/discover_sel.png',
          pagePath: 'pages/discover/index'
        },
        {
          text: '消息',
          icon: 'message',
          activeIcon: 'message.fill',
          pagePath: 'pages/message/index'
        },
        {
          text: '我的',
          icon: 'person',
          activeIcon: 'person.fill',
          pagePath: 'pages/my/index'
        }
      ],
      // 中间凸起按钮,完全可选;不需要则整个 midButton 都不传
      midButton: {
        text: '发布',            // 文案;showText=false 时不显示
        icon: 'plus',            // SF Symbol,默认 "plus"
        iconPath: '',            // 本地图片;传入后优先于 icon,且保留原始颜色不受 selectedColor 影响
        isRaised: false,         // 是否凸出 tabBar,默认 true
        showText: false          // 是否显示文案,默认 true
      },
      // 点击任意 tab 时的额外回调(内部已自动执行 uni.switchTab,这里通常做统计等附加逻辑)
      onChange(index) {
        console.log('切换到 tab', index)
      },
      // 中间凸起按钮点击回调(不参与 list 索引,不改变选中态)
      onMidButtonTap() {
        uni.showToast({ title: '点击了发布', icon: 'none' })
      }
    })
    // 建议每个 tab 页 onShow 都调用一次,保证从其它 tab / 二级页返回时正确显示与同步选中
    handleGlassTabPageShow(0)
  },
  onHide() {
    handleGlassTabPageHide()
  }
}

3. 其他 tab 页

import {
  handleGlassTabPageShow,
  handleGlassTabPageHide
} from '@/uni_modules/glass-tabbar/js_sdk/index.js'

export default {
  onShow() {
    // 参数为该页在 list 中的索引(从 0 开始)1代表第二个tab页面
    handleGlassTabPageShow(1)
  },
  onHide() {
    handleGlassTabPageHide()
  }
}

handleGlassTabPageShow / handleGlassTabPageHide 内部通过原生单例的“世代计数器”判断是否真的离开了 tab 区(详见下方常见问题第 4 条),vue 与 nvue 页面混用完全没有影响,每个 tab 页照抄这段即可。


三、可选功能:安全区设置

安全区相关能力不是必须的。只有在浮动玻璃 tabBar 下方出现露白时,再按需开启。

setGlassSafeArea(options)

字段 类型 默认 说明
fillColor string '' Home Indicator 区域补色;不传/空字符串表示不铺色

示例 1:底部补色

import { setGlassSafeArea } from '@/uni_modules/glass-tabbar/js_sdk/index.js'

// 建议取当前页背景渐变末端色;切换 tab 时可再次调用更新颜色
setGlassSafeArea({
  fillColor: '#38ef7d'
})

示例 2:按 tab 页切换补色

export default {
  onShow() {
    handleGlassTabPageShow(2)
    setGlassSafeArea({ fillColor: '#38ef7d' })
  }
}

说明:该功能仅在 iOS 26 液态玻璃模式生效;不会改写 manifest.json 全局 safearea,不影响低版本 iOS。


四、js_sdk API

方法 说明
setupGlassTabBar(config) 初始化玻璃 tabBar(建议在首个 tab 页 onShow),返回是否成功启用液态玻璃
handleGlassTabPageShow(index) tab 页 onShow 时调用:显示 tabBar 并同步选中态
handleGlassTabPageHide() tab 页 onHide 时调用:仅在真正离开 tab 区(进入二级页)时才隐藏 tabBar
setGlassSafeArea({ fillColor }) 可选:设置底部安全区补色
getGlassSafeAreaConfig() 读取当前安全区配置
shouldUseLiquidGlass() 当前是否 iOS 26+(是否会启用液态玻璃)
updateGlassTabBarActive(index) 手动同步高亮,不触发 onChange
syncGlassTabBar(route) 按路由字符串同步显示/隐藏(非 tab 页会自动隐藏)
getTabIndex(route) 路由转 tab 索引,非 tab 页返回 -1
removeGlassTabBar() 销毁玻璃 tabBar(一般不需要主动调用)

setupGlassTabBar(config) 参数详情

字段 类型 默认 说明
list Array - 必填,tab 列表,顺序需与 pages.jsontabBar.list 一致
list[].text string - 文案
list[].icon string - 未选中态图标,iOS SF Symbol 名称,如 "house"
list[].activeIcon string 复用 icon 选中态图标(SF Symbol);不传则复用 icon,仅切换颜色
list[].iconPath string - 未选中态本地图片路径;优先级高于 icon;建议原图约 25×25pt
list[].selectedIconPath string 复用 iconPath 选中态本地图片路径;不传则复用 iconPath,仅切换为 selectedColor
list[].pagePath string - 对应 tab 页路径,用于点击后 uni.switchTab
current number 0 初始选中索引
color string #7A7E83 未选中文字/图标颜色(十六进制)
selectedColor string #007AFF 选中文字/图标颜色(十六进制)
enableSwipe boolean true 是否启用左右滑动切 tab
midButton Object - 中间凸起按钮,完全可选
midButton.text string - 按钮文案;showText=false 时不显示
midButton.icon string "plus" SF Symbol 名称
midButton.iconPath string - 本地图片路径;传入后优先于 icon,且保留原始颜色
midButton.isRaised boolean true 是否凸出 tabBar;false 时按钮完整显示在 tabBar 内
midButton.showText boolean true 是否显示文案;false 时只显示图标
onChange Function(index) - 点击任意 tab 的额外回调(内部已自动 uni.switchTab
onMidButtonTap Function - 中间按钮点击回调

五、原生 UTS API(高级)

也可直接调用原生能力,一般业务侧优先使用 js_sdk,无需直接操作以下 API:

import {
  showGlassTabBar,
  hideGlassTabBar,
  setGlassTabBarActive,
  setGlassTabBarHidden,
  extendGlassTabPageToBottom,
  setGlassSafeAreaFillColor,
  restoreGlassTabPageSafeArea
} from '@/uni_modules/glass-tabbar'
方法 说明
showGlassTabBar(options) 创建并显示玻璃 tabBar(对应 setupGlassTabBar 首次调用)
hideGlassTabBar() 销毁玻璃 tabBar 及浮层窗口
setGlassTabBarActive(index) 同步选中项,不触发 onChange
setGlassTabBarHidden(hidden) 仅切换可见性,不销毁视图
extendGlassTabPageToBottom() 将当前页铺满屏幕底部(配合安全区增强使用)
setGlassSafeAreaFillColor(color) 更新底部安全区补色
restoreGlassTabPageSafeArea() 恢复系统底部安全区

六、调试与打包注意

  1. 必须使用包含本插件的自定义调试基座(或 Mac 真机 + Xcode 本地编译 UTS)
  2. 修改 .uts 后请完整重新运行,热刷新不会重新注入原生类
  3. 模拟器若报 undefined class: UTSSDKModulesGlassTabbarIndexSwift,说明当前基座未打入本插件
  4. 正式云打包时勾选本 UTS 插件即可

七、常见问题

1. 底部 Home Indicator 露白?

这是可选能力。需要时调用:

setGlassSafeArea({ fillColor: '#你的页面底色' })

不要为了本插件去改全局 manifest.safearea(否则会影响所有 iOS 版本)。

2. Android / 低版本 iOS 会怎样?

setupGlassTabBar 返回 false,页面继续走 pages.json 原生 tabBar,无额外影响。

3. vue / nvue 都能用吗?可以混用吗?

可以。玻璃 tabBar 挂在独立的原生浮层窗口上,与页面渲染方式(vue webview / nvue 原生视图)无关,同一个项目里 tab 页可以随意混用 vue 和 nvue。

4. 为什么切换 tab 时 tabBar 不会再被误隐藏?

handleGlassTabPageHide 只在“确实离开 tab 区(比如进入二级页)”时才隐藏 tabBar;纯粹在 tab 之间切换不应该触发隐藏。这个判断依赖一个“世代计数器”:

  • 每次任意 tab 页“显示/激活” tabBar,世代号 +1;
  • onHide 时先记录当时的世代号,延时一小段时间后再检查世代号是否变化,变化了说明期间已经有新 tab 页显示,放弃隐藏。

这个计数器存放在原生单例里,而不是 JS 侧的模块变量——因为 vue 的每个 tab 页(每个 webview)运行在各自独立的 JS 上下文中,同一份 .js 文件在不同页面里会各自加载一份实例,JS 侧的模块变量并不会在页面之间共享。放在原生单例(整个 App 进程内唯一)里才能保证跨 vue / nvue 页面正确生效。业务侧无需关心这个细节,照抄第二、三节的示例即可。

5. 浮层窗口会不会挡住页面中间的点击(比如跳转二级页面的按钮)?

不会。玻璃 tabBar 挂载的浮层窗口只覆盖 tabBar(含中间凸起按钮)所在的底部条状区域,不会铺满全屏,因此页面中间、顶部区域的点击不会经过这个浮层窗口,天然不受影响。


八、隐私与权限

  • 无广告
  • 不收集、上传用户数据
  • 无需系统权限

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无需申请任何系统权限。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

本插件仅用于在 App 端绘制底部 tabBar 原生视图,不会收集、存储、上传或分享任何用户数据。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。