HarmonyOS 7.0 / API 26 DynamicLayout 审核自检:多设备截图里最容易暴露的布局问题
上架前最怕什么
HarmonyOS 应用做多设备适配时,开发阶段看起来没问题,不代表上架截图也没问题。手机竖屏、折叠屏展开、平板横屏、鸿蒙电脑窗口态,每一种截图都会把页面布局问题放大。DynamicLayout 能帮助页面适配不同尺寸,但如果断点、状态和安全区没有处理好,截图里会直接暴露留白、遮挡、文字截断、按钮漂移这些问题。
这篇按 **HarmonyOS 7.0 / API 26** 的多设备开发场景来讲,重点放在上架前自检。不是写一套审核规则,而是从开发者角度列出最容易被截图暴露的问题,并给出可以落地的检查方式。
为什么截图比本地调试更容易暴露问题
本地调试时,开发者经常只看一个设备、一个窗口尺寸。上架材料和多设备展示不同,它会把页面放到多个尺寸里看。很多问题只有切到大屏或折叠屏才出现。
| 问题 | 手机上表现 | 大屏/折叠屏上表现 |
| 断点切换不完整 | 看不出来 | 左右面板宽度异常 |
| 状态没有迁移 | 返回时偶发 | 展开后详情为空 |
| 安全区没处理 | 顶部略挤 | 标题栏、悬浮按钮遮挡内容 |
| 文案没做收缩 | 只换行 | 卡片标题撑破布局 |
| 图片比例没固定 | 偶尔抖动 | 大屏下拉伸明显 |
所以我会在发布前做一套截图矩阵,不只看“能不能运行”,还要看“截图能不能交出去”。
先定义截图矩阵
截图矩阵不要写在文档里就结束,最好写成代码配置。这样每次改页面都能复用。
type ScreenshotDevice = 'phone' | 'foldableExpanded' | 'tablet' | 'desktopWindow'; type Orientation = 'portrait' | 'landscape'; interface ScreenshotCase { id: string; device: ScreenshotDevice; orientation: Orientation; widthVp: number; heightVp: number; requiredPanels: string[]; riskFocus: string[]; } export const DynamicLayoutScreenshotMatrix: ScreenshotCase[] = [ { id: 'phone-portrait-main', device: 'phone', orientation: 'portrait', widthVp: 390, heightVp: 780, requiredPanels: ['list'], riskFocus: ['title-overflow', 'bottom-button-safe-area'] }, { id: 'foldable-expanded-master-detail', device: 'foldableExpanded', orientation: 'landscape', widthVp: 980, heightVp: 760, requiredPanels: ['list', 'detail'], riskFocus: ['panel-width', 'selected-state', 'hinge-spacing'] }, { id: 'tablet-landscape-detail', device: 'tablet', orientation: 'landscape', widthVp: 1120, heightVp: 820, requiredPanels: ['list', 'detail'], riskFocus: ['large-blank-area', 'image-ratio', 'dialog-position'] }, { id: 'desktop-window-three-pane', device: 'desktopWindow', orientation: 'landscape', widthVp: 1440, heightVp: 900, requiredPanels: ['navigation', 'list', 'detail'], riskFocus: ['three-pane-density', 'floating-layer-anchor', 'keyboard-focus'] } ];这张矩阵解决的是“到底要测哪些尺寸”的问题。没有矩阵时,测试很容易变成随手拖一下窗口,看起来差不多就过了。正式上架前不能这样。
案例一:断点错位导致大屏留白
第一个常见问题是断点错位。比如 900vp 以上应该进入主从结构,但页面仍然按单栏渲染,右侧就会出现大片空白。
type LayoutMode = 'singleColumn' | 'masterDetail' | 'threePane'; interface LayoutAuditResult { passed: boolean; caseId: string; layoutMode: LayoutMode; problems: string[]; } export class DynamicLayoutScreenshotAuditor { auditLayout(screenshotCase: ScreenshotCase, actualMode: LayoutMode): LayoutAuditResult { const problems: string[] = []; if (screenshotCase.widthVp >= 1200 && actualMode !== 'threePane') { problems.push('大窗口应进入三栏结构,当前仍是 ' + actualMode); } if (screenshotCase.widthVp >= 900 && screenshotCase.widthVp < 1200 && actualMode === 'singleColumn') { problems.push('中大屏应进入主从结构,当前仍是单栏'); } if (screenshotCase.widthVp < 600 && actualMode !== 'singleColumn') { problems.push('窄屏不应强行展示双栏或三栏'); } return { passed: problems.length === 0, caseId: screenshotCase.id, layoutMode: actualMode, problems }; } }复现实验 A
const auditor = new DynamicLayoutScreenshotAuditor(); const tabletCase = DynamicLayoutScreenshotMatrix.find(item => item.id === 'tablet-landscape-detail')!; const result = auditor.auditLayout(tabletCase, 'singleColumn'); console.info(result.passed); // false console.info(result.problems); // 中大屏应进入主从结构,当前仍是单栏这个实验能抓出截图里的大面积留白。它不是视觉小问题,而是布局模式没有按设备尺寸切换。
案例二:浮层锚点在截图里错位
第二个问题是浮层。开发时点一下没问题,但窗口尺寸变化后,浮层可能还挂在旧锚点上。截图里会看到菜单漂在奇怪的位置。
interface OverlayAuditInput { visible: boolean; anchorPanel: string; anchorRect: { x: number; y: number; width: number; height: number }; viewport: { width: number; height: number }; } interface OverlayAuditResult { passed: boolean; problems: string[]; } export class OverlayScreenshotAuditor { audit(input: OverlayAuditInput): OverlayAuditResult { if (!input.visible) { return { passed: true, problems: [] }; } const problems: string[] = []; const rect = input.anchorRect; if (rect.x < 0 || rect.y < 0) { problems.push('浮层锚点超出左上边界'); } if (rect.x + rect.width > input.viewport.width) { problems.push('浮层锚点超出右侧边界'); } if (rect.y + rect.height > input.viewport.height) { problems.push('浮层锚点超出底部边界'); } return { passed: problems.length === 0, problems }; } }复现实验 B
const overlayAuditor = new OverlayScreenshotAuditor(); const overlayResult = overlayAuditor.audit({ visible: true, anchorPanel: 'detail', anchorRect: { x: 1180, y: 720, width: 320, height: 240 }, viewport: { width: 1280, height: 800 } }); console.info(overlayResult.passed); // false console.info(overlayResult.problems); // 右侧或底部越界这类问题很容易被忽略,因为本地开发时浮层只看一次。但截图矩阵一跑,大屏、分屏、小窗都会暴露出来。
自检流程建议
我会把上架前的 DynamicLayout 自检分成五步:
- 跑截图矩阵,确认每个尺寸对应正确布局模式;
- 检查标题、按钮、卡片文案是否截断;
- 检查列表、详情、导航面板是否有大面积空白;
- 检查弹窗、菜单、悬浮按钮是否越界;
- 切换一次窗口尺寸,确认状态不丢、接口不重复请求。
这套流程不复杂,但能抓住大多数多设备截图问题。
页面层如何配合
@Component struct ReviewReadyDynamicLayoutPage { @State private currentMode: LayoutMode = 'singleColumn'; private auditor = new DynamicLayoutScreenshotAuditor(); beforeCapture(caseInfo: ScreenshotCase) { const result = this.auditor.auditLayout(caseInfo, this.currentMode); if (!result.passed) { console.error('layout audit failed: ' + JSON.stringify(result.problems)); } } build() { Column() { Text('DynamicLayout Review Check') .fontSize(18) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .width('100%') .height('100%') } }这里的 beforeCapture 可以理解成截图前的自检入口。真实项目里可以放到测试脚本、截图脚本或调试面板里,不一定放在正式页面逻辑里。
结论
DynamicLayout 适配做完以后,不要只在一个设备上看效果。HarmonyOS 7.0 / API 26 的多设备场景里,截图矩阵很重要。手机、折叠屏、平板和窗口态都要看,尤其要盯住断点、状态、浮层、安全区和文案截断。
如果页面在截图矩阵里稳定,后面进入上架材料准备和审核自检时会省很多时间。反过来,如果截图阶段才发现大屏留白、浮层错位和状态丢失,返工成本会很高。