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)。
这组搭配在平板上很常见。左栏需要稳定宽度,因为列表项要有固定的阅读节奏;右栏内容更灵活,可以根据屏幕剩余空间展示正文、操作区、附件预览。
左栏不建议太宽。太宽会让右栏正文被压缩,尤其是竖屏平板或折叠屏展开但宽度不大的情况。实际项目里可以根据容器宽度,让左栏在 280vp 到 360vp 之间调整。
currentMail() 为什么要兜底
真实业务里,列表数据会变化。用户可能删除当前邮件,后台可能刷新列表,搜索条件也可能让当前选中项消失。
如果右栏直接使用 this.mails.find(...)! 这种强行断言,数据一变就容易出问题。示例里找不到时返回第一封邮件,是一种简单兜底。
项目里还可以做得更细:没有邮件时显示空状态,删除当前邮件后选中下一封,搜索为空时右栏提示“没有匹配内容”。重点是不要让右栏引用一个不存在的对象。
小屏不要硬上双栏
双栏适合宽屏,不代表所有屏幕都应该双栏。手机上强行左右分栏,结果就是列表看不清,详情也看不清。
| 宽度 | 展示方式 | 用户路径 |
|---|---|---|
| 手机 | 列表页跳详情页 | 点开后返回 |
| 折叠屏展开 | 双栏 | 点左看右 |
| 平板横屏 | 双栏加操作区 | 连续处理内容 |
如果要做完整适配,可以结合 onAreaChange 或断点逻辑。窄屏时只展示列表,点击后用路由进入详情;宽屏时把列表和详情放到同一个页面。
状态仍然可以复用。窄屏详情页从路由参数拿 id,宽屏双栏用 selectedId,本质都是围绕稳定业务 id 找数据。
双栏页面容易出问题的地方
左栏选中态一定要明显。用户看右栏时,需要知道当前详情来自左边哪一项。背景色、左侧指示条、字体加粗都可以,但不要只靠很淡的颜色。
右栏操作按钮不要离正文太远。邮件页的“回复”“归档”最好跟正文保持关系,别放到屏幕最右上角让用户来回扫视。
删除当前项后要处理选中状态。否则左栏没了那封邮件,右栏还显示旧内容,用户会困惑。
新手最容易踩的坑
这一类示例最容易让人产生错觉:界面出来了,就以为已经掌握了。其实真正容易出问题的地方,通常都在效果之外,比如状态有没有收拢、失败后怎么兜底、以后要扩展时会不会牵一发动全身。
所以你练这篇内容时,别只看“现在能不能跑”,还要继续看“以后好不好改”。能把这个习惯养起来,你写出来的页面会比单纯照着示例拼出来的页面稳很多。
放进真实项目还要补什么
示例代码的重点是把核心思路讲明白,所以很多工程化细节会故意省掉。真正落到项目里时,你通常还要继续补接口联动、异常处理、边界保护、资源抽离,以及和其他页面状态之间的配合。
比较稳的做法是分三步走:先把结构和职责立住,再把真实业务接进去,最后再优化视觉和交互体验。这样改出来的页面不只是“能演示”,而是真的更接近可以长期维护的业务代码。
写在最后
HarmonyOS7 做邮件、设置、客服会话这类页面时,双栏非常实用。只要 selectedId 这条状态线写清楚,页面后续加搜索、删除、批量操作都会更稳。
更多推荐



所有评论(0)