【OpenHarmony/HarmonyOs 】数学视界实战悬浮导航栏、沉浸光感与全新交互体验项目类型OpenHarmony / HarmonyOS ArkTS 数学学习应用项目名称数学视界关键词ArkUI、Tabs、沉浸式视觉、深色模式、底部导航、点击动效、响应式布局 ✨一、为什么要做“轻沉浸”的数学学习体验数学类应用很容易做成“工具集合”计算器、公式表、单位换算、题库练习各自独立页面之间缺少情绪连接。我的这个项目希望让用户打开应用时不只是看到一堆功能按钮而是进入一个有节奏、有反馈、有学习目标的空间。所以在 UI 设计上我重点做了三件事 用暖色光感做首页视觉入口让学习氛围更轻松 用底部导航承载高频页面首页、挑战、成就、收藏、我的 给按钮、卡片、弹窗都加上统一点击反馈让每一次操作都有回应。最终效果上应用并不是简单堆 ArkUI 组件而是围绕“今日目标 - 功能探索 - 学习数据 - 成就反馈”形成一个完整体验闭环。二、项目首页结构Tabs 承载五大核心场景项目的主入口在entry/src/main/ets/pages/Index.ets首页没有使用多个独立 Ability而是通过Tabs把几个主要场景组织到同一个主页面里。核心结构如下Tabs({barPosition: BarPosition.End,controller:this.tabController}){TabContent(){ this.buildHomePage()} .tabBar(this.buildBottomTab(0, , 首页))TabContent(){ this.buildChallengeTab()} .tabBar(this.buildBottomTab(1, , 挑战))TabContent(){ this.buildAchievementTab()} .tabBar(this.buildBottomTab(2, , 成就))TabContent(){ this.buildFavoritesTab()} .tabBar(this.buildBottomTab(3, , 收藏))TabContent(){MyPage()} .tabBar(this.buildBottomTab(4, , 我的)) } .barHeight(56).barBackgroundColor(this.getColor(#FFFDF7, #1C1C1E)) .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])这里有几个细节很关键barPosition: BarPosition.End把导航固定在底部更符合移动端单手操作习惯。TabsController为后续主动切换 Tab 留出扩展空间。expandSafeArea处理底部安全区域让导航不会被系统手势区域遮挡。自定义tabBar不用系统默认样式而是自己绘制图标、文字、角标。三、底部导航栏不只是切换页面还要承担状态表达数学视界的底部导航有一个小设计收藏 Tab 会显示收藏数量角标。这样用户不用进入收藏页也能知道自己积累了多少内容。Builder buildBottomTab(index:number,icon:string,title:string){Column({space: 2 }){Stack({alignContent: Alignment.Center }){Text(icon).fontSize(24)if(index3AppState.favorites.length 0) {Text(AppState.favorites.length 99 ? 99 : AppState.favorites.length.toString()) .fontSize(9).fontColor(#FFFFFF).backgroundColor(this.isDarkMode? #FF7A8A : #FF6B9D).borderRadius(10).padding({ left:3, right:3, top:1, bottom:1}) .offset({ x:14, y: -10}) } }Text(title).fontSize(11).fontWeight(this.currentIndexindex? FontWeight.Bold : FontWeight.Normal).fontColor(this.currentIndexindex?getThemeColors().primary : this.getColor(#AAAAAA, #666666)) .textAlign(TextAlign.Center)} }这个写法的好处是当前选中态通过字重和颜色表达用户不会迷路收藏数量直接关联AppState.favorites.length数据变化会反映到 UI深色模式下角标颜色也会调整不会出现浅色主题好看、深色主题刺眼的问题。四、沉浸光感从首页头图到进度卡片首页最醒目的区域是顶部标题和今日进度。它们都使用了比较明亮的暖粉色形成统一的品牌感。Text( 数学视界).fontSize(this.isLargeScreen? 26 : 22).fontWeight(FontWeight.Bold).fontColor(#FFFFFF)Text(探索数学的奇妙世界).fontSize(this.isLargeScreen? 14 : 12).fontColor(rgba(255,255,255,0.85))进度卡片则把“今日目标”直接视觉化Column() .width(Math.min(AppState.studyData.todayCount / AppState.studyData.dailyGoal *100,100) %) .height(100%) .backgroundColor(#FFFFFF) .borderRadius(10)这里我没有把学习数据藏在“我的”页面里而是放在首页首屏。原因很简单学习类产品最重要的是持续激励用户一打开就应该知道“今天还差多少”。页面文案也做了轻量反馈Text( AppState.studyData.todayCount AppState.studyData.dailyGoal ? 太棒了今日目标达成: 再完成 Math.max(AppState.studyData.dailyGoal - AppState.studyData.todayCount,0) 次即可达成今日目标)这类微文案虽然代码很短但对学习应用的体验很重要。它让进度条不只是一个数字而是一个“被鼓励”的瞬间。五、统一点击动效让交互有手感项目中很多按钮、卡片、弹窗关闭按钮都用了同一套点击反馈。核心思路是点击时记录当前元素的id短时间内让该元素缩小和降低透明度。pulseAnim(id:string):void{this.animId idif(this.animTimer0)clearTimeout(this.animTimer)this.animTimersetTimeout(():void{this.animId},200)asnumber}animScale(id:string):number{returnthis.animId id ?AnimScale.PRESSED:1}animAlpha(id:string):number{returnthis.animId id ?AnimAlpha.PRESSED:1}在功能卡片上使用.scale({ x: this.animScale(mod_ title), y: this.animScale(mod_ title) }).opacity(this.animAlpha(mod_ title)).animation({ duration: AnimDuration.NORMAL, curve: Curve.EaseOut}).onClick(() { this.pulseAnim(mod_ title) action() })体验上会变成这样用户点卡片时卡片轻微下压点击反馈在 200ms 左右结束动画不会抢戏但会让页面更“活”。我把这类动效抽到了AnimationUtils.ets统一维护时长、缩放值和透明度export const AnimDuration{FAST:100,NORMAL:150,SLOW:300,VERY_SLOW:500,}export const AnimScale{PRESSED:0.93,SMALL:0.95,LARGE:1.05,}export const AnimAlpha{PRESSED:0.82,DISABLED:0.5,}这样后续新增页面时不需要每个页面都重新想一套动画参数整套应用的手感会保持一致。六、深色模式不是简单反色而是主题系统项目中有一个统一的ThemeManager用于管理浅色主题、深色主题、图标背景映射和响应式工具。exportconstLightTheme: ThemeColors { primary:#FF7A8A, background:#FFF8F0, surface:#FFFFFF, textPrimary:#2C3E50, tabBarBackground:#FFFDF7, }exportconstDarkTheme: ThemeColors { primary:#FF7A8A, background:#000000, surface:#1C1C1E, textPrimary:#F2F2F7, tabBarBackground:#1C1C1E, }深色模式最容易踩坑的地方是图标背景。浅色模式下很多柔和色块很舒服但放到黑色背景上会显得发灰或发脏。因此项目里单独维护了图标背景映射exportfunctiongetIconBgColor(lightColor:string,isDark:boolean):string{if(!isDark) return lightColor const mapping IconBgColorMap[lightColor]if(mapping) return mapping.dark return adjustColorForDark(lightColor)}这样首页、我的页面、挑战页都可以复用getIconBg(bgColor:string):string{ return getIconBgColor(bgColor,this.isDarkMode)}七、状态栏同步让系统区域也融入视觉在EntryAbility.ets中应用会读取系统配置并更新主题状态同时设置状态栏颜色。onConfigurationUpdate(newConfig: Configuration): void { ThemeManager.getInstance().applyColorMode(newConfig.colorMode)this.applyStatusBar() }privateapplyStatusBar(): void {if(this.mainWindow null)returnconstisDark ThemeManager.getInstance().isDark()this.mainWindow.setWindowSystemBarProperties({ statusBarColor: isDark ?#1C1C1E:#FF9A8B, statusBarContentColor:#FFFFFF}) }这一步会让应用不只是内容区变色连状态栏也与页面主色协调起来。对于“沉浸光感”来说这种细节非常重要。八、响应式适配手机和平板都要能用项目在ThemeManager.ets中封装了ResponsiveUtilsexportclassResponsiveUtils{privatestaticreadonlyBASE_WIDTH375staticgetScreenWidth(): number {returngetScreenSize().width }staticisLargeScreen():boolean{returngetScreenSize().width 600}staticgetGridColumns(): number {returnResponsiveUtils.isLargeScreen() ?4:2} }首页里根据屏幕宽度调整字号、间距和内容宽度getisLargeScreen() {returnthis.screenWidth 600}这让应用在手机上保持紧凑在平板上则不会显得内容过小。九、实现总结这篇文章对应的主题是“悬浮导航栏、沉浸光感、全新视觉与交互体验”。在数学视界项目里我主要通过以下方式实现 使用Tabs 自定义 tabBar构建底部导航 使用暖色头部、进度卡片和轻渐变营造学习氛围 抽象AnimDuration / AnimScale / AnimAlpha统一点击动效 使用ThemeManager管理深色模式和图标背景映射 使用ResponsiveUtils处理手机和平板适配 把首页、挑战、成就、收藏、我的组成完整学习闭环。如果你也在做 OpenHarmony / HarmonyOS 应用不建议一开始就追求复杂动画。先把导航、主题、点击反馈、状态栏、安全区域这些基础体验做好应用的完成度会立刻提升一大截。