为一篇讲解 HarmonyOS7 平板双栏布局的文章绘制一张手绘笔记风信息图。主题是“平板双栏布局真

前言

邮件页、消息页、设置页在手机上用单列没问题。点列表,进详情,再返回列表,这是窄屏下很自然的路径。

但到了平板上,如果还让用户这样来回跳,就有点浪费空间了。左边明明可以一直放列表,右边直接展示详情,用户处理连续信息时会轻松很多。

双栏布局的价值不是多塞内容,而是减少不必要的页面跳转。

为什么这个问题经常被写乱

平板双栏布局真的很香 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。

所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。

双栏到底解决什么问题

为一篇关于 HarmonyOS7 平板双栏页面状态设计的文章绘制一张手绘蓝图风框架图。画面中心是状态

双栏布局适合“左边选,右边看”的场景。它不是简单把两个页面拼在一起,而是重新安排信息关系。

页面 左栏适合放什么 右栏适合放什么
邮件 收件箱列表、搜索、分类 邮件正文和操作按钮
设置 设置分类 当前设置项详情
客服会话 会话列表 聊天记录和输入框
文件管理 文件夹树 文件预览和操作

为一篇讲解 HarmonyOS7 平板双栏布局实现流程的文章绘制一张手绘流程图。内容要体现实际使用路

这类页面有一个共同点:用户会连续切换列表项。如果每次都跳详情页,再返回列表,操作成本会很高。

状态设计先想清楚

双栏页面最关键的状态不是“右栏显示什么组件”,而是当前选中了哪条数据。

这个例子里用 selectedId 作为左右栏的连接点:左栏点击邮件时只改 selectedId,右栏根据 selectedId 找当前邮件。

状态 谁修改 谁读取
selectedId 左栏列表点击 左栏选中态、右栏详情
mails 页面数据源 左栏列表、右栏兜底
currentMail() 页面内部计算 右栏标题、发件人、正文

这样做有个好处:左栏不用知道右栏怎么渲染,右栏也不用知道用户点的是哪一行。两边都围绕同一个状态工作。

先把页面目标想清楚

在真正写代码之前,先别急着盯着 API。更有用的做法是先想清楚:这个页面到底想解决什么问题,用户最在意的反馈是什么,哪些状态必须一直保持一致。

当你先把这条主线想明白,再回头看组件和状态设计,很多选择都会顺理成章。对小白来说,这一步尤其重要,因为它能帮你从“照着抄”慢慢过渡到“看得懂、改得动”。

完整 ArkTS 示例

下面是一个平板邮件页。左边固定宽度展示收件箱,右边使用 layoutWeight(1) 吃掉剩余空间。

interface MailItem28 {
  id: number
  sender: string
  subject: string
  preview: string
}

@Entry
@Component
struct TabletMailPage28 {
  @State selectedId: number = 1
  private mails: MailItem28[] = [
    { id: 1, sender: '设计团队', subject: '平板版信息架构评审', preview: '请重点看双栏下的阅读效率。' },
    { id: 2, sender: '测试同学', subject: 'HarmonyOS7 适配问题汇总', preview: '折叠屏展开后列表间距正常。' },
    { id: 3, sender: '产品经理', subject: '下周版本排期', preview: '详情页需要保留操作入口。' }
  ]

  currentMail(): MailItem28 {
    const found = this.mails.find((item: MailItem28) => item.id === this.selectedId)
    return found ? found : this.mails[0]
  }

  @Builder
  MailRow(item: MailItem28) {
    Column({ space: 6 }) {
      Text(item.sender)
        .fontSize(14)
        .fontColor('#666666')
      Text(item.subject)
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .maxLines(1)
      Text(item.preview)
        .fontSize(12)
        .fontColor('#888888')
        .maxLines(1)
    }
    .alignItems(HorizontalAlign.Start)
    .padding(14)
    .width('100%')
    .backgroundColor(this.selectedId === item.id ? '#EAF1FF' : '#FFFFFF')
    .borderRadius(10)
    .onClick(() => {
      this.selectedId = item.id
    })
  }

