#### 1、HarmonyOS windowClass.getWindowAvoidArea() 方法中导航区域高度是否准确?
通过如下代码,获取底部导航区域的位置信息,拿到的height值是 91,是否是准确的?定值逻辑是什么?
```
const systemArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); console.log("systemArea>>>>>>", JSON.stringify(systemArea)) 
```
打印结果如下:
```
systemArea>>>>>> {"visible":true,"leftRect":{"left":0,"top":0,"width":0,"height":0},"topRect":{"left":0,"top":0,"width":0,"height":0},"rightRect":{"left":0,"top":0,"width":0,"height":0},"bottomRect":{"left":409,"top":2629,"width":442,"height":91}}
```

目前获取到的91是px。 导航条本身高度为6vp,距离屏幕边缘是10vp。

#### 2、HarmonyOS 如何区分截屏和录屏事件?

`@ohos.window.on(‘screenshot’)`使用该方法监听截屏事件时,用户进行截屏和结束录屏均会触发该事件,请问应该如何区分截屏事件和录屏事件

开启屏幕截屏、投屏、录屏状态变化的监听参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-display-V5#ZH-CN_TOPIC_0000001930756769__displayoncapturestatuschange12

`on(type: 'captureStatusChange', callback: Callback<boolean>): void`
开启屏幕截屏、投屏、录屏状态变化的监听。

**参数:**

| 参数名      | 类型                | 必填  | 说明                                                             |
| :------- | :---------------- | :-- | :------------------------------------------------------------- |
| type     | string            | 是   | 监听事件,固定为'captureStatusChange'表示设备截屏、投屏或者录屏状态发生变化。              |
| callback | Callback<boolean> | 是   | 回调函数。表示设备截屏、投屏、录屏状态发生变化。true表示设备开始截屏、投屏或者录屏,false表示结束截屏、投屏、录屏。 |


#### 3、HarmonyOS 设备自动旋转?
HarmonyOS设备支持屏幕自动旋转吗?如何监听设备旋转控制页面横竖屏展示

应用设置屏幕自动旋转:在模块配置文件module.json5中给EntryAbility设置"orientation": “auto_rotation_restricted”,再打开手机自动旋转即可。应用中通过window.getLastWindow 获取window实例–>用setPreferredOrientation设置窗口显示方向的属性。通过diplay.on可以监听屏幕状态改变。点击设置了具体方向后,再加上传感器模式判断屏幕方向。demo如下:
```
import window from '@ohos.window';
import display from '@ohos.display';

const TAG = 'foo'
const ORIENTATION: Array<string> = ['垂直','平', '反向垂直', '反向水平']

@Entry
@Component
struct Index {

  @State rotation: number = 0
  @State message: string = ORIENTATION[this.rotation]
  @Watch('setWindowLayOut') @State isLandscape: boolean = false;// 是否横屏状态

  aboutToAppear() {

    this.setOrientation(1)
    let callback = async () => {
      let d = await display.getDefaultDisplaySync()
      this.rotation = d.rotation
      this.message = ORIENTATION[this.rotation]
      console.info(TAG, JSON.stringify(d))
    }
    try {
      display.on("change", callback);//监听屏幕状态改变
    } catch (exception) {
      console.error(TAG, 'Failed to register callback. Code: ' + JSON.stringify(exception));
    }
  }

  setOrientation(type : number) {
    try {
      window.getLastWindow(getContext(this), (err, data) => { //获取window实例
        if (err.code) {
          console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(err));
          return;
        }
        let windowClass = data;
        console.info(TAG, 'Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));

        let orientation : number;
        if (type === 1) {
          orientation = window.Orientation.AUTO_ROTATION; //设置窗口方向为传感器自动旋转模式。
        } else {
          orientation = window.Orientation.UNSPECIFIED; //设置窗口方向为传感器锁定。
        }
        try {
          windowClass.setPreferredOrientation(orientation, (err) => {
            if (err.code) {
              console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(err));
              return;
            }
            console.info(TAG, 'Succeeded in setting window orientation.');
          });
        } catch (exception) {
          console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(exception));
        }
        ;
      });
    } catch (exception) {
      console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(exception));
    }
    ;
  }

  setWindowLayOut() {
    // 调用该接口手动改变设备横竖屏状态(设置全屏模式,先强制横屏,再加上传感器模式)
    window.getLastWindow(getContext(this)).then((windowClass) => {
      if (this.isLandscape) {
        console.log('设置屏幕横屏')
        windowClass.setPreferredOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE);

      } else {
        console.log('设置屏幕竖屏')
        windowClass.setPreferredOrientation(window.Orientation.AUTO_ROTATION_PORTRAIT);
      }
    });
  }

  build() {
    Row() {
      Column() {
        Text(`${this.rotation}`).fontSize(25)
        Text(`${this.message}`).fontSize(25)
        Button('全屏')
          .width(140)
          .onClick(() => {
            this.isLandscape = !this.isLandscape; // 设置横屏
          });
      }
      .width("100%")
    }
    .height('100%')
  }
}
```

