羽毛球工具 App HarmonyOS 6.0 实战(02/10):ArkUI 响应式布局
系列第 2 篇。本文聚焦一件事不要为手机、平板、2in1 各写一套页面而是在同一套业务页面上建立可维护的响应式外壳。一、真实问题背景羽毛球工具的使用场景天然跨设备组织者可能用手机录入人员场边可能用平板看对阵安排2in1 设备适合横屏展示实时计分。如果只按手机竖屏设计平板会显得空如果按平板写死宽布局手机又会拥挤。当前项目在entry/src/main/module.json5中声明了phone、tablet、2in1。这不是为了“多写几个设备名”而是让工程从配置层就承认多端体验是产品目标。二、目标与边界响应式适配要解决三个层次1. 设备宽度变化后页面知道自己处在哪个断点。2. 主导航在小屏用底部 Tab大屏用侧边导航。3. 业务页面内部使用相同状态不因为布局切换丢数据。边界是本文不讲折叠屏姿态、不讲跨设备流转也不讲手表端。这些属于后续协同体验文章。本文只讲当前 App 已经落地的 ArkUI 响应式基础。三、断点系统设计项目把断点监听放在common/src/main/ets/utils/BreakpointSystem.ets而不是分散到每个页面。核心思路是入口 Ability 初始化断点系统断点变化写入AppStorage(currentBreakpoint)页面通过StorageProp读取。private static smQuery: string (width600vp); private static mdQuery: string (600vpwidth840vp); private static lgQuery: string (840vpwidth1080vp); private static xlQuery: string (1080vpwidth); BreakpointSystem.smListener mediaquery.matchMediaSync(BreakpointSystem.smQuery); BreakpointSystem.smListener.on(change, (result: mediaquery.MediaQueryResult) { if (result.matches) { BreakpointSystem.updateBreakpoint(BreakpointConstants.BREAKPOINT_SM); } });这个方案的优点是低侵入。业务页面不需要自己维护窗口监听也不需要把窗口对象层层传参。只要读取currentBreakpoint就能决定布局密度、边距、列数和导航方式。四、入口页面切换导航entry/src/main/ets/pages/Index.ets是主壳页面。它用StorageLink(active_tab_index)维护当前 Tab用StorageProp(currentBreakpoint)读取断点。StorageLink(active_tab_index) currentIndex: number 0; StorageProp(currentBreakpoint) currentBreakpoint: string sm; isSmall(): boolean { return this.currentBreakpoint BreakpointConstants.BREAKPOINT_SM; }构建 UI 时小屏走底部 Tab大屏走左侧导航。业务内容通过PageContent()分发首页、对阵、计分、排名、我的页仍然是同一批 features 组件。if (this.isSmall()) { Column() { this.PageContent(); Row() { this.BottomTabItem(this.tabs[0], 0); this.BottomTabItem(this.tabs[1], 1); this.BottomTabItem(this.tabs[2], 2); this.BottomTabItem(this.tabs[3], 3); this.BottomTabItem(this.tabs[4], 4); } } } else { Row() { Column() { this.SideNavItem(this.tabs[0], 0); this.SideNavItem(this.tabs[1], 1); this.SideNavItem(this.tabs[2], 2); this.SideNavItem(this.tabs[3], 3); this.SideNavItem(this.tabs[4], 4); } this.PageContent(); } }五、业务页面如何跟随业务页面也读取currentBreakpoint。例如费用页、对阵页、排名页会根据断点调整 padding、最大宽度、卡片密度。我的页头像选择区域则进一步根据真实区域宽度计算列数避免在平板上仍然按手机三列挤在一起。相关源码包括-features/src/main/ets/home/HomePage.ets-features/src/main/ets/fee/FeeInputPage.ets-features/src/main/ets/stats/StatsPage.ets-features/src/main/ets/me/MePage.ets-common/src/main/ets/utils/BreakpointConstants.ets这类页面适配最容易踩的坑是“只改外壳不改内容”。外壳变宽后如果内部仍然写死宽度或用过大的字号平板体验依旧不自然。六、取舍与风险当前项目选择mediaquery AppStorage没有引入更复杂的设备类型判断。这样做的取舍是宽度优先逻辑简单适合工具型 App缺点是无法直接表达折叠态、悬浮窗态、外接屏状态。后续如果要做平板大屏记分牌或跨设备展示需要增加更细的窗口上下文。另一个风险是Builder中读取响应式状态时可能出现状态变化但局部组件不刷新的情况。项目的做法是尽量把依赖StorageProp的布局判断放在主 build 分支或者显式传参给 Builder。七、构建验证验证命令 D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\hvigor\bin\hvigorw.bat assembleHap --mode module -p productdefault --no-daemon验证时间2026-06-28。当前结果为BUILD SUCCESSFUL。截图来自doc/screenshots_current/phone和doc/screenshots_current/tablet用于证明不是只在代码里写了断点而是真的覆盖了手机和平板两种显示状态。八、官方参考ArkUI 响应式布局和媒体查询能力应以官方文档为准可从 HarmonyOS ArkUI 指南 进入并结合当前 SDK 的kit.ArkUIAPI 说明核对。九、工程验收清单-module.json5声明phone/tablet/2in1。-BreakpointSystem统一维护断点不在每个页面重复监听。- 主壳页面小屏底部导航大屏侧边导航。- 业务页面通过StorageProp(currentBreakpoint)跟随布局。- 手机和平板截图都能对应到同一套源码。十、小结响应式布局不是把元素变大也不是给平板加几个空白。更实用的方式是状态统一、导航换形、内容调密度。这个羽毛球工具的实现还不复杂但已经足够支撑后续跨设备文章手机控制、平板展示、手表计分都可以继续复用这套状态和页面分层。十一、下一篇衔接下一篇讲本地优先数据方案为什么这个 App 用Preferences AppStorage管住对局、费用和设置而不是让每个页面自己保存一份状态。