  build() {
    Row() {
      Column({ space: 12 }) {
        Text('收件箱')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .width('100%')
        ForEach(this.mails, (item: MailItem28) => {
          this.MailRow(item)
        }, (item: MailItem28) => item.id.toString())
      }
      .width(320)
      .height('100%')
      .padding(16)
      .backgroundColor('#F6F7F9')

      Divider()
        .vertical(true)
        .height('100%')
        .color('#E5E7EB')

      Column({ space: 16 }) {
        Text(this.currentMail().subject)
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .width('100%')
        Text(`来自:${this.currentMail().sender}`)
          .fontSize(14)
          .fontColor('#666666')
          .width('100%')
        Text('这封邮件用来演示平板双栏布局。左侧保持列表上下文,右侧直接展示详情,用户处理连续邮件时会轻松很多。')
          .fontSize(16)
          .lineHeight(26)
          .width('100%')
        Row({ space: 10 }) {
          Button('回复')
          Button('归档')
        }
        .width('100%')
      }
      .layoutWeight(1)
      .height('100%')
      .padding(24)
      .backgroundColor('#FFFFFF')
    }
    .width('100%')
    .height('100%')
  }
}

selectedId 是左右栏的桥

这段代码里,左栏点击邮件时没有直接操作右栏。它只做一件事:更新 selectedId

右栏展示什么,由 currentMail() 根据 selectedId 算出来。这个设计很适合双栏页面,因为它避免了左右组件互相调用,也让状态来源非常清楚。

如果后面要加键盘上下切换、搜索结果定位、删除邮件后自动选中下一封,也都可以围绕 selectedId 做,不需要重写整个页面结构。

左栏固定宽度,右栏吃剩余空间

示例里左栏用了 .width(320),右栏用了 .layoutWeight(1)

这组搭配在平板上很常见。左栏需要稳定宽度,因为列表项要有固定的阅读节奏;右栏内容更灵活,可以根据屏幕剩余空间展示正文、操作区、附件预览。

左栏不建议太宽。太宽会让右栏正文被压缩,尤其是竖屏平板或折叠屏展开但宽度不大的情况。实际项目里可以根据容器宽度,让左栏在 280vp360vp 之间调整。

currentMail() 为什么要兜底

真实业务里,列表数据会变化。用户可能删除当前邮件,后台可能刷新列表,搜索条件也可能让当前选中项消失。

如果右栏直接使用 this.mails.find(...)! 这种强行断言,数据一变就容易出问题。示例里找不到时返回第一封邮件,是一种简单兜底。

项目里还可以做得更细:没有邮件时显示空状态,删除当前邮件后选中下一封,搜索为空时右栏提示“没有匹配内容”。重点是不要让右栏引用一个不存在的对象。

小屏不要硬上双栏

双栏适合宽屏,不代表所有屏幕都应该双栏。手机上强行左右分栏,结果就是列表看不清,详情也看不清。

宽度 展示方式 用户路径
手机 列表页跳详情页 点开后返回
折叠屏展开 双栏 点左看右
平板横屏 双栏加操作区 连续处理内容

如果要做完整适配,可以结合 onAreaChange 或断点逻辑。窄屏时只展示列表,点击后用路由进入详情;宽屏时把列表和详情放到同一个页面。

状态仍然可以复用。窄屏详情页从路由参数拿 id,宽屏双栏用 selectedId,本质都是围绕稳定业务 id 找数据。

双栏页面容易出问题的地方

左栏选中态一定要明显。用户看右栏时,需要知道当前详情来自左边哪一项。背景色、左侧指示条、字体加粗都可以,但不要只靠很淡的颜色。

右栏操作按钮不要离正文太远。邮件页的“回复”“归档”最好跟正文保持关系,别放到屏幕最右上角让用户来回扫视。

删除当前项后要处理选中状态。否则左栏没了那封邮件,右栏还显示旧内容,用户会困惑。

新手最容易踩的坑

这一类示例最容易让人产生错觉:界面出来了,就以为已经掌握了。其实真正容易出问题的地方,通常都在效果之外,比如状态有没有收拢、失败后怎么兜底、以后要扩展时会不会牵一发动全身。

所以你练这篇内容时,别只看“现在能不能跑”,还要继续看“以后好不好改”。能把这个习惯养起来,你写出来的页面会比单纯照着示例拼出来的页面稳很多。

放进真实项目还要补什么

示例代码的重点是把核心思路讲明白,所以很多工程化细节会故意省掉。真正落到项目里时,你通常还要继续补接口联动、异常处理、边界保护、资源抽离,以及和其他页面状态之间的配合。

比较稳的做法是分三步走:先把结构和职责立住,再把真实业务接进去,最后再优化视觉和交互体验。这样改出来的页面不只是“能演示”,而是真的更接近可以长期维护的业务代码。

写在最后

HarmonyOS7 做邮件、设置、客服会话这类页面时,双栏非常实用。只要 selectedId 这条状态线写清楚,页面后续加搜索、删除、批量操作都会更稳。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