鸿蒙 HarmonyOS 实现沉浸式三种方式

一、setWindowLayoutFullScreen(true)

  • 设置主窗口或子窗口的布局是否为沉浸式布局,使用Promise异步回调。
  • 沉浸式布局生效时,布局不避让状态栏与导航栏,组件可能产生与其重叠的情况。
  • 非沉浸式布局生效时,布局避让状态栏与导航栏,组件不会与其重叠。
  • 窗口的布局是否为沉浸式布局(该沉浸式布局状态栏、导航栏仍然显示)。true表示沉浸式布局;false表示非沉浸式布局。


1、EntryAbility直接设置

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
    GlobalContext.get().setContext(this.context);

    windowStage.getMainWindow().then((windowObj: window.Window) => {
      //设置沉浸式
      windowObj.setWindowLayoutFullScreen(true).catch((error: BusinessError) => {
        hilog.error(0x0001, 'testTag', `Failed to setWindowLayoutFullScreen. Code: ${error.code}`);
      })
      //获取并保存状态栏高度
      let avoidArea = windowObj.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      GlobalContext.get().setObject('state_bar_height', avoidArea.topRect.height);

      windowStage.loadContent('pages/Index', (err) => {
        if (err.code) {
          hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
          return;
        }
        hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
      });
    })
  }
}

未做状态栏高度处理页面代码

@Entry
@Component
struct ImmersivePage {
  build() {
    Column() {
      Text('setWindowLayoutFullScreen(true) 沉浸式')
        .fontSize(50)
        .fontColor(Color.Red)
    }
    .height('100%')
    .width('100%')
  }
}

状态栏高度处理页面代码

@Entry
@Component
struct ImmersivePage {
  build() {
    Column() {
      //添加状态高度,可以封装好一个通用
      Text()
        .backgroundColor(Color.Orange)
        .height(px2vp(GlobalContext.get().getT<number>('state_bar_height')))
        .width('100%')

      Text('setWindowLayoutFullScreen(true) 沉浸式')
        .fontSize(50)
        .fontColor(Color.Red)
    }
    .height('100%')
    .width('100%')
  }
}
处理

2、在对应页面设置setWindowLayoutFullScreen(true)沉浸式

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
    GlobalContext.get().setContext(this.context);

    windowStage.getMainWindow().then((windowObj: window.Window) => {
      //获取并保存状态栏高度
      let avoidArea = windowObj.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      GlobalContext.get().setObject('state_bar_height', avoidArea.topRect.height);
      //保存窗口全局使用
      GlobalContext.get().window = windowStage.getMainWindowSync()

      windowStage.loadContent('pages/Index', (err) => {
        if (err.code) {
          hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
          return;
        }
        hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
      });
    })
  }
}
@Entry
@Component
struct ImmersivePage {
  build() {
    Column() {
      Text('当前页面设置setWindowLayoutFullScreen(true) 沉浸式')
        .fontSize(50)
        .fontColor(Color.Red)
    }
    .height('100%')
    .width('100%')
  }

  aboutToAppear(): void {
    //设置沉浸式
    GlobalContext.get().window?.setWindowLayoutFullScreen(true)
  }

  aboutToDisappear(): void {
     //沉浸式恢复
    GlobalContext.get().window?.setWindowLayoutFullScreen(false)
  }
}

3、使用方式总结

  1. 直接设置setWindowLayoutFullScreen(true),会导致全部页面内容到状态栏,需要手动添加状态栏高度,可以考虑封装好一个。
  2. 在页面显示前(aboutToAppear)获取窗口(windowStage.getMainWindowSync())设置setWindowLayoutFullScreen(true)实现沉浸式,页面销毁(aboutToDisappear)设置setWindowLayoutFullScreen(false)回归正常。
    但是这样做有个不好影响就是上一个页面会有向下动的视觉,体验不是很好。

二、expandSafeArea()

  • 控制组件扩展其安全区域。

1、未设置expandSafeArea

@Entry
@Component
struct ImmersivePage {
  build() {
    Column() {
      Text('未设置 expandSafeArea 沉浸式')
        .fontSize(50)
        .fontColor(Color.Red)
    }
    .backgroundColor(Color.Orange)
    .height('100%')
    .width('100%')
  }
}

2、设置expandSafeArea背景色沉浸

对父容器设置才是背景色沉浸,如果对Text设置会连带文字一起沉浸到状态栏。

