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

在 HarmonyOS6 中实现 Material Design 3 导航栏

文章目录

    • 一、什么是 Material Design 3?
    • 二、Elevation 层级系统
      • 2.1 层级概念
      • 2.2 项目中的枚举定义
      • 2.3 Elevation 转换为 shadow 参数
    • 三、色彩系统
      • 3.1 色彩角色定义
      • 3.2 浅色与深色两套配色
      • 3.3 应用到标签栏
    • 四、主题切换
      • 4.1 切换逻辑
      • 4.2 Elevation 动态调节
    • 五、完整标签栏容器
    • 总结

一、什么是 Material Design 3?

Material Design 3(简称 M3)是 Google 的设计系统最新版本。HarmonyOS 有自己的设计语言 HDS,但很多开发者仍然选择 M3 风格来获得跨平台视觉一致性。

M3 的两个核心机制:

  • Elevation(层级):通过阴影深度表达元素的空间层次,阴影越深,元素在视觉上"悬浮"越高;
  • Color Roles(色彩角色):一套完整的色彩命名规范,每个颜色都有明确用途,浅色/深色主题切换只需换一套色值,不用改代码逻辑。

二、Elevation 层级系统

2.1 层级概念

Elevation 用 dp 值表示元素的"悬浮高度",数值越大阴影越明显:

0dp 无阴影 贴在背景上 1dp 轻微阴影 轻微抬起 2dp 卡片阴影 卡片级别 4dp 导航阴影 导航栏级别(推荐) 8dp 弹窗阴影 对话框级别 16dp 模态阴影 全屏模态级别

2.2 项目中的枚举定义

