【HarmonyOS 7 平行视界深度实战】05 1:1、1:2、2:1 分栏比例如何分配
前言
分类入口已经稳定留在左侧,右侧也能显示选中的内容,阅读时却仍然不顺:目录里的长标题被截断,正文每行又容纳不了多少文字。把分隔线向左移动,正文获得了更多空间,目录可能随即变得难以辨认。页面关系确定以后,开发者还需要根据两边的任务分配宽度。
文档目录与正文适合用来判断这种取舍。用户先在目录中找到章节,再把注意力转向阅读,因此两边需要的空间会随操作变化。比例配置要回答两个问题:应用启动时采用哪一档,以及用户能否在阅读中自己调整。判断依据需要来自相同窗口、字体和内容下的比较。

一、目录和正文各需要保留多少信息
决定比例时,可以从用户能否完成一次操作开始。
目录必须让人找到目标章节,正文必须让人连续读懂内容。如果目录只剩几个相同的开头,用户需要反复打开详情才能分辨条目,给正文增加的空间就以查找成本为代价。反过来,目录很宽而正文被挤成窄条,也会让阅读不断中断。
大家可以用项目的真实标题约定最低条件,例如最长章节名称最多换成两行、主要操作文字完整、正文不会在常见字号下产生过多横向滚动。这些条件来自当前内容和设计选择,并非系统给出的统一标准。字号、图标、缩进和内边距不同,相同栏宽能承载的信息也不同,所以不宜只记录一个脱离页面的宽度数值。
需要比较的内容应当先固定下来。短标题全部正常时,三种比例可能没有区别;加入最长章节名称以后,左栏的限制才会出现。正文同样要保留实际阅读的段落长度,不能为某一档临时删短文字。完成这一步以后,三档配置才面对同一个问题。
内容样本还应包含容易混淆的名称。例如,同一组章节都以设备管理开头,区别集中在标题后半段,左栏缩窄就可能隐藏用户真正需要辨认的部分。此时只统计标题显示了多少个字还不够,还要让用户能够区分目标章节。比较条件因此需要围绕查找任务制定,不能把文本没有溢出容器当作唯一通过条件。
| 比例 | 空间分配 | 先观察哪里 | 需要排除的问题 |
|---|---|---|---|
| 1:1 | 两侧相同 | 两栏是否都能完成主要动作 | 平均分配后,两边仍然拥挤 |
| 1:2 | 右侧约为左侧两倍 | 目录名称与点击区域 | 阅读变宽,章节却难以区分 |
| 2:1 | 左侧约为右侧两倍 | 正文行长与操作区 | 列表信息完整,详情却无法操作 |
1:1 便于建立对照起点,但最终比例仍取决于内容。目录配长文可以先尝试 1:2,因为右侧承担持续阅读;密集数据列表配简短预览则可以尝试 2:1。邮件列表与邮件内容都需要保留多项信息,可以从 1:1 开始。这些是根据任务作出的起始判断,比较以后仍可能改变。
比例描述两个区域的相对宽度,不等于正文实际可排版的宽度。系统区域、分隔区域和页面内边距还会占用空间,同样的 1:2 放进不同大小的窗口,也会得到不同结果。因此,即使分隔线位置符合预期,仍要回到标题和正文检查可用性,不能用比例数字代替页面观察。
如果三档都无法同时满足两侧要求,需要回到信息安排检查原因。目录里是否同时塞入了正文摘要、更新时间和多个操作,详情是否保留了本可以放到其他位置的固定工具区,这些都会消耗空间。开发者可以按任务优先级减少同屏信息,再重新比较比例;这样的调整改变了页面内容基线,应该另记一轮结果,不能继续与之前的截图直接混比。
需要把这个选择写入配置时,API 26 提供 wideSplit 与 squareSplit,分别承载长方形宽窗口和方形宽窗口的设置。内部的 ratio 是两个正整数以空格和竖线分隔的字符串,例如 1 | 2。比例范围为 1:2 到 2:1,未配置时默认为 1:1;超出范围的数值按范围边界处理。工程中应直接填写预期范围内的值,避免让越界处理掩盖配置错误。
"wideSplit": {
"ratio": "1 | 1"
},
"squareSplit": {
"ratio": "1 | 1"
},
两处都使用 1 | 1,可以让首次比较从相同分配开始。修改到另外两档时,同时核对这两个分支,防止窗口形状变化后仍采用旧比例。实际项目可以让长方形窗口使用 1:2、方形窗口使用 1:1,但每个分支都需要有自己的内容检查结果;窗口转换本身不需要为了比例再创建一条路由。
分支选择与比例选择还需要分别确认。开发者在长方形窗口修改了 wideSplit,如果实际窗口已经接近方形,观察到的画面就可能来自 squareSplit。遇到配置似乎没有变化时,先保存窗口宽高和两处配置,再确认观察对象。每次只凭横屏这一称呼识别窗口,容易遗漏形状条件,从而把分支命中问题误判为比例失效。
比较过程中还应保持分隔线颜色不变。splitDividerColor 使用包含 light、dark 的对象,颜色格式为 #AARRGGBB。当前页面保留以下配置,便于识别两侧边界:
"splitDividerColor": {
"light": "#FFD7DCE8",
"dark": "#FF4A5060"
}
两个值分别服务浅色与深色模式,不能把整个字段改成一个颜色字符串。颜色可以帮助定位边界,但无法修复内容截断。把这些外观条件固定以后,观察重点就能留在每次比例变化失去了什么信息。
二、用同一阅读页面比较三档比例
目录与正文使用同一个 Navigation,右侧内容由 ArticlePage 提供。保留这组关系以后,比例比较只需要更换 EasyGo 值,无须复制三套页面。当前启动代码主动压入正文页,三组配置都沿用同一个入口:
aboutToAppear(): void {
this.pageStack.pushPathByName('ArticlePage', null)
}
这段代码保留了既有的 aboutToAppear() 写法,正式版能够编译,但首次显示仍需要单独检查。Navigation 的初始化约束提示,在页面尚未构建完成时执行栈操作可能导致白屏或跳转失败,因此这个启动位置不能作为现有项目的通用接入建议。业务工程应结合自己的页面就绪时机安排首次跳转,并防止重新出现时重复入栈;尚未取得运行记录前,不能假定冷启动已经稳定。
只有确认进入同一正文页以后,三档画面才有比较价值。当前 Navigation 保留 NavigationMode.Stack,空间分配交给 EasyGo。每次修改两处 ratio,重新构建并安装同一组页面,再回到相同窗口尺寸和阅读起点。如果目标页没有打开,需要先处理初始化问题,扩大右栏不会改变这次跳转结果。
比较 1:1 时,可以记录左栏最长标题占几行、首屏看见多少条目录,以及右栏段落是否能连续阅读。切换到 1:2 后,重点检查左栏让出空间的代价:条目是否变得难以区分,原本可见的说明是否被挤到下一屏。再切换到 2:1,检查正文是否因行长缩短而频繁换行。这样的记录能够解释选择原因,也能指出需要继续修改的是比例还是内容布局。
记录时要把不同类型的失败分开。标题换行但仍能辨认,可能符合产品要求;操作按钮被裁掉,用户就无法完成任务。两者不能只记成页面拥挤,否则另一位开发者很难根据记录作出相同判断。可以给每个失败标出位置、内容和触发条件,让设计取舍能够被复查。
失败记录也应当说明用户是否还能完成操作。有的目录允许换行,行高增加以后只是首屏条目变少;有的操作区域却把按钮固定在不可见位置,用户无法继续。前者需要权衡查找效率,后者需要处理可操作性。若只追求一张截图里所有内容都完整,反而可能把允许滚动的正常页面误判为不可用。
业务数据还可能改变起始判断。下面几类场景的差别在于用户需要从哪一侧获取更多信息,表中的数值只用于安排比较顺序。
| 场景 | 左栏任务 | 右栏任务 | 起始档 |
|---|---|---|---|
| 文档目录与正文 | 找到章节 | 连续阅读 | 1:2 |
| 邮件列表与内容 | 辨认发件人、主题和时间 | 阅读与处理邮件 | 1:1 |
| 商品列表与详情 | 筛选与比较候选 | 检查规格和操作 | 1:1 或 1:2 |
| 数据列表与预览 | 查看字段或批量选择 | 确认摘要 | 2:1 |
如果目录配正文最终选择 1:2,记录应当说明右栏改善了什么,以及左栏付出了什么代价。例如,业务测试可以记录正文在平分时需要额外横向滚动,而左侧缩窄后仍能辨认最长目录。只有得到实际结果以后,这才构成选择理由,不能把这个记录示范写成当前页面已经发生的现象。
当前我的实现提供静态章节卡片和文字段落,没有代码编辑器、图片操作、表单或滚动位置保存。接入真实文档应用时,需要把这些控件加入自己的比较样本。普通正文通过以后,再检查长标题、大字体、较长语言、空态和错误提示;它们会改变占用空间,但仍然服务于同一次阅读任务。
状态内容需要与正常正文使用相同的区域检查。加载时文字较少,窄栏可能没有暴露问题;请求失败以后增加了重试说明和操作按钮,原来的空间分配就可能不足。真实项目可以保留同一条目录入口,分别进入这些已有状态,确认用户能够理解当前结果并继续操作。当前静态阅读页没有实现请求流程,这部分属于项目内容覆盖要求。
这时仍应保持页面内边距稳定。如果一边调整比例,一边修改字号、留白和卡片数量,画面改善后就无法知道哪项改动起作用。比例确定以后,再根据实际栏宽微调内部排列;后续内容发生变化,也可以沿原记录找到最先失效的条件。