@Entry
@Component
struct ImmersivePage {
  build() {
    Column() {
      Text('设置 expandSafeArea 沉浸式')
        .fontSize(50)
        .fontColor(Color.Red)
    }
    .expandSafeArea()//设置沉浸式
    .backgroundColor(Color.Orange)
    .height('100%')
    .width('100%')
  }
}

3、设置expandSafeArea图片沉浸

@Entry
@Component
struct ImmersivePage {
  build() {
    Stack() {
      Image($rawfile('img.png'))
        .expandSafeArea()//设置沉浸式
      Text('设置 expandSafeArea 沉浸式')
        .fontSize(50)
        .fontColor(Color.White)
    }
    .height('100%')
    .width('100%')
  }
}
未设置沉浸式 设置沉浸式

4、多层组件也能设置expandSafeArea沉浸,只要父组件没有限制其到状态栏

@Entry
@Component
struct ImmersivePage {
  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      this.LayoutBuilder()
      Text('设置 expandSafeArea 沉浸式')
        .fontSize(50)
        .fontColor(Color.White)
    }
    .height('100%')
    .width('100%')
  }

  @Builder
  LayoutBuilder() {
    Column() {
      Image($rawfile('img.png'))
        .expandSafeArea() //设置沉浸式
    }
  }
}

5、多个组件也能设置expandSafeArea沉浸

@Entry
@Component
struct ImmersivePage {
  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      this.LayoutBuilder()
      Text('设置 expandSafeArea 沉浸式')
        .fontSize(50)
        .fontColor(Color.White)
        .expandSafeArea() //设置沉浸式1
    }
    .height('100%')
    .width('100%')
  }

  @Builder
  LayoutBuilder() {
    Column() {
      Image($rawfile('img.png'))
        .expandSafeArea() //设置沉浸式2
    }
  }
}

6、使用方式总结

  1. expandSafeArea设置沉浸式更灵活,可以根据情况对其中一个或多个组件设置沉浸式
  2. expandSafeArea设置沉浸式不会导致页面上下抖动

7、说明

设置expandSafeArea属性进行组件绘制扩展时,组件不能设置固定宽高尺寸(百分比除外)。
安全区域不会限制内部组件的布局和大小,不会裁剪内部组件。
当父容器是滚动容器时,设置expandSafeArea属性不生效。
设置expandSafeArea()时,不传参,走默认值处理;设置expandSafeArea([],[])时,相当于入参是空数组,此时设置expandSafeArea属性不生效。
组件设置expandSafeArea之后生效的条件为:
1.type为SafeAreaType.KEYBOARD时默认生效,组件不避让键盘。
2.设置其他type,组件的边界与安全区域重合时组件能够延伸到安全区域下。例如:设备顶部状态栏高度100,那么组件在屏幕中的绝对位置需要为0 <= y <= 100。
组件延伸到安全区域下,在安全区域处的事件,如点击事件等可能会被系统拦截,优先给状态栏等系统组件响应。
滚动类容器内的组件不建议设置expandSafeArea属性,如果设置,需要按照组件嵌套关系,将当前节点到滚动类祖先容器间所有直接节点设置expandSafeArea属性,否则expandSafeArea属性在滚动后可能会失效

三、Navigation()+NavDestination()

Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(NavDestination的子组件),首页和非首页通过路由进行切换。

作为子页面的根容器,用于显示Navigation的内容区。

该组件从API Version 11开始默认支持安全区避让特性(默认值为:expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])),开发者可以重写该属性覆盖默认行为,API Version 11之前的版本需配合expandSafeArea属性实现安全区避让。

@Builder
export function ImmersivePageBuilder() {
  ImmersivePage()
}

@Component
export struct ImmersivePage {
  pathStack: NavPathStack = new NavPathStack()

  build() {
    NavDestination() {
      Stack({ alignContent: Alignment.TopStart }) {
        Text('设置 NavDestination 沉浸式')
          .fontSize(50)
          .fontColor(Color.White)
      }
      .height('100%')
      .width('100%')
    }
    .hideTitleBar(true) //设置沉浸式
    .backgroundColor(Color.Orange) //设置沉浸式
    .backgroundImage($rawfile('img.png'))//图片设置沉浸式,容易图片拉伸
    .backgroundImageSize({ width: '100%', height: '100%' })//图片设置沉浸式,容易图片拉伸
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack
    })
  }
}
背景色沉浸式 图片沉浸式

使用方式总结

  1. 默认还是使用expandSafeArea实现沉浸式。
  2. 推荐在这使用颜色沉浸式,用图片容易造成拉伸,确定用图片可以单独对图片使用expandSafeArea沉浸式。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容