当前位置: 首页 > news >正文

鸿蒙HarmonyOS NEXT开发:横竖屏切换开发实践

文章目录

      • 一、概述
      • 二、窗口旋转说明
        • 1、配置module.json5的orientation字段
        • 2、调用窗口的setPreferredOrientation方法
      • 四、性能优化
        • 1、使用自定义组件冻结
        • 2、对图片使用autoResize
        • 3、排查一些耗时操作
      • 四、常见场景示例
        • 1、视频类应用横竖屏开发
        • 2、游戏类应用横屏开发
      • 五、其他常见问题
        • 1、Tabs栏中的视频横屏播放,无法隐藏Tabs栏
        • 2、如何解决直板机和平板上默认旋转行为不一致的问题?
        • 3、通过调用window.getLastWindow的方式获取窗口实例出现延迟,如何解决?
        • 4、自动旋转和旋转锁定按钮的关系是什么?与Orientation字段的关系如何判断?

一、概述

横竖屏切换功能即实现应用内既支持竖屏显示也支持横屏显示的效果。对于应用内不同页面显示方向不同的情况,需要在应用逻辑中,动态修改窗口方向,来实现该效果,例如包含视频播放功能的应用,首页内容是采用竖屏方式,而视频详情页则采用横屏方式展示。

本文主要介绍横竖屏功能的开发过程中需要关注的内容,包括如下部分:

  • 窗口旋转策略的选择
  • 常用应用类型的横竖屏开发
  • 常见的横竖屏开发问题

二、窗口旋转说明

目前在HarmonyOS系统中,窗口的旋转形态包括以下四种,窗口的状态对应真机实际状态如下:
在这里插入图片描述

有两种设置窗口旋转策略的方式:

  • 通过module.json5文件中“orientation”字段进行设置

  • 在代码中通过调用窗口window的setPreferredOrientation方法进行设置

这两种方式触发设置旋转的时机不同,总的来说,module.json5文件中的字段在窗口启动时就会生效,对于应用启动时就需要设置横屏或者竖屏的应用,需要进行配置。而setPreferredOrientation是在调用该方法时进行窗口方向的设置,用于在应用启动之后,还需要改变显示方向的场景。

1、配置module.json5的orientation字段

此字段配置的是应用启动时的窗口显示状态,对于开屏时就需要以默认的横屏或者竖屏方式显示,需要在此字段进行相应的配置:

