本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

跨平台框架社区释放阔屏潜能:CPF社区KMP&CMP在Pura X Max折叠UI的适配实践-华为开发者话题 | 华为开发者联盟

Pura X Max作为阔形态折叠设备,设备会在窄外屏、阔展开内屏、悬停半折姿态之间动态切换,同时还需要兼容分屏、自由窗口、键盘唤起等场景。窗口的宽度、可用高度、安全区、折痕位置都随设备姿态实时改变。传统适配方案普遍存在通过设备机型判定布局,从而导致窗口尺寸变化时页面体验割裂,同时存在适配后用户编辑状态、选中项丢失,以及挖孔、折痕容易遮挡关键交互控件等常见问题。

CPF 社区的 CMP(Compose)提供一套响应式组件体系,不判断设备机型,而是读取运行时的窗口尺寸、折叠状态、安全区域,并将其作为布局判断依据;UI形态随空间动态改变,但始终保留业务状态连续性,帮助开发者用同一套页面代码完成Pura X Max 阔屏全场景适配,是这套跨平台UI开发套件的核心思路。

一、适配挑战与CPF-CMP应对思路

Pura X Max阔折叠可以在各类屏幕姿态之间自由切换,兼顾便携使用与大屏视野,给用户带来全新交互体验,但也给开发带来多重现实挑战。针对每一类痛点,CPF-CMP形成了对应的设计原则,从框架层面规避传统开发的各类问题。

1、窗口尺寸动态多变:收拢外屏、展开内屏、分屏模式,同一应用窗口宽度差异巨大;横屏、键盘弹出时可用高度被压缩。如果基于设备形态做静态判定,分屏等非标准窗口场景很容易出现布局错乱。

应对思路:以窗口条件代替设备判断,布局决策依据当前窗口实际可用宽高、安全区、折叠姿态,兼容分屏、自由窗口全部窗口模式。

2、导航布局需要动态切换:窄窗口空间有限,导航侧栏应当覆盖正文;阔展开窗口适合导航与正文左右并排;窗口切换过程中,用户的选中条目、输入草稿不能丢失。

应对思路:UI表现与业务状态分离,布局组件只负责界面渲染展示;选中项、编辑草稿等业务状态外置保存;窗口切换仅改变UI形态,保障用户任务可以接续执行。

3、特殊屏幕遮挡问题:内屏挖孔、系统状态栏、键盘会遮挡UI;悬停状态存在折痕区域,关键文字与按钮不能放置在折痕避让区。沉浸式页面既要背景铺满全屏,又要保证交互控件安全可见。

应对思路:封装容器组件收敛差异,框架提供宫格、侧栏、分栏、悬停分区等专用容器,折叠屏适配逻辑下沉至组件内部;业务层专注业务内容实现,避免大量条件分支判断。

4、阅读与操作空间矛盾:浏览场景希望最大化内容阅读面积,但是标题栏、底部Tab栏又需要随时可访问;弹窗长文本场景下,高度压缩时确认按钮容易被挤出可视区域。

应对思路:分层处理空间分配,区分内容展示层与交互操作层;阔屏新增屏幕面积优先承载高价值业务内容,而不是单纯放大UI控件。

5、用户任务连续性保障:开合、旋转、窗口变更触发页面重绘,不能打断用户完整业务链路(浏览-选择-编辑-确认-分享),状态丢失会直接破坏用户体验。

应对思路:业务状态与UI渲染解耦,无论布局如何变化,用户操作产生的数据统一保留,保障完整业务流程不受姿态切换干扰。

二、分层适配实践

1、窗口宽度响应:动态宫格布局,一屏展示更多内容

当窗口从窄变宽,我们希望列表内容自动增加列数,数据、条目顺序完全不变,仅调整每行展示数量。

通过BoxWithConstraints实时获取窗口最大宽度,结合GridRow/GridCol宫格组件,设置布局断点:窄窗口和窗口宽度达到阈值设置不同的展示列数。

用法示例:把当前宽度交给宫格

BoxWithConstraints {
    val count = if (maxWidth >= 600.dp) 4 else 2
    GridRow(
        columns = GridColumns(
            xs = count, sm = count, md = count,
            lg = count, xl = count, xxl = count
        )
    ) {
        repeat(8) { index ->
            GridCol(span = GridSpan(1)) { ItemCard(index) }
        }
    }
}

阈值不要写死固定数值,业务应当依据卡片最小可读宽度来设置;复杂页面支持多档断点,同步调整列数、间距,搭配媒体查询、资源限定词切换图文资源。

业务页面不需要维护两套列表数据,仅依靠容器组件完成重排,在收拢外屏、展开大屏、分屏窄窗口场景均可以得到合理排布效果。

2、导航自适应:窄窗覆盖,阔窗并排,业务状态持续保留

针对导航-正文场景,CPF-CMP提供SideBarContainer组件,开启Auto自动模式:窄窗口下侧栏弹出覆盖正文;窗口变宽之后导航与正文实现左右并排。列表-详情类页面,还可以使用NavigationSplitContainer双栏容器。

关键实践要点:业务状态外置存储把选中项、编辑草稿等状态写到布局组件外部,借助rememberSaveable保存状态。无论侧栏是覆盖模式还是并排模式,两套UI读取同一份业务状态。窗口开合、旋转切换布局,用户已经输入的内容、选中条目不会重置,保障任务连续性。

