天空闲话 发表于 2024-11-26 20:35:36

【HarmonyOS Next】原生沉醉式界面

背景

在实际项目中,为了软件使用整体色调看起来统一,一般顶部和底部的颜色必要铺满整个手机屏幕。因此,这篇帖子是介绍设置的方法,也是应用沉醉式结果。如下图:底部的绿色延伸到上面的状态栏和下面的导航栏
https://img-blog.csdnimg.cn/img_convert/0adf02dd1b725ce66f57bb4301401c8b.png
UI

在鸿蒙应用中,全屏UI元素分为状态栏、应用界面和导航栏。
https://img-blog.csdnimg.cn/img_convert/69b276d8704188471bc3014b753f8dda.png
一般实现应用沉醉式结果由两种方式:


[*]窗口全屏布局方案:调整布局体系为全屏布局,界面元素延伸到状态栏和导航条地区实现沉醉式结果。
[*]组件延伸方案:组件布局在应用界面地区,通过接口方法延伸到状态栏和导航栏。
窗口全屏布局方案


[*]新建展示页面,并使用@StorageProp界说页面内容的顶部偏移和底部偏移属性
@Entry
@Component
struct Index {
@StorageProp('bottomRectHeight')
bottomRectHeight: number = 0;
@StorageProp('topRectHeight')
topRectHeight: number = 0;

build() {
    Row() {
      Column() {
      Row() {
          Text('DEMO-ROW1').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)

      Row() {
          Text('DEMO-ROW2').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)

      Row() {
          Text('DEMO-ROW3').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)

      Row() {
          Text('DEMO-ROW4').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)

      Row() {
          Text('DEMO-ROW5').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)

      Row() {
          Text('DEMO-ROW6').fontSize(40)
      }.backgroundColor(Color.Orange).padding(20)
      }
      .width('100%')
      .height('100%')
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.SpaceBetween)
      .backgroundColor('#008000')
      // top数值与状态栏区域高度保持一致;bottom数值与导航条区域高度保持一致
      .padding({ top: px2vp(this.topRectHeight), bottom: px2vp(this.bottomRectHeight) })
    }
}
}

[*]在EntryAbility的onWindowStageCreate方法中,调用window.Window.setWindowLayoutFullScreen方法设置窗口全屏。
let windowClass: window.Window = windowStage.getMainWindowSync();
let isLayoutFullScreen = true;
    windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {
      console.info('Succeeded in setting the window layout to full-screen mode.');
    }).catch((err: BusinessError) => {
      console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
    });

[*]为了避免构件被挡住,根据导航条和状态栏的高度,修改bottomRectHeight和topRectHeight的数值。
    //获取导航栏高度
    let bottomRectHeight = windowClass
      .getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
      .bottomRect
      .height;
    AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
    // 获取状态栏区域高度
    let topRectHeight = windowClass
      .getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
      .topRect
      .height;
    AppStorage.setOrCreate('topRectHeight', topRectHeight);

[*]再设置页面监听,动态修改bottomRectHeight和topRectHeight的数值。
windowClass.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);
      }
    });
EntryAbility完整代码

仅必要修改onWindowStageCreate方法
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) => {      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.');    });    // 获取应用主窗口    let windowClass: window.Window = windowStage.getMainWindowSync();    // 设置窗口全屏    let isLayoutFullScreen = true;    windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {      console.info('Succeeded in setting the window layout to full-screen mode.');    }).catch((err: BusinessError) => {      console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));    });    //获取导航栏高度
    let bottomRectHeight = windowClass
      .getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
      .bottomRect
      .height;
    AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
    // 获取状态栏区域高度
    let topRectHeight = windowClass
      .getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM)
      .topRect
      .height;
    AppStorage.setOrCreate('topRectHeight', topRectHeight);
    // 注册监听函数,动态获取避让地区数据    windowClass.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);
      }
    });
} 组件延伸方案

使用expandSafeArea方法来实现。
expandSafeArea(types?: Array<SafeAreaType>, edges?: Array<SafeAreaEdge>): T;


[*]types:配置扩展安全地区的类型。SafeAreaType罗列类型,SYSTEM是体系默认非安全地区,包罗状态栏、导航栏;CUTOUT是设备的非安全地区,例如刘海屏或挖孔屏地区;KEYBOARD是软键盘地区,组件不避让键盘。
[*]edges:扩展安全地区的方向。
代码

通过颜色对比,可以看出组件延伸结果。


[*]column:背景颜色设置为橘色,从图片可以看出只能在安全地区内显示。
[*]list:背景颜色设置为黄色,从图片可以看出已经延伸至导航条和状态栏了。
[*]Text:背景颜色设置成红色,就可以看到整个组件的滑动过程.
https://img-blog.csdnimg.cn/img_convert/c9a2657e14fa052885d2582666ae3fb1.gif
@Entry
@Component
struct ExamplePage {
private arr: number[] =

build() {
    Column() {
      List({ space: 20, initialIndex: 0 }) {
      ForEach(this.arr, (item: number) => {
          ListItem() {
            Text('' + item)
            .width('100%')
            .height(100)
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .borderRadius(10)
            .backgroundColor(Color.Red)
          }

      }, (item: number) => item.toString())
      }
      .listDirection(Axis.Vertical) // 排列方向
      .scrollBar(BarState.Off)
      .friction(0.6)
      .divider({
      strokeWidth: 2,
      color: 0xFFFFFF,
      startMargin: 20,
      endMargin: 20
      }) // 每行之间的分界线
      .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
      .width('90%')
      .backgroundColor(Color.Yellow)
      // List组件的视窗范围扩展至导航条。
      .expandSafeArea(, )
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Orange)
}
}
总结

如果不是全部界面都必要实现沉醉式布局时,可以通过组件延伸方案去实现部门组件的沉醉式布局。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【HarmonyOS Next】原生沉醉式界面