#### 4、HarmonyOS 如何适配挖孔屏?
可以通过使用setWindowLayoutFullScreen接口设置窗口为全屏布局,参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/application-window-stage-V5#%E4%BD%93%E9%AA%8C%E7%AA%97%E5%8F%A3%E6%B2%89%E6%B5%B8%E5%BC%8F%E8%83%BD%E5%8A%9B

在看视频、玩游戏等场景下,用户往往希望隐藏状态栏、导航栏等不必要的系统窗口,从而获得更佳的沉浸式体验。此时可以借助窗口沉浸式能力(窗口沉浸式能力都是针对应用主窗口而言的),达到预期效果。从API version 10开始,沉浸式窗口默认配置为全屏大小并由组件模块控制布局,状态栏、导航栏背景颜色为透明,文字颜色为黑色;应用窗口调用setWindowLayoutFullScreen接口,设置为true表示由组件模块控制忽略状态栏、导航栏的沉浸式全屏布局,设置为false表示由组件模块控制避让状态栏、导航栏的非沉浸式全屏布局。

开发步骤
1. 获取应用主窗口。
通过getMainWindow接口获取应用主窗口。
2. 实现沉浸式效果。有以下两种方式:
    - 方式一:应用主窗口为全屏窗口时,调用setWindowSystemBarEnable接口,设置导航栏、状态栏不显示,从而达到沉浸式效果。
    - 方式二:调用setWindowLayoutFullScreen接口,设置应用主窗口为全屏布局;然后调用setWindowSystemBarProperties接口,设置导航栏、状态栏的透明度、背景/文字颜色以及高亮图标等属性,使之保持与主窗口显示协调一致,从而达到沉浸式效果。

3. 加载显示沉浸式窗口的具体内容。
通过loadContent接口加载沉浸式窗口的具体内容。

```
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';


export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    // 1.获取应用主窗口。
    let windowClass: window.Window | null = null;
    windowStage.getMainWindow((err: BusinessError, data) => {
      let errCode: number = err.code;
      if (errCode) {
        console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
        return;
      }
      windowClass = data;
      console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));


      // 2.实现沉浸式效果。方式一:设置导航栏、状态栏不显示。
      let names: Array<'status' | 'navigation'> = [];
      windowClass.setWindowSystemBarEnable(names)
        .then(() => {
          console.info('Succeeded in setting the system bar to be visible.');
        })
        .catch((err: BusinessError) => {
          console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
        });
      // 2.实现沉浸式效果。方式二:设置窗口为全屏布局,配合设置导航栏、状态栏的透明度、背景/文字颜色及高亮图标等属性,与主窗口显示保持协调一致。
      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 sysBarProps: window.SystemBarProperties = {
        statusBarColor: '#ff00ff',
        navigationBarColor: '#00ff00',
        // 以下两个属性从API Version 8开始支持
        statusBarContentColor: '#ffffff',
        navigationBarContentColor: '#ffffff'
      };
      windowClass.setWindowSystemBarProperties(sysBarProps)
        .then(() => {
          console.info('Succeeded in setting the system bar properties.');
        })
        .catch((err: BusinessError) => {
          console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
        });
    })
    // 3.为沉浸式窗口加载对应的目标页面。
    windowStage.loadContent("pages/page2", (err: BusinessError) => {
      let errCode: number = err.code;
      if (errCode) {
        console.error('Failed to load the content. Cause:' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in loading the content.');
    });
  }
};
```