三、预设可用以后是否还要允许拖动
阅读长文时扩大正文,回到目录查找时扩大左侧,是用户在同一任务中的不同需要。如果三个位置都能完成核心操作,允许调整可能减少反复切换页面的成本。某一档已经遮挡主要按钮时,开放拖动就可能把用户带入无法继续的状态,需要先修复布局或保留固定比例。
isDraggable 默认是 false。设为 true 后,拖动从 1:1 开始,在 1:2、1:1、2:1 三档之间吸附。开启拖动后固定 ratio 不再起作用;本机 Release SDK 的配置检查还要求移除同层 ratio,否则配置无法通过。这个限制针对 isDraggable: true,不能概括为两个字段在任何取值下都互斥。
| 配置 | 两个窗口分支怎样设置 | 本轮正式版构建 |
|---|---|---|
| 平分基线 | ratio 为 1 | 1 | 通过 |
| 正文优先 | ratio 为 1 | 2 | 通过 |
| 目录优先 | ratio 为 2 | 1 | 通过 |
| 开放拖动 | isDraggable: true,移除各自的 ratio | 通过 |
是否保留拖动还取决于页面对位置稳定性的要求。阅读页允许临时改变正文宽度,复杂表单或固定操作台却可能因为控件移动增加误操作成本。这个判断属于产品取舍,可以用同一项任务比较固定预设和拖动后的完成过程,不能从字段存在直接推出应该开启。
拖动过程还需要与拖动结束后的阅读分别观察。停留在某一档时文字能够放下,不代表手指移动过程中没有遮挡或误触;用户调整完宽度以后能否找到原来的阅读位置,也不能由比例吸附推出。项目可以先把这些操作列为开放条件,等对应设备取得记录后再决定默认策略。本轮没有触控过程或位置恢复结果,因此没有把可拖动写成已经改善阅读体验。

