【HarmonyOS Next】鸿蒙应用折叠屏设备适配方案

嚴華  论坛元老 | 2025-3-17 14:55:20 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1023|帖子 1023|积分 3069

【HarmonyOS Next】鸿蒙应用折叠屏设备适配方案

一、媒介


目前应用上架华为AGC平台,都会被要求适配折叠屏设备。目前华为系列的折叠屏手机,有华为 Mate系列(左右折叠,华为 Mate XT三折叠),华为Pocket 系列(上下折叠)。
二、适配方案思绪探讨

目前鸿蒙应用适配折叠屏的思绪分为两种:分栏和全屏适配。


分栏
在左右折叠手机上,相当于首页一级页面在左边,二级子页面点开后在右边。三折叠上形态未知,有知道的小伙伴可以同步下。
上下折叠手机上,不以分栏的方式呈现,和直板机相似。
单栏(全屏)
全屏适配而且拉伸界面,不进行界面处理。而是处理成平板的UI布局形式,和直板机界面排版不一样。这种适配方案结果最好,但是工作量较大。
不过目前华为官方反馈说以后不演进分栏方案了。三折叠和25年三月新形态手机的适配都是风险。
三、适配方案实现

传统的router路由在折叠屏适配上,无法提供良好支持。所以建议切换到Navigation。
因为不管是路由回退栈的处理,还是页面数的限定问题。Navigation都优于router,而且华为官方已经明确表现,推荐Navgation的方案。
当然如果有了解HMRouter的同学,也可以利用,因为HMRouter就是在Navgation上进行封装和优化的三方库。
分栏
设置主页面目面目器Navigation,mode属性为NavigationMode.Stack:
  1. @Entry
  2. @Component
  3. struct MainPage {
  4.   @State message: string = 'Hello World';
  5.   // 创建一个页面栈对象并传入Navigation
  6.   pageStack: NavPathStack = new NavPathStack()
  7.   build() {
  8.     Navigation(this.pageStack) {
  9.       // 页面布局
  10.       Row() {
  11.         Column() {
  12.           Text(this.message)
  13.             .fontSize(50)
  14.             .fontWeight(FontWeight.Bold)
  15.             .onClick(()=>{
  16.               // 跳转到子页面
  17.               this.pageStack.pushDestination({
  18.                 name: "OnePage",
  19.               }, false); //该false表示不需要转场动画,默认是有的
  20.             })
  21.         }
  22.         .width('100%')
  23.       }
  24.       .height('100%')
  25.     }
  26.     .mode(NavigationMode.Split)
  27.   }
  28. }
复制代码
细节可参考该文章,点击跳转=》(【HarmonyOS】关于官方推荐的组件级路由Navigation的心得了解)

单栏(全屏)
设置主页面目面目器Navigation,mode属性为NavigationMode.Stack:
  1. @Entry
  2. @Component
  3. struct MainPage {
  4.   @State message: string = 'Hello World';
  5.   // 创建一个页面栈对象并传入Navigation
  6.   pageStack: NavPathStack = new NavPathStack()
  7.     // 使用 @State 装饰器定义响应式变量,用于存储组件的宽高
  8.   @State width: number = 0
  9.   @State height: number = 0
  10.   build() {
  11.     Navigation(this.pageStack) {
  12.       // 页面布局
  13.       Row() {
  14.         Column() {
  15.           Text(this.message)
  16.             .fontSize(50)
  17.             .fontWeight(FontWeight.Bold)
  18.             .onClick(()=>{
  19.               // 跳转到子页面
  20.               this.pageStack.pushDestination({
  21.                 name: "OnePage",
  22.               }, false); //该false表示不需要转场动画,默认是有的
  23.             })
  24.         }
  25.         .width('100%')
  26.       }
  27.       .height('100%')
  28.     }
  29.     // 分为三种模式,(默认)自动NavigationMode.Auto,单页面NavigationMode.Stack和分栏NavigationMode.Split
  30.     .mode(NavigationMode.Stack)
  31.     .backgroundColor(Color.Gray)
  32.      .onSizeChange((width: number, height: number) => {
  33.           // 当组件大小变化时,更新宽高信息
  34.           this.width = width
  35.           this.height = height
  36.         })
  37.         .onAreaChange( (oldValue: Area, newValue: Area)=>{
  38.           // newValue.width
  39.       })
  40.   }
  41. }
复制代码
界面必要监听最外层宽高,onSizeChange和onAreaChange都可以,建议利用onAreaChange,用于判断界面是否必要切换为平板适配模式。【目前官方推荐利用600vp 作为当页面宽度大于等于肯定阈值点】
子页面添加跳转入口函数,添加NavDestination生命周期的处理:
  1. // 跳转页面入口函数
  2. @Builder
  3. export function OnePageBuilder() {
  4.   OnePage()
  5. }
  6. @Entry
  7. @Component
  8. struct OnePage {
  9.   private TAG: string = "OnePage";
  10.   @State message: string = 'Hello World';
  11.   pathStack: NavPathStack = new NavPathStack();
  12.   build() {
  13.     NavDestination() {
  14.       Row() {
  15.         Column() {
  16.           Text(this.message)
  17.             .fontSize(50)
  18.             .fontWeight(FontWeight.Bold)
  19.         }
  20.         .width('100%')
  21.       }
  22.       .height('100%')
  23.     }.onShown(()=>{
  24.       console.log(this.TAG, "OnePage onShown");
  25.     })
  26.      .onReady((context: NavDestinationContext) => {
  27.          this.pathStack = context.pathStack;
  28.     })
  29.   }
  30. }
复制代码
在首页获取到的宽高,可以利用多种方式缓存起来,例如放到AppStorage,单例中。二级等子页面进入后就可以判断。
当然页面中的动态监听也必要生存。场景必要覆盖,因为在首页时用户可能是折叠状态,进入子页面后展开的情况也有。
当然判断手机折叠屏状态,除了通过宽高,也可通过官方提供的折叠屏状态进行判断,不过在上下折叠屏手机上也会被激活,这里必要额外在判断一下。
  1. import { display } from '@kit.ArkUI';
  2. let ret: boolean = false;
  3. // 当前是否是折叠屏
  4. ret = display.isFoldable();
  5. if(ret){
  6. let callback: Callback<display.FoldStatus> = (data: display.FoldStatus) => {
  7.   console.info('Listening enabled. Data: ' + JSON.stringify(data));
  8. };
  9. display.on('foldStatusChange', callback);
  10. }
  11. // 页面销毁时,记得取消监听
  12. display.off('foldStatusChange', callback);
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

嚴華

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表