HarmonyOS鸿蒙开辟 - 解决上下两栏白边 - 沉浸式结果

打印 上一主题 下一主题

主题 960|帖子 960|积分 2880

鸿蒙应用开辟从入门到入行

HarmonyOS鸿蒙开辟 - 解决上下两栏白边 - 沉浸式结果

预览器上下两栏白边



  • 自从HarmonyOS升级到release版后,很多同砚会问猫林老师:为什么他的预览器上下有白边,为什么明显根容器写了宽高百分百但没铺满。如下图

白边原因



  • 其实上面的白边,称之为状态栏。上面会放手机wifi信号、电池电量等信息。一般情况下我们不需要把应用中具有交互结果的界面延伸到上面去,免得影响操作。
  • 同样,下面的白边称之为导航栏,也即切换手机内应用的地方。会有一个小横条方便你切换差别应用以及回到桌面。
  • 如下图所示

  • 而HarmonyOS升级到release版本后,特意在预览器里把这上下两栏给你留白空出来,就是为了方便让开辟者知道,本身的界面并没占用这两个区域,以是一般情况下,假如你的应用团体配景颜色就是白色的,其实是无需处理的。
沉浸式结果先容



  • 根据上面说的白边情况,假如你的app配景致正好也是白色,那么可以和上下白边融为一体,显得不那么突兀。但假如你的app是别的颜色,那么大概会有明显的突兀感。
  • 举个例子:大家经常用的美团。我们看看它现在的情况,以及假设有白边的情况

    这是美团正常情况,会看到顶部是黄色,状态栏也变为黄色,视觉结果上完美无缺
  • 以下假设状态栏白色

    可以看到视觉结果上会比力突兀
  • 通过对比我们发现,确实在实际app开辟过程中,状态栏上可以不放任何界面元素,但是需要将状态栏的颜色界说的与app配景致保持同等,才会视觉上显得更好看,更融为一体。像如许的结果,我们称之为沉浸式结果
  • 通过上面的形貌我们已经发现沉浸式结果能提供比力好的视觉结果,但怎样实现呢?
  • 有三种方案都可以实现:

    • 通过设置Window配景致来实现
    • 通过调用窗口强制全屏结构接口setWindowLayoutFullScreen() + padding避让实现 (麻烦)
    • 直接使用扩展到避让区功能

通过设置Window配景致实现沉浸式



  • 设置窗体配景致实现

    • 先看不设置的情况下,我们写的一个宽高百分百,且配景颜色为红色的界面,如下图,可以看到状态栏和团体配景致不同等,有明显突兀感

    • 此时,我们可以设置窗体全局配景致也为红色实现视觉沉浸,来到EntryAbility.ets,找到onWindowStageCreate生命周期函数,在windowStage.loadContent回调里设置如下代码即可
      1. windowStage.getMainWindowSync().setWindowBackgroundColor('#ff0000')
      复制代码
    • 注意:这里只能给16进制颜色,且必须满6位
    • 结果如下


      • 此时完美无缺

    • 这种方法虽然简朴,但有缺点:

      • 预览器依然会有白边,只有模拟器或真机运行才能看到结果
      • 它写死了颜色,每个App里不管是哪个页面都是此颜色,假如你App里多个页面的主题颜色不一样,会导致非常突兀,如下图