改为2 | 1之后,效果如下所示。

总结
目录与正文的宽度可以通过同一组内容比较三档,再根据最先影响查找或阅读的位置决定预设。项目留下触发条件和放弃其他比例的原因,后续标题、字号和内容改变时,就有重新判断的依据。只有三档都能完成核心任务,才继续评估拖动是否值得开放。
比例调整不会改变用户已经经过的页面顺序。右侧继续进入更深内容时,返回仍需要保留中间层级。
我目前手里的设备还不支持 HarmonyOS 7 ,所以相关内容现阶段主要通过 HarmonyOS 7 模拟器进行验证,真机上的系统表现、设备差异和实际体验,后面有条件再继续补测,最终还是以实际设备运行结果为准。
完整代码
Index.ets
@Entry
@Component
struct Index {
@Provide('pageStack')
pageStack: NavPathStack = new NavPathStack()
@Builder
pageMap(name: string) {
if (name === 'ArticlePage') {
ArticlePage()
}
}
aboutToAppear(): void {
this.pageStack.pushPathByName('ArticlePage', null)
}
build() {
Navigation(this.pageStack) {
Column({ space: 12 }) {
Text('文档目录')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.width('100%')
Text('三组实验保持同一份目录、正文、字号和间距。')
.fontSize(15)
.fontColor('#5F6678')
.lineHeight(22)
.width('100%')
this.chapterItem('01 窗口条件', '宽窗口与方形窗口')
this.chapterItem('02 页面关联', '主页与详情页')
this.chapterItem('03 分栏比例', '1:1、1:2、2:1')
}
.width('100%')
.height('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.mode(NavigationMode.Stack)
.title('文档目录')
.navDestination(this.pageMap)
.width('100%')
.height('100%')
}
@Builder
private chapterItem(title: string, subtitle: string) {
Column({ space: 6 }) {
Text(title)
.fontSize(18)
.fontWeight(FontWeight.Medium)
.width('100%')
Text(subtitle)
.fontSize(14)
.fontColor('#667085')
.width('100%')
}
.width('100%')
.padding(18)
.backgroundColor('#F2F4FA')
.borderRadius(16)
.alignItems(HorizontalAlign.Start)
}
}
@Component
struct ArticlePage {
build() {
NavDestination() {
Column({ space: 16 }) {
Text('分栏比例实验')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.width('100%')
Text('右栏正文内容保持不变,只由 EasyGo 调整左右区域的宽度比例。')
.fontSize(15)
.fontColor('#5F6678')
.lineHeight(22)
.width('100%')
Text('目录与正文的阅读任务不同。目录需要快速扫视标题,正文需要足够的连续行宽。把三种比例放在同一设备和同一窗口下比较,才能判断内容密度是否合适。')
.fontSize(17)
.lineHeight(28)
.width('100%')
Text('实验时记录每栏可见内容、换行数量和触控目标是否拥挤。')
.fontSize(17)
.lineHeight(28)
.width('100%')
}
.width('100%')
.height('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.title('分栏比例')
}
}
module.json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"easyGo": "$profile:easy_go",
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
]
}
]
}
}
easy_go.json
{
"common": {
"displayModeOptions": {
"wideWindowMode": "navigationSplit",
"squareWindowMode": "navigationSplit",
"navigationSplitOptions": {
"homePage": "navBar",
"relatedPage": "ArticlePage",
"wideSplit": {
"ratio": "1 | 1"
},
"squareSplit": {
"ratio": "1 | 1"
},
"splitDividerColor": {
"light": "#FFD7DCE8",
"dark": "#FF4A5060"
}
}
}
}
}
更多推荐


所有评论(0)