exportenumMaterialElevation{NONE=0,// 0dp - 无阴影RAISED=1,// 1dp - 轻微抬起CARD=2,// 2dp - 卡片NAVIGATION=4,// 4dp - 导航栏(底部标签栏推荐值)DIALOG=8,// 8dp - 对话框MODAL=16,// 16dp - 模态窗口}

2.3 Elevation 转换为 shadow 参数

HarmonyOS 使用shadow属性实现阴影。在MaterialTabItem组件中,Elevation 数值按以下公式映射到shadow参数:

@Componentstruct MaterialTabItem{@PropisActive:boolean;@Proptab:TabItem;@PropcolorScheme:MaterialColorScheme;@Propelevation:number;// 接收父组件传入的 Elevation 值build(){Column(){// ...图标和文字...}.shadow({// 1dp 约等于 3px 模糊半径radius:this.elevation*3,// Elevation 越高,透明度越低(阴影越深),上限 0.25color:`rgba(0, 0, 0,${Math.min(0.05+this.elevation*0.02,0.25)})`,offsetX:0,offsetY:this.elevation*1.5// 垂直偏移与 Elevation 成正比})}}

代码说明:

  • radius: elevation * 3让阴影随层级线性扩大,层级越高阴影越柔和;
  • Math.min(0.05 + elevation * 0.02, 0.25)控制阴影透明度,设置上限0.25防止阴影过重;
  • offsetY: elevation * 1.5让阴影随层级向下偏移,模拟光线从上方照射的效果。

三、色彩系统

3.1 色彩角色定义

// entry/src/main/ets/types/TabBarTypes.etsexportinterfaceMaterialColorScheme{primary:ResourceColor;// 主色:选中状态背景primaryVariant:ResourceColor;// 主色变体secondary:ResourceColor;// 次要色secondaryVariant:ResourceColor;background:ResourceColor;// 页面背景色surface:ResourceColor;// 卡片/标签栏背景色error:ResourceColor;// 错误色success:ResourceColor;warning:ResourceColor;onPrimary:ResourceColor;// 主色上的文字/图标颜色onSecondary:ResourceColor;onBackground:ResourceColor;// 背景上的文字颜色onSurface:ResourceColor;// 表面色上的文字颜色}

代码说明:以on开头的颜色表示"放在该背景上的前景色"。比如onPrimary是放在primary色背景上的文字颜色,onSurface是放在surface色背景上的文字颜色。这种命名约定让颜色用途一目了然。

3.2 浅色与深色两套配色

exportconstMaterialLightColorScheme:MaterialColorScheme={primary:'#6200EE',// 深紫色作为主色primaryVariant:'#3700B3',secondary:'#03DAC6',secondaryVariant:'#018786',background:'#FAFAFA',surface:'#FFFFFF',error:'#B00020',success:'#4CAF50',warning:'#FF9800',onPrimary:'#FFFFFF',// 深紫背景上用白色文字onSecondary:'#000000',onBackground:'#000000',onSurface:'#000000',};exportconstMaterialDarkColorScheme:MaterialColorScheme={primary:'#BB86FC',// 浅紫色,在深色背景上可读性好primaryVariant:'#3700B3',secondary:'#03DAC6',secondaryVariant:'#03DAC6',background:'#121212',// 深色背景surface:'#1E1E1E',error:'#CF6679',success:'#81C784',warning:'#FFB74D',onPrimary:'#000000',// 浅紫背景上用黑色文字onSecondary:'#000000',onBackground:'#FFFFFF',onSurface:'#FFFFFF',};

代码说明:深色模式下primary从深紫#6200EE换成浅紫#BB86FC,原因是深色模式背景很深,深紫在其上会显得不清晰;onPrimary也相应从白色换为黑色,保证对比度。

3.3 应用到标签栏

// MaterialTabItem 组件中的颜色使用build(){Column(){// 图标颜色:选中时用 onPrimary,未选中时用 onSurfaceSymbolGlyph(this.isActive?this.tab.activeIcon:this.tab.icon).fontSize(24).fontColor(this.isActive?[this.colorScheme.onPrimary]// 选中:主色背景上的文字色:[this.colorScheme.onSurface]// 未选中:表面色上的文字色)// 图标缩放动画:选中时放大 10%.scale({x:this.isActive?1.1:1,y:this.isActive?1.1:1,}).animation({duration:200,curve:Curve.EaseOut})// 标签文字Text(this.tab.title).fontSize(12).fontColor(this.isActive?this.colorScheme.onPrimary:this.colorScheme.onSurface).fontWeight(this.isActive?FontWeight.Medium:FontWeight.Normal).margin({top:4})// 选中指示条:宽度从 0 动画展开到 32Row().width(this.isActive?32:0).height(3).backgroundColor(this.colorScheme.onPrimary).borderRadius(1.5).margin({top:4}).animation({duration:200,curve:Curve.FastOutSlowIn})}.width(64).height(56).backgroundColor(this.isActive?this.colorScheme.primary:Color.Transparent).borderRadius(16)// ...shadow 属性见上文}

代码说明:

  • 选中状态下整个Column背景变为primary色,图标和文字颜色切换为onPrimary,形成色彩组合一致的选中效果;
  • 指示条宽度从032配合.animation(),ArkUI 会自动插值生成展开动画;
  • Curve.FastOutSlowIn是 M3 推荐的动画曲线,起步快、收尾慢,符合物理直觉。

四、主题切换

4.1 切换逻辑

@Entry@Componentstruct MaterialTabsDemo{@StateisDarkMode:boolean=false;@StatecolorScheme:MaterialColorScheme=MaterialLightColorScheme;// 点击主题切换按钮时调用privatetoggleTheme(){// 用 animateTo 包裹状态更新,让颜色变化有过渡动画animateTo({duration:300,curve:Curve.EaseInOut},()=>{this.isDarkMode=!this.isDarkMode;this.colorScheme=this.isDarkMode?MaterialDarkColorScheme:MaterialLightColorScheme;});}}

代码说明:整个颜色方案是一个对象引用,切换主题只需把colorScheme指向另一个预设对象,所有依赖它的子组件会自动重新渲染。用animateTo包裹赋值操作,让颜色变化有平滑过渡。

4.2 Elevation 动态调节

本项目提供了一个 Elevation 选择器,可以实时预览不同阴影深度的效果:

// Elevation 选择器 UIForEach([{label:'0',value:MaterialElevation.NONE},{label:'1',value:MaterialElevation.RAISED},{label:'2',value:MaterialElevation.CARD},{label:'4',value:MaterialElevation.NAVIGATION},{label:'8',value:MaterialElevation.DIALOG},],(item:ElevationItem)=>{// ElevationItem 是文件顶部定义的 interfaceText(item.label).fontSize(13).fontWeight(this.elevation===item.value?FontWeight.Medium:FontWeight.Normal).fontColor(this.elevation===item.value?this.colorScheme.primary:this.colorScheme.onSurface).padding({left:8,right:8,top:4,bottom:4}).borderRadius(12).backgroundColor(this.elevation===item.value?this.colorScheme.primary:Color.Transparent).onClick(()=>{animateTo({duration:200},()=>{this.elevation=item.value;});})})

代码说明:

  • 这里用到了本地定义的interface ElevationItem,而不是Record<string, number>,原因是 ArkTS 规范禁止在回调函数类型声明处直接使用对象字面量类型,必须先声明为具名接口;
  • 每个 Elevation 选项在点击后通过animateTo使阴影变化有动画效果。

五、完整标签栏容器

// 底部 Material 标签栏容器Row(){ForEach(this.tabs,(tab:TabItem,index:number)=>{MaterialTabItem({isActive:this.currentIndex===index,tab:tab,colorScheme:this.colorScheme,elevation:this.elevation}).onClick(()=>{this.switchTab(index);})})}.width('100%').height(64).padding({bottom:8}).backgroundColor(this.colorScheme.surface)// 标签栏背景用 surface 色.justifyContent(FlexAlign.SpaceEvenly).shadow({radius:12,// 深色模式下阴影更深,浅色模式下更轻color:this.isDarkMode?'rgba(0, 0, 0, 0.4)':'rgba(0, 0, 0, 0.08)',offsetX:0,offsetY:-4// 向上偏移,阴影出现在标签栏顶部边缘}).expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.BOTTOM])

代码说明:offsetY: -4让阴影出现在标签栏上方,产生"内容从下方滑入"的层次感;深色模式下阴影透明度从0.08提高到0.4,因为深色背景上浅色阴影几乎不可见。

总结

Material Design 3 的精髓在于"系统性":颜色不是随手选的,而是有角色分工;阴影不是装饰性的,而是有层级含义。在 HarmonyOS 里把这套规范落地,核心工作就两件事——把 Elevation 映射成shadow参数,把色彩角色映射成一个可以整体切换的配色对象。把这两个部分搭建好之后,浅色/深色主题切换、阴影层级调整都只是换一个变量的事,整个代码结构会变得非常清晰好维护。

http://www.jsqmd.com/news/680267/

相关文章:

  • 2026年评价高的工地红模板批发/覆膜建筑木模板/文旅项目异形模板/异形结构木模板加工厂家对比推荐 - 行业平台推荐
  • 2026专业工业污水处理设备/废气治理设备厂家推荐:反渗透水处理设备、工业污水一体化处理及中水回用设备生产供应 - 栗子测评
  • 保姆级教程:在Windows 10上用Anaconda3和Cuda 10.1,为你的Tesla V100显卡配置PyTorch 1.8深度学习环境
  • 技术文档写作风格 - 图形
  • 数据关联性与趋势发现(使用千问)
  • 2026年靠谱的高端开尾拉链/高端拉链公司对比推荐 - 品牌宣传支持者
  • 2026年比较好的安徽单晶硅压力变送器/陶瓷电容压力变送器/安徽扩散硅压力变送器/不锈钢壳体压力变送器推荐品牌厂家 - 品牌宣传支持者
  • 告别黑窗口:用QT+STKX为你的航天仿真软件做个现代化GUI界面(实战分享)
  • FreeCAD 六角扳手建模教程
  • 避坑指南:在全志T113-S3的Buildroot系统中搞定移远EC200T/EC200A USB上网(RNDIS/ECM)与串口驱动
  • 2026年Q2仓储塑料波纹管选购指南:穿线波纹管、船舶包塑金属软管、设备线束塑料波纹管、软管快速接头、金属软管接头选择指南 - 优质品牌商家
  • 2026年质量好的进口松木建筑木方稳定供货厂家推荐 - 行业平台推荐
  • 如何用3步实现效率突破:开源智能工具重构网盘资源获取体验
  • RPC项目
  • 全自动切管机厂家哪家好?2026全自动切管机厂家/张家港全自动切管机厂家推荐:昊泰克领衔,一站式全自动切管机定制厂家合集 - 栗子测评
  • AI Agent的抗干扰能力:复杂环境下的决策稳定性设计
  • STM32F103跑LVGL?手把手教你用Keil MDK5和外部SRAM搞定移植(附DMA加速技巧)
  • 2026年靠谱的广东古建斗拱木模板/广东覆膜建筑木模板优质公司推荐 - 品牌宣传支持者
  • 2026年口碑好的气源处理不锈钢减压阀/气源处理不锈钢三联件/气源处理减压阀/宁波气源处理减压阀横向对比厂家推荐 - 品牌宣传支持者
  • 关键指标自动提取(使用千问)
  • 别再死记硬背SPI引脚了!一张图搞懂MOSI/MISO/SCLK/CS的别名和实战接线(附逻辑分析仪调试技巧)
  • 2026年隧道盾构泥浆离心机技术选型与现场运维指南:泥浆固液分离、淤泥固液分离、煤矿离心机、离心式固液分离、餐厨垃圾固液分离选择指南 - 优质品牌商家
  • 耗时小时分,理想的AI编程助手Claude Code 部署与本地自托管模型配置
  • 【新人专属教程】本地 AI 自动化工具 OpenClaw Windows 部署全流程(含最新版安装包)
  • 2026杭州抖音客服外包:杭州全链路客服外包、杭州售前客服、杭州外包客服团队、杭州天猫客服外包、杭州客服外包推荐选择指南 - 优质品牌商家
  • 别再死记硬背PDR/PPDR了!用这个‘攻防时间赛跑’比喻,5分钟搞懂网络安全核心模型
  • 串口电平标准及设计原理
  • Windows Cleaner:如何用这款终极免费工具快速解决C盘爆红问题
  • 2026年行业内知名的印刷粘箱打包联动线源头厂家推荐分析,印刷粘箱打包联动线厂家哪个好 - 品牌推荐师
  • ROS Action从入门到精通:一个自定义Timer.action的完整开发、编译与调试避坑指南