使用setWindowLayoutFullScreen实现沉浸式



  • 这是Window提供的一个方法,可以设置让App整屏(即覆盖状态栏与导航栏)实现整块屏幕都可以结构,但是大部门使用时必须共同避让偏移,否则会有题目。至于什么题目呢,我们往下看。
  • 起首来到EntryAbility.ets,继承找到onWindowStageCreate生命周期函数,在windowStage.loadContent回调里设置如下代码即可
    1. windowStage.getMainWindow().then(w => {
    2.     // 设置占用全屏
    3.     w.setWindowLayoutFullScreen(true)
    4. })
    复制代码
  • 如许虽然实现了沉浸式结果,但也存在了题目,例如,我们第一页中原来有Button,但是此时Button位置跑到原来的状态栏去了,如下图

  • 如许的话,会导致本来不该结构的区域也会存在我们的结构元素。第一巨丑,第二用户也点击不了。
  • 因此,我们使用这个方法实现沉浸式时,一般还要做让页面根容器padding避让。也即让我们结构的组件,通过padding的方式挪动他们位置,避让本来的状态栏和导航栏。
  • 例:
    1. Column() {
    2.     Button('去下一页')
    3.       .onClick(() => {
    4.         router.pushUrl({
    5.           url: 'pages/Second'
    6.         })
    7.       })
    8.   }
    9.   .width('100%')
    10.   .height('100%')
    11.   .backgroundColor(Color.Red)
    12.   .padding({ top: 50, bottom: 50 })
    复制代码
  • 此时,我们发现写的按钮确实不会被刘海屏挡住了。但是细致的同砚发现了,我们这里写死的50vp。不公道,有大概给少了,也有大概给多了。毕竟差别装备的状态栏大概不一样。以是假如我们使用这种方案还需要获取屏幕的状态栏与导航栏的高度。然后把高度存到本地存储里,方便所有页面都可以使用并设置padding
  • 具体步调:继承来到onWindowStageCreate,填写如下代码
    1. onWindowStageCreate(windowStage: window.WindowStage): void {    // Main window is created, set main page for this ability    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');    windowStage.loadContent('pages/Index', (err) => {      // windowStage.getMainWindowSync().setWindowBackgroundColor('#ff0000')
    2.       if (err.code) {        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');        return;      }            // 以下是设置沉浸式,以及获取装备导航条、状态栏高度的代码      windowStage.getMainWindow().then(w => {        // 设置沉浸式         w.setWindowLayoutFullScreen(true)        // 获取装备区域参数        let avoidArea = w.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)        let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度        AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight); // 存到本地存储        let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度        AppStorage.setOrCreate('topRectHeight', topRectHeight); // 存到本地存储        // 当区域发生改变(例如竖屏变横屏),重新获取一次再生存        w.on('avoidAreaChange', (data) => {          if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {            let topRectHeight = data.area.topRect.height;            AppStorage.setOrCreate('topRectHeight', topRectHeight);          } else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {            let bottomRectHeight = data.area.bottomRect.height;            AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);          }        });      })      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');    });  }
    复制代码
  • 好了,上面每句代码都有解释,可以根据解释去理解。固然咯,我知道你们没爱好看代码,以是需要用可以直接复制,反正这个代码是固定的
  • 然后来到页面里,先取出本地存储的值,且用@StorageProp装饰器,设置状态自动更新。
    1.   @StorageProp('bottomRectHeight')
    2.   bottomRectHeight: number = 0;
    3.   @StorageProp('topRectHeight')
    4.   topRectHeight: number = 0;
    复制代码
  • 然后把这两个变量,设置给根容器的padding即可
    1.   @StorageProp('bottomRectHeight')
    2.   bottomRectHeight: number = 0;
    3.   @StorageProp('topRectHeight')
    4.   topRectHeight: number = 0;
    5.   build() {    Column() {      Button('去下一页')        .onClick(() => {          router.pushUrl({            url: 'pages/Second'          })        })    }    .width('100%')    .height('100%')    .backgroundColor(Color.Red)    .padding({ top: px2vp(this.topRectHeight), bottom: px2vp(this.bottomRectHeight) })
    复制代码
  • 同样的,其他页面也如此设置即可
  • 如许,我们通过一系列操作。以及一段代码实现了沉浸式结果。但大家也发现明显的缺点

    • 预览器依然没结果,需要真机或模拟器查察
    • 代码过多。很多多少没耐烦的同砚看到这,大概都已经烦躁的想打人了
    • 如许子会让所有页面都被迫使用沉浸式,假如哪个页面不需要沉浸式,还需要再此页面的about里禁用
      1. aboutToAppear(): void {
      2.     window.getLastWindow(getContext())
      3.       .then(win => {
      4.         win.setWindowLayoutFullScreen(false)
      5.       })
      6. }
      复制代码

  • 因此,我们还有最为简朴的一种方式,请往下继承看
使用expandSafeArea设置沉浸式(保举)



  • expandSafeArea是一个按需方式的沉浸式方案,它能完美起到哪个页面需要沉浸式,就在哪个页面使用即可,绝对不会让整个App每个页面都强制沉浸式。而且使用起来非常简朴,只需要在需要沉浸式的页面的根容器里设置即可,例
    1. Column() {
    2.       Button('去下一页')
    3.         .onClick(() => {
    4.           router.pushUrl({
    5.             url: 'pages/Second'
    6.           })
    7.         })
    8.     }
    9.     .width('100%')
    10.     .height('100%')
    11.     .backgroundColor(Color.Red)
    12.     .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
    复制代码
  • 解释:参数1固定,参数2是设置需要沉浸式的区域,SafeAreaEdge.TOP代表上面状态栏沉浸式,SafeAreaEdge.BOTTOM代表下面导航栏沉浸式,此时结果如下


    • 没错,此时不需要启动模拟器,预览器也可以直接看到结果!

  • 固然,你也可以只设置让顶部沉浸式,则第二个参数只要写一个TOP即可,如下代码
    1. Column() {
    2.       // 生略里面代码
    3.   }
    4.     .width('100%')
    5.     .height('100%')
    6.     .backgroundColor(Color.Red)
    7.     .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
    复制代码
  • 结果如下

扩展思索:setWindowLayoutFullScreen是否很鸡肋?



  • 同砚们到现在为止,发实际现沉浸式我们用了三种方案。其中第一种设置Window配景致可以无视掉,这种方法我们基本不会用。而第二种方法能实现,但又比力麻烦,第三种是最轻易也最保举的方式。
  • 但此时请我们思索下:setWindowLayoutFullScreen是否真的一点应用场景都没有?
  • 要想答复这个题目,我们可以从setWindowLayoutFullScreen的特点入手,大家还记得吗?setWindowLayoutFullScreen最大的特点是让app所有页面都强制全屏(沉浸式),那么大家细致想想,有没有哪种App是需要任意页面都强制全屏的呢?

    • 没错,答案是游戏!如下图


  • 像如许的,假如以后是游戏类App,我们一定需要使用setWindowLayoutFullScreen一次性设置所有页面全屏
  • 因此,这个方法,大家也需要有点印象哦!万一哪天要用到呢?
  • 请思索:还有没有除了游戏以外也大概要用到setWindowLayoutFullScreen的场景呢?把你的想法可以打在批评区

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

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

惊落一身雪

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表