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

news2025/2/13 19:11:06

文章目录

      • 一、概述
      • 二、窗口旋转说明
        • 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 bar
    this.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,此时应用的旋转不受到控制中心的锁定控制。其他的旋转方式同理。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297512.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Spring Security 6的OAuth2 系列之十五 - 高级特性--客户端认证方式

之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…

排序合集之快排详解(二)

摘要:快速排序是一种在实践中广泛使用的高效排序算法。它基于分治策略,平均时间复杂度为O(n log n),使其成为处理大型数据集的理想选择。本文将深入探讨快速排序的各种实现方式、优化技巧以及非递归实现,并通过C语言代码示例进行详…

前缀树算法篇:前缀信息的巧妙获取

前缀树算法篇:前缀信息的巧妙获取 那么前缀树算法是一个非常常用的算法,那么在介绍我们前缀树具体的原理以及实现上,我们先来说一下我们前缀树所应用的一个场景,那么在一个字符串的数据集合当中,那么我们查询我们某个字…

大数据系列 | 白话讲解大数据技术生态中Hadoop、Hive、Spark的关系介绍

大数据属于数据管理系统的范畴,数据管理系统无非就两个问题:数据怎么存、数据怎么算    现在的信息爆炸时代,一台服务器数据存不下,可以找10台服务器存储,10台存储不下,可以再找100台服务器存储。但是这1…

华为云函数计算FunctionGraph部署ollma+deepseek

1 概述 ollama和deepseek如果需要多实例,一种方式是部署在kubernetes集群中,一种是使用云厂商的云函数服务。云函数服务是按量付费,并且底层支持GPU,不需要维护kubernetes集群。本文介绍使用华为云函数计算FunctionGraph来部署ol…

尚硅谷爬虫note001

一、模板设置 file——setting——editor——code style——file and code template——python script # _*_ coding : utf-8 _*_ # Time : ${DATE} ${TIME} # Author : 20250206-里奥 # File : ${NAME} # Project : ${PROJECT_NAME} 二、数据类型 2-1. 数字 整型int 浮点型f…

35~37.ppt

目录 35.张秘书-《会计行业中长期人才发展规划》 题目​ 解析 36.颐和园公园(25张PPT) 题目​ 解析 37.颐和园公园(22张PPT) 题目 解析 35.张秘书-《会计行业中长期人才发展规划》 题目 解析 插入自定义的幻灯片:新建幻灯片→重用…

FPGA简介|结构、组成和应用

Field Programmable Gate Arrays(FPGA,现场可编程逻辑门阵列),是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物, 是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的&#xff0c…

4. React 中的 CSS

用例中的干净的脚手架的创建可以参考另一篇文章:3.React 组件化开发React官方并没有给出在React中统一的样式风格: 由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百…

django中间件,中间件给下面传值

1、新建middleware.py文件 # myapp/middleware.py import time from django.http import HttpRequest import json from django.http import JsonResponse import urllib.parse from django.core.cache import cache from comm.Db import Db class RequestTimeMiddleware:def …

【论文阅读】Revisiting the Assumption of Latent Separability for Backdoor Defenses

https://github.com/Unispac/Circumventing-Backdoor-Defenses 摘要和介绍 在各种后门毒化攻击中,来自目标类别的毒化样本和干净样本通常在潜在空间中形成两个分离的簇。 这种潜在的分离性非常普遍,甚至在防御研究中成为了一种默认假设,我…

Python基于Django的微博热搜、微博舆论可视化系统(V3.0)【附源码】

博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…

不小心删除服务[null]后,git bash出现错误

不小心删除服务[null]后,git bash出现错误,如何解决? 错误描述:打开 git bash、msys2都会出现错误「bash: /dev/null: No such device or address」 问题定位: 1.使用搜索引擎搜索「bash: /dev/null: No such device o…

【云安全】云原生- K8S kubeconfig 文件泄露

什么是 kubeconfig 文件? kubeconfig 文件是 Kubernetes 的配置文件,用于存储集群的访问凭证、API Server 的地址和认证信息,允许用户和 kubectl 等工具与 Kubernetes 集群进行交互。它通常包含多个集群的配置,支持通过上下文&am…

【工业场景】用YOLOv8实现火灾识别

火灾识别任务是工业领域急需关注的重点安全事项,其应用场景和背景意义主要体现在以下几个方面: 应用场景:工业场所:在工厂、仓库等工业场所中,火灾是造成重大财产损失和人员伤亡的主要原因之一。利用火灾识别技术可以及时发现火灾迹象,采取相应的应急措施,保障人员安全和…

(2025)深度分析DeepSeek-R1开源的6种蒸馏模型之间的逻辑处理和编写代码能力区别以及配置要求,并与ChatGPT进行对比(附本地部署教程)

(2025)通过Ollama光速部署本地DeepSeek-R1模型(支持Windows10/11)_deepseek猫娘咒语-CSDN博客文章浏览阅读1k次,点赞19次,收藏9次。通过Ollama光速部署本地DeepSeek-R1(支持Windows10/11)_deepseek猫娘咒语https://blog.csdn.net/m0_70478643/article/de…

【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)

文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句(Python源码实现) 一、TextRank 算法提取关键词 [工具包] 见链接 【自然语言处理】TextRank 算法…

记一次Self XSS+CSRF组合利用

视频教程在我主页简介或专栏里 (不懂都可以来问我 专栏找我哦) 目录:  确认 XSS 漏洞 确认 CSRF 漏洞 这个漏洞是我在应用程序的订阅表单中发现的一个 XSS 漏洞,只能通过 POST 请求进行利用。通常情况下,基于 POST 的…

JDBC如何连接数据库

首先,我们要去下载JDBC的驱动程序 官网下载地址:https://downloads.mysql.com/archives/c-j/ 选择最新版本就可以 然后回到我们idea点击file - project Structure - Modules, 就行了 参考1:如何解决JDBC连接数据库出现问题且对进行数据库操…

AI语言模型的技术之争:DeepSeek与ChatGPT的架构与训练揭秘

云边有个稻草人-CSDN博客 目录 第一章:DeepSeek与ChatGPT的基础概述 1.1 DeepSeek简介 1.2 ChatGPT简介 第二章:模型架构对比 2.1 Transformer架构:核心相似性 2.2 模型规模与参数 第三章:训练方法与技术 3.1 预训练与微调…