积分中心
从一套页面到多种窗口:HarmonyOS 7 ArkUI 自适应工作台实践
头像 ccai 2026-09-10 11:29:54    发布
2407 浏览 3 点赞 0 收藏

摘要

手机、平板、折叠屏和分屏窗口的可用宽度差异很大,固定宽高的页面在换屏或旋转后容易出现按钮挤压、卡片留白过多和滚动区域不合理等问题。本文以一个任务工作台为例,使用 ArkUI 的栅格布局能力,根据窗口宽度调整页面结构,并用少量状态处理交互差异。文章重点讨论布局规则、字体放大、安全区域和测试边界,不把“适配所有设备”作为未经验证的结论。

一、先把“手机版和平板版”改成窗口规则

最初的工作台只按约 360vp 宽的手机窗口设计,页面包含:

  • 顶部标题和新增按钮;
  • 中间的汇总卡片;
  • 快捷操作区域;
  • 最近任务列表。

当窗口变宽后,汇总卡片变成很长的横条;在折叠屏半屏状态下,标题和右侧按钮会争抢空间。问题不在于某一个控件的边距,而在于页面把“设备型号”当成了布局依据。

这次调整制定了三个规则:

  1. 使用窗口可用宽度,而不是判断具体机型;
  2. 窄窗口优先保证可操作性,宽窗口再利用多列空间;
  3. 旋转、分屏和字体放大后,重要内容不能被裁切。

断点 360vp、600vp 和 840vp 只是本例的起始值,正式项目应根据实际页面内容和目标设备重新验证。

二、用 GridRow/GridCol 搭建页面骨架

下面只展示核心布局。GridRow、GridCol 的对象参数和断点类型可能随 SDK 小版本变化,实际开发请以当前 DevEco Studio 的类型提示为准。

import { BreakpointsReference } from '@kit.ArkUI'

interface TaskItem {
  id: string
  title: string
  done: boolean
}

@Entry
@Component
struct WorkbenchPage {
  @State private compact: boolean = true
  @State private tasks: TaskItem[] = [
    { id: '1', title: '整理本周会议记录', done: false },
    { id: '2', title: '检查发布清单', done: true }
  ]

  build() {
    Column({ space: 12 }) {
      Row() {
        Text('今日工作台')
          .fontSize(this.compact ? 22 : 28)
          .fontWeight(FontWeight.Medium)

        Blank()

        if (!this.compact) {
          Button('批量操作')
            .height(40)
            .onClick(() => this.openBatchAction())
        }

        Button('新增')
          .height(40)
          .onClick(() => this.addTask())
      }
      .width('100%')

      GridRow({
        columns: 12,
        gutter: { x: 12, y: 12 },
        breakpoints: {
          value: ['360vp', '600vp', '840vp'],
          reference: BreakpointsReference.WindowSize
        }
      }) {
        GridCol({ span: { xs: 12, sm: 12, md: 7, lg: 8 } }) {
          SummaryCard({ taskCount: this.tasks.length })
        }

        GridCol({ span: { xs: 12, sm: 12, md: 5, lg: 4 } }) {
          QuickActions({ compact: this.compact })
        }

        GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {
          RecentTaskList({ items: this.tasks })
        }
      }
      .width('100%')
      .onAreaChange((_oldArea, area) => {
        this.updateCompact(area.width)
      })
    }
    .width('100%')
    .height('100%')
    .padding({ left: 16, right: 16, top: 12, bottom: 12 })
  }

  private updateCompact(width: number): void {
    const next = width < 600
    if (next !== this.compact) {
      this.compact = next
    }
  }

  private addTask(): void {
    const item: TaskItem = {
      id: makeId(), // 项目中使用可靠的唯一 ID 生成方式
      title: '未命名任务',
      done: false
    }
    this.tasks = [item, ...this.tasks]
  }

  private openBatchAction(): void {
    // 交给业务层处理
  }
}

这个布局有几个值得注意的地方:

  • 每个断点下的 GridCol.span 总和不能超过 12;
  • 重要操作“新增”在窄屏仍保留文字,不只显示图标;
  • 列表使用业务 ID 作为 key,不使用数组下标;
  • 卡片内部尽量使用 width('100%'),避免继续写死宽度;
  • 页面只保留一个主要滚动容器,减少嵌套滚动冲突。

三、窄屏和宽屏的交互不必完全相同

自适应不只是改变列数,还包括交互取舍。

窄屏下可以:

  • 将“批量操作”收进更多菜单;
  • 减小标题字号,但保留足够的可读性;
  • 保留主要按钮的文字和触控高度;
  • 让表单在键盘弹出时仍可滚动到提交按钮。

宽屏下可以:

  • 将汇总和快捷操作并排;
  • 增加详情栏或预览区域;
  • 让列表占满下一行;
  • 在主从布局中同时显示列表和详情。

字体放大时也要重新检查卡片高度。不能因为默认字号下没有问题,就假设辅助功能设置下仍然不会溢出。

四、测试矩阵

发布前至少覆盖以下窗口和状态:


类别用例
窗口宽度360、600、840、1200vp 附近的窗口
方向竖屏、横屏
形态折叠半屏、展开、左右分屏
字体默认字号、放大字号
数据空列表、单条、几十条
系统区域状态栏、导航区域、键盘弹出
操作新增、删除、返回、重复点击

验收重点不是“看起来差不多”,而是:

  • 是否出现横向滚动;
  • 最后一条列表项是否被安全区域遮挡;
  • 断点切换时是否出现明显跳动;
  • 窗口连续拖动时是否产生大量无意义重绘;
  • 主要操作是否仍然容易找到和点击。

五、容易忽略的坑

第一,不能直接照搬 Web 端的 Bootstrap 断点规则。ArkUI 的窗口参考系、单位和对象参数应以当前 SDK 文档为准。

第二,不能把某个机型的状态栏高度写成固定值。应使用当前 SDK 提供的安全区域能力。

第三,onAreaChange 在窗口连续变化时可能频繁触发。实际项目中只在跨过阈值时更新状态,避免每次尺寸变化都修改多个状态字段。

第四,响应式布局不能代替真实设备验证。栅格只是骨架,图片比例、文本长度、输入法和系统字体仍需要在目标设备上检查。

六、总结

这次实践的重点是把“手机版、平板版、折叠屏版”改写成可验证的窗口规则。先用 GridRow/GridCol 建立稳定骨架,再用少量状态处理交互差异,通常比为每一种设备维护一套页面更容易测试和维护。


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255