{"module": {// ..."abilities": [{"name": "EntryAbility",// ..."orientation": "portrait"}]}
}

其支持的参数可以参考module.json5配置项中orientation字段相关配置的orientation字段说明:

根据应用默认的旋转行为进行相应的配置:

如果应用是竖屏应用,建议配置portrait为默认旋转策略。
如果应用是横屏应用,例如游戏类应用,进入游戏时,默认就是横屏,此时有两种情况:

  • 仅支持横屏,建议配置landscape为默认旋转策略。

  • 支持在横屏和反向横屏中切换,建议设置为auto_rotation_landscape。

如果应用为可旋转应用,建议应用配置auto_rotation_restricted为默认旋转策略。
如果一个应用,在直板机和折叠机折叠态是竖屏应用,在平板和折叠机展开态默认是可旋转应用,推荐配置follow_desktop为默认旋转策略。

注意
对于需要通过控制中心进行旋转锁定控制的,可以选择字段后方带有restricted字段的旋转策略,此字段表示旋转行为受到控制中心按钮控制,开关打开情况下,不随设备方向旋转,关闭情况下,则会发生跟随设备旋转。

以如下文件管理应用为例,在系统关闭了旋转锁定后,应用的页面都会随着手机旋转而发生展示上的切换,而打开时则不会发生旋转行为,此时就需要配置为auto_rotation_restricted。

在这里插入图片描述

2、调用窗口的setPreferredOrientation方法

对于需要进入应用后,修改应用窗口显示横竖屏状态的情况下,可以调用setPreferredOrientation 方法进行设置,典型场景如一些视频类应用、图片类应用等。

在这里插入图片描述

此类应用在进入时为竖屏,而在视频播放页面可以显示为横屏,则需要支持用户临时修改窗口方向。由于setPreferredOrientation 方法调用的是窗口的显示方向,是整个应用窗口级别都发生了旋转,窗口将一直保持最后一次设置窗口方向的效果,即使发生页面跳转等行为窗口方向也不会发生变化。

四、性能优化

由于在窗口旋转时,屏幕的尺寸会发生变化,界面会发生重新布局,为了提高横竖屏切换时的流畅度,需要进行相应的性能优化。

1、使用自定义组件冻结

旋转时,由于整窗一起旋转,会导致页面重新布局,但是实际上需要展示的可能只有播放内容,对于其他的组件可以使用自定义组件冻结功能,避免由于旋转导致的UI更新操作。例如视频播放底下的详情内容,可能是单独的组件。

@Component({ freezeWhenInactive: true })  // 添加自定义组件冻结功能
struct VideoDetailView {build() {Scroll() {// ... 详情内容}}
}
2、对图片使用autoResize

如果当前旋转页面存在一些图片,未经合理的裁剪,图片过大,可以对图片设置autoResize属性,使图片裁剪到合适的大小进行绘制。该属性的作用是将组件显示区域作为绘制的图源尺寸,可以减少内存占用,例如原图是19201080,但是显示区域是200100,则在解码时会降低采样编码到200*100尺寸。

@Builder
function ImageItem(imageSrc:ResourceStr) {Stack({}) {Image(imageSrc).width('100%').height('100%').autoResize(true)  // 对图片使用auto_resize属性.borderRadius(8).objectFit(ImageFit.Fill).backgroundColor('#1AFFFFFF')}
}
3、排查一些耗时操作

排查当前页面是否存在一些冗余的OnAreaChange事件、blur模糊或者一些线性变化linearGradient的属性,这些都比较耗时,可以根据是否必须使用来决定是否进行优化。

四、常见场景示例

1、视频类应用横竖屏开发
  • 监听窗口变化

由于传感器变化或者用户手动设置窗口方向时,窗口的显示会发生变化,对应窗口的尺寸也会发生改变,此时可以通过拿到窗口的宽高,并对宽高进行对比,判断当前显示是竖屏还是横屏状态,并利用该数据对布局进行适配。

监听窗口尺寸的变化可以通过window.on(‘windowSizeChange’)进行实现。具体的措施如下,在需要进行横竖屏切换的页面进行以下窗口的监听,一般建议是在aboutToAppear中执行:

aboutToAppear(): void {// ...this.windowClass.on('windowSizeChange', (size) => {// ...});// ...
}

并在aboutToDisappear中取消监听:

aboutToDisappear(): void {// ...this.windowClass.off('windowSizeChange');
}

需要注意的是,当用户手动触发setOrientation设置为横屏状态时,即使当前手机处于垂直方向,窗口的状态也是横屏方向,即如下所示:

在这里插入图片描述

此时,窗口的宽是竖屏状态下的高,高变为竖屏状态的宽。所以在监听窗口变化时,可以通过窗口的宽高大小关系,来确定当前窗口的方向,并决定实际的横竖屏状态。

this.windowClass.on('windowSizeChange', (size) => {let viewWidth = px2vp(size.width);let viewHeight = px2vp(size.height);if (viewWidth > viewHeight) {// ...} else {// ...}
});
  • 进行布局适配

对应视频播放这类应用,属于只有播放窗口需要进行横竖屏,所以只需要对视频播放的组件内容进行横屏并进入全屏,所以可以利用UI状态更新的特点,来让播窗变为全屏,将播窗的尺寸定义为@State状态,并设置到Xcomponent组件上。

@State xComponentWidth: number = px2vp(display.getDefaultDisplaySync().width);
@State xComponentHeight: number = px2vp(display.getDefaultDisplaySync().width * this.aspect);

将状态变量与播窗绑定。

XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.xComponentController }).onLoad(() => {// ...}).width(this.xComponentWidth).height(this.xComponentHeight)

并且在之前监听窗口变化的回调中,对XComponentWidth和XComponentHeight进行动态修改,完成窗口变化时横屏和竖屏的视频窗口布局。需要注意的是,在横屏时,视频播放的宽高应该和窗口的宽高一样,并且需要进入全屏状态。而竖屏时,视频播放的宽应该等于窗口的宽,但是高度应该是按照播窗比例乘以窗口的宽进行设置,并退出全屏状态。

在这里插入图片描述

具体实现如下,进入视频详情页面内需要监听窗口尺寸的变化,并根据当前状态,实现对横竖屏状态的监听,根据状态变化修改对应XComponent的宽高,实现全屏或者隐藏状态栏和导航条的逻辑。

this.windowClass.on('windowSizeChange', (size) => {let viewWidth = px2vp(size.width);let viewHeight = px2vp(size.height);if (viewWidth > viewHeight) {// 实现横屏逻辑if (display.getFoldStatus() === display.FoldStatus.FOLD_STATUS_EXPANDED || display.getFoldStatus() === display.FoldStatus.FOLD_STATUS_HALF_FOLDED) {this.xComponentHeight = viewWidth * this.aspect;this.xComponentWidth = viewWidth;} else {this.xComponentWidth = viewHeight / this.aspect;this.xComponentHeight = viewHeight;this.isLandscape = true;}this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', false); // hide bottom navigation bar} else {// 实现竖屏逻辑this.xComponentHeight = viewWidth * this.aspect;this.xComponentWidth = viewWidth;this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', true); // show bottom navigation barthis.isLandscape = false;}
});
2、游戏类应用横屏开发

对于游戏类应用,以横屏游戏居多,此类应用不需要在应用内进行开关控制,所以只需要在module.json5配置文件中进行相应的配置即可。一般有以下几种情况:

  • 默认仅为横屏
    如果该应用默认为横屏状态,那么则需要在module.json5中的“orientation”字段进行配置为landscape。

在这里插入图片描述

  • 支持横屏和反向横屏
    如果应用需要根据设备方向,决定是横屏还是反向横屏,则可以对module.json5配置中“orientation”设置为auto_rotation_landscape。

在这里插入图片描述

注意 如果需要跟随控制中心的旋转锁定,则可以选择配置为"auto_rotation_landscape_restricted"

  • 支持竖屏切换横屏
    此类适用于一些游戏大厅等应用,由于游戏大厅内,主页可能为竖屏,部分应用为横屏。那么从竖屏进入横屏时,则需要调用设置窗口旋转方法进行窗口控制。

五、其他常见问题

1、Tabs栏中的视频横屏播放,无法隐藏Tabs栏

对于首页中有部分视频可以直接播放,并且不会跳转至详情页播放的,需要支持直接在首页发生旋转,当前可以通过设置XComponent的宽高实现,但是会发现即使全屏后,Tabs栏并不会消失。而是会一起发生旋转并存在于页面上。解决方案如下:

进入全屏时,隐藏Tabs,退出全屏时,展示Tabs栏。

@Component
struct TabsView {@State isLayoutFullScreen:boolean = false;build() {Tabs() {// ... 省略布局内容}.barHeight(this.isLayoutFullScreen ? 0 : 50) // 通过用户是否需要点击进入全屏,隐藏Tabs标签栏的高度,可以实现隐藏}
}
2、如何解决直板机和平板上默认旋转行为不一致的问题?

对于部分应用,在直板手机上默认是采用竖屏显示的策略,但是在平板或者折叠屏上,是需要支持自动旋转的,如果在Ability的生命周期中调用setPreferredOrientation,可能会出现在应用启动时,出现旋转动画的情况,所以可以将module.json5文件中的“orientation”字段设置为“follow_desktop”。

3、通过调用window.getLastWindow的方式获取窗口实例出现延迟,如何解决?

由于getLastWindow底层原因,需要经过查找获取实例,一定程度上会有性能损耗,可能会出现已经发生横屏或者竖屏切换的情况下,状态栏还没切换的情况。对此类场景的同步要求较高情况下,可以使用windowStage.getMainWindowSync的同步方式获取窗口实例。

4、自动旋转和旋转锁定按钮的关系是什么?与Orientation字段的关系如何判断?

控制中心的旋转开关控制的是当前是否可以跟随屏幕旋转,“旋转锁定”高亮状态是锁定,不可旋转。“旋转锁定”灰色是解锁状态,可以旋转。对于希望跟随控制中心的旋转开关的行为,可以选择带RESTRICTED后缀字段的旋转方式。

例如想实现跟随控制中心的自动旋转,如果想旋转到横屏,竖屏,反向横屏,反向竖屏。则可以设置为AUTO_ROTATION_RESTRICTED。

如果不想跟随控制中心的控制开关,那么只需要设置为AUTO_ROTATION,此时应用的旋转不受到控制中心的锁定控制。其他的旋转方式同理。

其他更详细内容可参见官网《最佳实践》

相关文章:

鸿蒙HarmonyOS NEXT开发:横竖屏切换开发实践

文章目录 一、概述二、窗口旋转说明1、配置module.json5的orientation字段2、调用窗口的setPreferredOrientation方法 四、性能优化1、使用自定义组件冻结2、对图片使用autoResize3、排查一些耗时操作 四、常见场景示例1、视频类应用横竖屏开发2、游戏类应用横屏开发 五、其他常…...

汇能感知宠物智能监控模块

汇能感知宠物智能监控模块 分辨率:2/3M 帧率:15-30FPS 压缩方式:H.264/H.265 APP支持:涂鸦Tuya、安居云AJcloud 配网方式:BLE蓝牙 / WiFi WIFI:2.4/5.8G WIFI 音频:单向/双向语音对讲/录…...

C# 两种方案实现调用 DeepSeek API

目录 序 开发运行环境 访问API的一个通用方法 原生官网实现 申请 API key 调用实现 调用示例 腾讯云知识引擎原子调用 申请 API key 调用示例 小结 序 DeepSeek(深度求索) 最近可谓火爆的一塌糊涂,具体的介绍这里不再赘述&#x…...

Android ndk兼容 64bit so报错

1、报错logcat如下 2025-01-13 11:34:41.963 4687-4687 DEBUG pid-4687 A #01 pc 00000000000063b8 /system/lib64/liblog.so (__android_log_default_aborter16) (BuildId: 467c2038cdfa767245f9280e657fdb85) 2025…...

计算机毕业设计——Springboot的校园新闻网站

📘 博主小档案: 花花,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 花花在深度学习任务中展现出卓越的能力,包括但不限于java、python等技术。近年来,花花更…...

Tauri Windows入门开发避坑指南

一、前置条件 在Windows上开发Tauri应用,需要先配置开发环境: windows上需要满足以下三个要求: 1.Microsoft C 构建工具 2.安装WebView2 3.下载并安装Rust 这些软件在本文附件中可以下载,如何安装请查看官方文档:htt…...

用AI绘制CAD气温曲线图

此文章视频讲解地址 https://www.bilibili.com/video/BV1JtKjenEhF 需求 根据气温的JSON数据,用AI自动生成CAD格式的气温曲线DWG图 数据准备 用deepseek获取了北京市最近一个月的气温json数据 AI对话 首先进入唯杰地图云端管理平台 选择与唯杰地图AI对话 需求描…...

什么是http请求中的session

一、引言 在现代Web开发中,Session是一个非常重要的概念。它允许服务器在多个HTTP请求之间保持用户状态,解决了HTTP协议无状态的问题。本文将详细介绍Session的工作原理、具体使用场景,并通过HTTP请求的例子来阐述其应用。 二、Session概述…...

全链路数据引擎:WhaleStudio驱动下的大数据调度与同步智能革新

在数字化转型不断加速的今天,数据已成为企业最宝贵的资产,而如何高效地处理、传输和协调这些海量数据成为企业制胜的关键。大数据调度与同步正是支撑这一核心业务的两大技术支柱。本文将详细阐述大数据调度与同步的工作原理、二者之间的紧密关系以及它们…...

PHP 中的除以零错误

除以零错误(Division by zero)是指数字除以零的情况, 这在数学上是未定义的。在 PHP 中,处理这种错误的方式取决于 PHP 版本: PHP 7: 使用 / 运算符会产生一个警告 (E_WARNING) 并返回 false。 使用 intd…...

3.2 > Bash

概览 在上一节中我们了解了关于 Shell 的执行流程,知道了在 Linux 环境中一般有哪些常用的 Shell。而在本节中,将会学习到 Linux 中最常见的一个 Shell —— Bash,了解到 bash 的相关知识和用法。 本节目录 概览相关知识bash 命令提示符bas…...

排序合集(一)

一、直接插入排序 (Insertion Sort) 基本思想 直接插入排序是一种简单直观的排序算法,就像我们打扑克牌时的操作:每次摸到一张牌,都会把它插入到手中已排好序的牌的正确位置。通过这种方式,逐步构建一个有序序列。 步骤 从第一…...

Spring:Spring实现AOP的通俗理解(有源码跟踪)

目录标题 AOP定义SpringAOP和AspectJ联系Spring如何实现AOPAOP的代理对象AOP的代理对象生成过程 AOP定义 AOP (Aspect Orient Programming):直译过来就是 面向切面编程。AOP 是一种编程思想用途:Transactions (事务调…...

通过openresty和lua实现随机壁纸

效果: 图片存放路径: /home/jobs/webs/imgs/ ├── default/ │ ├── image1.jpg │ ├── image2.png ├── cats/ │ ├── cat1.jpg │ ├── cat2.gif ├── dogs/ │ ├── dog1.jpg访问http://demo.com/imgs/default 随机返回…...

Day 36 卡玛笔记

这是基于代码随想录的每日打卡 56. 合并区间 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 示例 1…...

【Elasticsearch】match查询

Elasticsearch 的match查询是全文搜索中最常用和最强大的查询类型之一。它允许用户在指定字段中搜索文本、数字、日期或布尔值,并提供了丰富的功能来控制搜索行为和结果。以下是match查询的详细解析,包括其工作原理、参数配置和使用场景。 1.match查询的…...

MATLAB 生成脉冲序列 pulstran函数使用详解

MATLAB 生成脉冲序列 pulstran函数使用详解 目录 前言 一、参数说明 二、示例一 三、示例二 总结 前言 MATLAB中的pulstran函数用于生成脉冲序列,支持连续或离散脉冲。该函数通过将原型脉冲延迟并相加,生成脉冲序列,适用于信号处理和系统…...

开源、免费项目管理工具比较:2025最新整理30款

好用的开源、免费版项目管理系统有:1.Redmine;2. Taiga;3. OpenProject; 4.ProjectLibre; 5.GanttProject; 6.Tuleap; 7.Trac;8. Phabricator; 9.Notion; 10.…...

ffmpeg -muxers

1. ffmpeg -muxers -loglevel quiet 显示ffmpeg支持的复用器。复用器的作用是将多个独立的媒体流(如视频流、音频流、字幕流等)按照一定的格式和规则组合成一个单一的复合流;解复用器的作用与复用器相反,它将复合流分解为多个独立…...

设置mysql的主从复制模式

mysql设置主从复制模式似乎很容易,关键在于1)主库启用二进制日志,2)从库将主库设为主库。另外,主从复制,复制些什么?从我现在获得的还很少的经验来看,复制的内容有表,用户…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

django filter 统计数量 按属性去重

在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程

基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

【Zephyr 系列 16】构建 BLE + LoRa 协同通信系统:网关转发与混合调度实战

🧠关键词:Zephyr、BLE、LoRa、混合通信、事件驱动、网关中继、低功耗调度 📌面向读者:希望将 BLE 和 LoRa 结合应用于资产追踪、环境监测、远程数据采集等场景的开发者 📊篇幅预计:5300+ 字 🧭 背景与需求 在许多 IoT 项目中,单一通信方式往往难以兼顾近场数据采集…...

Shell 解释器​​ bash 和 dash 区别

bash 和 dash 都是 Unix/Linux 系统中的 ​​Shell 解释器​​,但它们在功能、语法和性能上有显著区别。以下是它们的详细对比: ​​1. 基本区别​​ ​​特性​​​​bash (Bourne-Again SHell)​​​​dash (Debian Almquist SHell)​​​​来源​​G…...