#### 5、HarmonyOS 创建子窗口时,如何向子窗口传递页面参数?
参考demo:

EntryAbility.ets
```
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.');
// 给Index页面传递windowStage
AppStorage.setOrCreate('windowStage', windowStage);
});
}
```
Index.ets
```
import window from '@ohos.window';
import { BusinessError } from '@ohos.base';
let windowStage_: window.WindowStage | undefined = undefined;
let sub_windowClass: window.Window | undefined = undefined;
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  storage: LocalStorage = new LocalStorage();

  private CreateSubWindow(){
    // 获取windowStage
    windowStage_ = AppStorage.get('windowStage');
    // 1.创建应用子窗口。
    if (windowStage_ == null) {
      console.error('Failed to create the subwindow. Cause: windowStage_ is null');
    }
    else {
      windowStage_.createSubWindow("mySubWindow", (err: BusinessError, data) => {
        let errCode: number = err.code;
        if (errCode) {
          console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
          return;
        }
        sub_windowClass = data;
        console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
        // 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等。
        sub_windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
          let errCode: number = err.code;
          if (errCode) {
            console.error('Failed to move the window. Cause:' + JSON.stringify(err));
            return;
          }
          console.info('Succeeded in moving the window.');
        });
        sub_windowClass.resize(500, 500, (err: BusinessError) => {
          let errCode: number = err.code;
          if (errCode) {
            console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
            return;
          }
          console.info('Succeeded in changing the window size.');
        });
        // 3.为子窗口加载对应的目标页面。
        this.storage.setOrCreate('storageSimpleProp', 121);
        sub_windowClass.loadContent("pages/SubWindow", this.storage, (err: BusinessError) => {
          let errCode: number = err.code;
          if (errCode) {
            console.error('Failed to load the content. Cause:' + JSON.stringify(err));
            return;
          }
          console.info('Succeeded in loading the content.');
          // 3.显示子窗口。
          (sub_windowClass as window.Window).showWindow((err: BusinessError) => {
            let errCode: number = err.code;
            if (errCode) {
              console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
              return;
            }
            console.info('Succeeded in showing the window.');
          });
        });
      })
    }
  }
  private destroySubWindow(){
    // 4.销毁子窗口。当不再需要子窗口时,可根据具体实现逻辑,使用destroy对其进行销毁。
    (sub_windowClass as window.Window).destroyWindow((err: BusinessError) => {
      let errCode: number = err.code;
      if (errCode) {
        console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in destroying the window.');
    });
  }
  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        Button(){
          Text('CreateSubWindow')
            .fontSize(24)
            .fontWeight(FontWeight.Normal)
        }.width(220).height(68)
        .margin({left:10, top:60})
        .onClick(() => {
          this.CreateSubWindow()
        })
        Button(){
          Text('destroySubWindow')
            .fontSize(24)
            .fontWeight(FontWeight.Normal)
        }.width(220).height(68)
        .margin({left:10, top:60})
        .onClick(() => {
          this.destroySubWindow()
        })
        Image($rawfile('[library2].mmm.png'))
      }
      .width('100%')
    }
    .height('100%')
  }
}
```

 

Logo

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

更多推荐