用法示例:共用状态与自动侧栏

var draft by rememberSaveable { mutableStateOf("") }
val sidebar = rememberSideBarContainerState()
SideBarContainer(
    type = SideBarContainerType.Auto,
    state = sidebar,
    sideBarContent = { NavigationMenu() }
) {
    Editor(draft, onChange = { draft = it })
}

3、沉浸式页面分层:背景铺满,内容自动避让挖孔与系统遮挡

阔屏横屏场景,页面常常需要做沉浸式全屏效果。CPF-CMP采用分层布局方案:外层容器背景直接铺满整个窗口;内层业务内容调用safeDrawingPadding(),自动避让挖孔、系统状态栏、键盘带来的遮挡区域。

这样既保留沉浸式完整背景,同时保证文字、按钮等关键交互控件落在安全绘制区域,避免被屏幕硬件或者系统UI遮挡。

用法示例:背景铺满,内容自动避让

Box(Modifier.fillMaxSize().background(pageBackground)) {
    // 只给文字和按钮留出安全距离,背景保持铺满
    Column(Modifier.fillMaxSize().safeDrawingPadding()) {
        PageContent()
    }
}

上述“用法示例”需要CPF-CMP对应版本支持四边挖孔安全区能力。

4、悬浮叠放栏位:释放阅读空间,栏位可滚动收放

阅读浏览场景,标题栏、底部Tab长期占用屏幕会压缩阅读面积。采用下层内容、上层悬浮栏位的叠放模式:

• 顶部标题栏使用TopAppBar搭配滚动行为,底部Tab开启barOverlap悬浮能力;

• 结合nestedScroll嵌套滚动监听列表滑动;上滑阅读时栏位自动收起释放屏幕空间,下滑页面栏位重新显示;

• 列表设置contentPadding,给首条内容预留避让空间,列表整体依旧铺满页面,内容可以从悬浮栏位后方滚动穿过。

用法示例:内容铺满,标题栏叠放

val behavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Box(Modifier.fillMaxSize()
    .nestedScroll(behavior.nestedScrollConnection)) {
    NavDisplay(
        backStack = backStack,
        entryProvider = entryProvider,
        modifier = Modifier.fillMaxSize()
    )
    TopAppBar(
        title = { Text("行程详情") },
        modifier = Modifier.align(Alignment.TopCenter),
        scrollBehavior = behavior
    )
}

5、高度受限场景:正文可滚动,核心操作始终可见

横屏、分屏、输入法弹出会压缩页面可用高度,宽度不再是主要矛盾。弹窗、表单页面遵循分工原则:长正文区域允许滚动,确认、提交等核心操作按钮固定保留在可视区域。

业务直接复用标准AlertDialog;自定义弹窗同样需要区分滚动内容区和常驻操作区,优先保障用户能够完成任务操作。

用法示例:继续使用标准弹窗

AlertDialog(
    onDismissRequest = { show = false },
    title = { Text("长正文确认") },
    text = { Text(longText) },
    confirmButton = {
        Button(onClick = { show = false }) { Text("确认") }
    }
)

6、悬停半折姿态:上下分区布局,规避折痕风险

设备半折悬停时,屏幕被折痕天然分割为上下两块。使用FoldSplitContainer做页面分区:

• primaryContent放置视频、会议、相机预览等主画面(上半区);

• secondaryContent放置播放、拍摄等交互操作控件(下半区);

折痕避让区域不放置关键文字与点击按钮,不要写死边距数值,读取设备真实折痕区域做布局;相机预览保持原始画面比例,禁止拉伸变形。

用法示例:分别提供画面、操作和补充内容

FoldSplitContainer(
    primaryContent = { VideoArea() },
    secondaryContent = { PlaybackControls() },
    extraContent = { RelatedContent() }
)

7、完整业务链路校验,保障全流程体验

阔屏适配不止是页面UI排版,需要完整跑通用户业务链路:列表浏览、窗口展开、条目选择、详情页、输入编辑、确认、分享。

• 触摸、鼠标、键盘等不同输入方式,复用同一套业务处理逻辑;

• 系统分享场景,通过ShareManager调用鸿蒙系统分享面板;

• 每一步需要校验三点:内容可读、操作控件可触达、业务状态完整保留。

借助CPF-CMP开发Pura X Max阔折叠页面,核心是响应窗口真实运行环境,UI形态自适应变化,业务状态持续不中断。开发者依托框架提供的宫格、侧栏、安全区、悬停分区等容器组件,将折叠屏适配逻辑收敛在组件层,避免业务页面大量机型判断代码;把阔折叠多出的屏幕空间,转化为用户真正可用的内容与操作,实现收拢、展开、悬停、分屏多场景下一致流畅的应用体验。

想了解更多请登录HarmonyOS开发者官网,通过“开发-最佳实践-多设备开发-多设备界面开发-特殊界面布局场景”路径,找到“折叠屏悬停态”文档,也可复制链接直达原文:https://developer.huawei.com/consumer/cn/doc/ doccenter-multi-device/bpta-folded-hover

了解详情;同时也可以GitCode官网搜索“CPF-KMP-CMP/docs”了解更多。

GitCode官网:CPF-KMP-CMP/docs - AtomGit

Logo

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

更多推荐