window.setMainWindowOrientation 设置横竖屏切换,为什么没有切换完成后的监听?

本问答帖原创发布在华为开发者联盟社区 ,欢迎开发者前往论坛提问交流。
更多与该问题相关的讨论,请点击原帖查看:
window.setMainWindowOrientation 设置横竖屏切换,为什么没有切换完成后的监听?-华为开发者问答 | 华为开发者联盟 (huawei.com)
问题描述:
window.setMainWindowOrientation 设置横竖屏切换,为什么没有切换完成后的监听?
解决方案:
【背景知识】
- @ohos.display (屏幕属性)是用于给予开发者获取显示设备分辨率、旋转角度等信息的能力。
- on(‘windowSizeChange’)开启窗口尺寸变化的监听。
- @ohos.sensor (传感器)模块提供了获取传感器数据的能力,用于收集设备内外环境的各种数据。GRAVITY重力传感器能够帮助设备感知其在空间中的位置变化和运动状态。
- @ohos.mediaquery (媒体查询)可以设置媒体查询的查询条件,并返回对应的监听句柄。
- module.json5配置文件可以配置orientation标识当前UIAbility组件启动时的方向。
【解决方案】
- 实现监听屏幕旋转的能力可以通过display.on(“change”)监听屏幕状态改变,并通过display.getDefaultDisplaySync()获取屏幕示例对象,其中rotation属性用于显示设备的屏幕顺时针旋转角度。实现示例如下:
import window from '@ohos.window';
import display from '@ohos.display';
const ORIENTATION: Array<string> = ['垂直', '平', '反向垂直', '反向水平']
@Entry
@Component
struct OrientationPage {
@State rotation: number = 0
@State message: string = ORIENTATION[this.rotation]
// 是否横屏状态
@State @Watch('setWindowLayOut') isLandscape: boolean = false;
aboutToAppear() {
// 监听屏幕状态改变
display.on("change", async () => {
// 获取当前旋转角度
this.rotation = await display.getDefaultDisplaySync().rotation
this.message = ORIENTATION[this.rotation]
});
}
setWindowLayOut() {
// 调用该接口手动改变设备横竖屏状态(设置全屏模式,先强制横屏,再加上传感器模式)
window.getLastWindow(getContext(this)).then((windowClass) => {
if (this.isLandscape) {
// 设置屏幕横屏
windowClass.setPreferredOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE);
} else {
// 设置屏幕竖屏
windowClass.setPreferredOrientation(window.Orientation.AUTO_ROTATION_PORTRAIT);
}
});
}
build() {
Row() {
Column() {
Text(`${this.rotation}`)
.fontSize(25)
Text(`${this.message}`)
.fontSize(25)
Button(this.isLandscape ? '竖屏' : '横屏')
.width(140)
.onClick(() => {
// 设置横屏
this.isLandscape = !this.isLandscape;
});
}
.width("100%")
}
.height('100%')
}
}
- 可在EntryAbility的onWindowStageCreate中注册windowsSizeChange事件,并通过AppStorage存储,在页面中通过StorageLink监听数据的变换实现屏幕旋转的监听,可参考以下示例:
// EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { display, window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
let mainWindow: window.Window;
try {
mainWindow = windowStage.getMainWindowSync();
let displayClass: display.Display = display.getDefaultDisplaySync();
AppStorage.setOrCreate('orientation', displayClass.orientation);
// 监听窗口的windowsSizeChange事件,旋转屏时会触发该事件
mainWindow.on('windowSizeChange', (data) => {
let displayClass: display.Display | null = null;
try {
displayClass = display.getDefaultDisplaySync();
// 获取屏幕的显示方向
AppStorage.set('orientation', displayClass.orientation);
} catch {
return;
}
})
} catch {
hilog.info(0x0000, 'testTag', '%{public}s', 'error');
return;
}
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
```
- 页面中通过StorageLink监听数据的变换实现屏幕旋转的监听:
```ts
// index.ets
import { display } from '@kit.ArkUI';
@Entry
@Component
struct Index {
// 获取通过监听窗口的windowsSizeChange事件得到的屏幕显示方向
@StorageLink('orientation') myOrientation: display.Orientation = 0;
build() {
Stack() {
// 当屏幕显示方向变化时,切换组件的视图效果
if (this.myOrientation == 0 ||
this.myOrientation == 2) {
Image($r('app.media.startIcon'))
.size({ width: 100, height: 100 })
.id('image1')
} else {
Image($r('app.media.background'))
.position({ x: 0, y: 0 })
.size({ width: 200, height: 200 })
.id('image2')
}
}
.backgroundColor(Color.White)
.size({ width: '100%', height: '100%' })
}
}
需要在项目的module.json5文件中的abilities列表里添加"orientation",指定为"auto_rotation":
{
"module": {
// ...
"abilities": [
{
// ...
"orientation": "auto_rotation",
}
],
}
}
- 通过设备中的重力传感器,可以检测该设备在三个坐标轴(即X轴、Y轴及Z轴)上的线性加速度。基于这些数据,能够推算出屏幕当前的旋转状态。有关具体实现方式,可参考以下示例:
import sensor from '@ohos.sensor';
import base from '@ohos.base';
@Entry
@Component
struct OrientationPage {
@State rotation: string = 'INVALID'
onDegree(callback: base.Callback<string>): void {
sensor.on(sensor.SensorId.GRAVITY, (data: sensor.GravityResponse) => {
let degree: number = -1;
degree = this.CalDegree(data.x, data.y, data.z)
console.log(degree + "zzz")
if (degree >= 0 && (degree <= 30 || degree >= 330)) {
this.rotation = "ROTATION_0";
} else if (degree >= 60 && degree <= 120) { // Use ROTATION_90 when degree range is [60, 120]
this.rotation = "ROTATION_90";
} else if (degree >= 150 && degree <= 210) { // Use ROTATION_180 when degree range is [150, 210]
this.rotation = "ROTATION_180";
} else if (degree >= 240 && degree <= 300) { // Use ROTATION_270 when degree range is [240, 300]
this.rotation = "ROTATION_270";
}
callback(this.rotation);
});
}
CalDegree(x: number, y: number, z: number): number {
let degree: number = -1;
// 3为有效_增量_角度_阈值_系数
if ((x * x + y * y) * 3 < z * z) {
return degree;
}
degree = 90 - (Number)(Math.round(Math.atan2(y, -x) / Math.PI * 180));
return degree >= 0 ? degree % 360 : degree % 360 + 360;
}
aboutToAppear() {
let callback = async (rotation: string) => {
console.log('rotation = ' + rotation)
}
try {
this.onDegree(callback);
} catch (exception) {
}
}
build() {
Row() {
Column() {
Text(`${this.rotation}`)
.fontSize(25)
}
.width("100%")
}
.height('100%')
}
}
- 使用媒体查询接口监听屏幕旋转,设置媒体查询的查询条件为屏幕的方向,可选值为orientation:portrait(设备竖屏)和orientation: landscape(设备横屏)。有关具体实现方式,可参考以下示例:
import { mediaquery } from '@kit.ArkUI';
// 监听横屏事件
let listener = mediaquery.matchMediaSync('(orientation: portrait)');
function onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) {
if (mediaQueryResult.matches) {
console.log(`横屏`)
} else {
}
}
// 注册回调
listener.on('change', onPortrait)
// 取消注册回调
listener.off('change', onPortrait)
【总结】
除可在module.json5文件中全局配置当前UIAbility组件启动时的方向之外,亦可通过调用window.setPreferredOrientation方法动态设定特定页面的窗口方向,请根据具体的业务场景选择合适的方案来监听屏幕旋转事件。
▶更多实践干货就在华为开发者联盟
▶扫码加入鸿蒙主题交流群,共同交流鸿蒙应用创新与开发

评论
- 目前还没评论,等你发挥!

起点课堂会员权益



