HarmonyOS 鸿蒙Next 媒体查询中,折叠屏手机折叠起来,监听器监听不到

发布于 1周前 作者 eggper 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 媒体查询中,折叠屏手机折叠起来,监听器监听不到 对于这个媒体查询的问题,出现了一下两个不理解的地方:我是计算机小白,有任何名次运用不当的地方,谢谢指正!

  1. 首先我在我的主页面,使用这个全局存储的时候,我是首先给了一个默认值是defaultvalue这个值,然后我在运行的时候,无论是普通手机模式,还是折叠屏的折叠模式,他给我的显示都是defaultvalue,并不是我在类中一个函数中,将对应的设备的型号赋值给全局存储的那个值,例如,是手机形式行该显示sm,折叠屏的展开应该实现md,这里他并没有显示sm,而是直接显示的defaultvalue这个值,但是我在折叠屏的折叠状态下把折叠屏展开,他的数值会变成md;但是,让我第一次的运行是在折叠屏的展开状态下时,他就执行的时md,不再是defaultvalue这个值,对于这里不是很理解,一开始以为是:aboutToAppear生命周期钩子可能是在页面开始构建之后才执行的,导致AppStorage的更新发生在build函数之后,初始值未被覆盖。这个原因,但是直接在折叠屏的展开运行就正常的显示md,这个原因就不成立了。这是一个问题

  2. 不能检测设备的状态变化,就在我设备从折叠屏的展开状态变为折叠状态后,按理说,他的这个md应该变为sm,但是他没有变化,一直都是md,不知道时什么原因

以上是我的两个疑问,下面是我的主要代码部分:

index.ets部分:

import { BreakPointSystem } from 'common'
// import { MainPage } from 'homelibrary'
import { BasicConstants } from '../Constants/BasicConstants'
import { BreakPointConstants } from 'common'

@Entry
@Component
struct Index {
  @State message: string = 'entry index';
  //由于我们暴露的是一个类,所以我们必须要new一个实例出来,才能调用里面的方法
  private breakpointSystem = new BreakPointSystem();
  //private breakpointconstants = new BreakPointConstants();
  //为什么这里不用实例化就可以直接访问,在这个类中,我们都是创建的静态对象,但是在BreakPointSystem中,我们创建的都是实例化对象

  //解释
  //静态成员属于类本身,不需要实例化就可以访问,而实例成员属于类的每个对象,必须通过实例来访问。
  // 用户可能没有意识到BreakPointConstants中的CURRENT_BREAKPOINT是静态的,而BreakPointSystem中的方法是非静态的,所以需要实例化才能调用。

  //全局存储一下
  @StorageProp(BreakPointConstants.CURRENT_BREAKPOINT) currentBreakpoint: string = "sm"

  //刚进入界面时
  aboutToAppear(): void {
    //console.log(add(1,2)+"")
    this.breakpointSystem.register() //进入时,我们就注册监听器
  }

  //组件销毁时
  aboutToDisappear(): void {
    this.breakpointSystem.unregister() //结束时,我们就要解除绑定,内存有利于回收,不写这个可能会造成内存泄露
  }

  build() {
    Column() {
      Text(this.message)
        .fontSize(BasicConstants.FONT_SIZE_LARGE)
        .fontWeight(FontWeight.Bold)

      Text(`当前屏幕的单位是:${this.currentBreakpoint}`)
      // //EmptyView()
      // MainPage()
      Text("纯文本")

    }
    .height(BasicConstants.FULL_WIDTH)
    .width(BasicConstants.FULL_HEIGHT)
  }
}

BreakPointSystem.ets部分:

import { BreakPointConstants } from '../constants/BreakPointConstants'
import { mediaquery } from '@kit.ArkUI';

export class BreakPointSystem {
  //首先我们要把我们当前屏幕的大小的值保存起来,保存起来以后其他的页面就都可以获取我们当前的屏幕信息了
  //媒体查询得到的单位后,我们要及那个sm md保存到全局,这时候我们要将这个currentBreakpoint作为key保存起来
  private currentBreakpoint: string = BreakPointConstants.BREAKPOINT_SM //默认的初始值就是手机
  //1. 第一步 查看屏幕的大小,并且查询屏幕的大小
  private smlistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_SM); //表示这个是手机范围。返回值是true或false
  private mdlistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_MD); //表示这个是折叠屏范围。返回值是true或false
  private lglistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_LG); //表示这个是平板范围。返回值是true或false
  private xllistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_XL); //表示这个是大屏范围。返回值是true或false

  //2. 给监听器绑定一个change事件,
  //后面每一个函数内部都要将对应的单位保存起来,我们这里直接抽取出来作为一个公共的函数
  //保存当前屏幕的检测见过,sm md lg xl 保存在应用的状态,可以保证所有的页面都可以共享
  private updateCurrentBreakpoint(breakpoint: string) {
    if (this.currentBreakpoint !== breakpoint) {
      this.currentBreakpoint = breakpoint //我的初始单位是手机类型的,如果这时候你传过来的值不是手机类型的我就更新我的数据
      //应用存储,存到全局中
      AppStorage.setOrCreate<string>(BreakPointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint)
      // 手动触发组件的重新渲染
      //this.$forceUpdate(); // 或者使用合适的机制触发重新渲染
    } else {
      AppStorage.setOrCreate<string>(BreakPointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint)
    }
  }

  //手机
  private isBreakpointSM = (mediaQueryResult: mediaquery.MediaQueryResult) => {
    // 若设备为横屏状态,matches匹配成功,更改相应的页面布局
    if (mediaQueryResult.matches) {
      //将sm 的单位保存起来
      this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_SM)
      console.log("这个是一个手机")
    }
  }
  private isBreakpointMD = (mediaQueryResult: mediaquery.MediaQueryResult) => {
    // 若设备为横屏状态,matches匹配成功,更改相应的页面布局
    if (mediaQueryResult.matches) {
      //将MD 的单位保存起来
      this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_MD)
      console.log("这个是一个折叠屏")
    }
  }
  private isBreakpointLG = (mediaQueryResult: mediaquery.MediaQueryResult) => {
    // 若设备为横屏状态,matches匹配成功,更改相应的页面布局
    if (mediaQueryResult.matches) {
      //将LG 的单位保存起来
      this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_LG)
      console.log("这个是一个平板")
    }
  }
  private isBreakpointXL = (mediaQueryResult: mediaquery.MediaQueryResult) => {
    // 若设备为横屏状态,matches匹配成功,更改相应的页面布局
    if (mediaQueryResult.matches) {
      //将XL 的单位保存起来
      this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_XL)
      console.log("这个是一个大屏")
    }
  }

  //3. 这个函数我们外面要调用,绑定监听器
  public register() {
    //重新初始化一下
    this.smlistener = mediaquery.matchMediaSync(BreakPointConstants.BREAKPOINT_SM)
    //绑定change事件
    this.smlistener.on('change', this.isBreakpointSM)

    this.mdlistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_MD); //表示这个是折叠屏范围。返回值是true或false
    this.mdlistener.on('change', this.isBreakpointMD)

    this.lglistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_LG); //表示这个是平板范围。返回值是true或false
    this.lglistener.on('change', this.isBreakpointLG)

    this.xllistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_XL); //表示这个是大屏范围。返回值是true或false
    this.xllistener.on('change', this.isBreakpointXL)
  }

  //解绑设备
  public unregister() {
    this.smlistener.off('change',this.isBreakpointSM)
    this.mdlistener.off('change',this.isBreakpointMD)
    this.lglistener.off('change',this.isBreakpointLG)
    this.xllistener.off('change',this.isBreakpointXL)
  }
}

BreakPointConstants.ets部分:

//媒体查询的断点常量
export class BreakPointConstants {
/** * Constants for breakpoint. */
  /**   * 这个单位页面上表示手机 xs就没有加入   */
  static readonly BREAKPOINT_SM: string = 'sm';
  /**   * 折叠屏可以用md来表示   */
  static readonly BREAKPOINT_MD: string = 'md';
  /**   * 一般pad端可以用lg的来表示   */
  static readonly BREAKPOINT_LG: string = 'lg';
  static readonly BREAKPOINT_XL: string = 'xl';
  /**   * The break point value.   */
  static readonly BREAKPOINT_VALUE: Array<string> = ['320vp', '600vp', '840vp', "1200vp"];
  /**   * The number of columns for SM device.   */
  //列数
  static readonly COLUMN_SM: number = 4;
  /**   * The number of columns for MD device.   */
  static readonly COLUMN_MD: number = 8;
  /**   * The number of columns for LG device.   */
  static readonly COLUMN_LG: number = 12;
  /**   * The number of gutter X for device.   */
  static readonly GUTTER_X: number = 12;
  /**   * The number of span for SM device.   */
  static readonly SPAN_SM: number = 4;
  /**   * The number of span for MD device.   */
  static readonly SPAN_MD: number = 6;
  /**   * The number of span for LG device.   */
  static readonly SPAN_LG: number = 8;
  /**   * The number of offset for MD device.   */
  static readonly OFFSET_MD: number = 1;
  /**   * The number of offset for LG device.   */
  static readonly OFFSET_LG: number = 2;
  /**   * Current breakpoints that to query the device types.   */
  //当前的单位
  static readonly CURRENT_BREAKPOINT: string = 'currentBreakpoint';
  /**   * Font size of the small device type.   */
  static readonly FONT_SIZE_SM: number = 14;
  /**   * Font size of the middle device type.   */
  static readonly FONT_SIZE_MD: number = 16;
  /**   * Font size of the large device type.   */
  static readonly FONT_SIZE_LG: number = 18;
  /**   * Cover margin of the small device type.   */
  static readonly COVER_MARGIN_SM: number = 10;
  /**   * Cover margin of the middle device type.   */
  static readonly COVER_MARGIN_MD: number = 30;
  /**   * Cover margin of the large device type.   */
  static readonly COVER_MARGIN_LG: number = 40;
  /**   * Range of the small device width.   */
  static readonly RANGE_SM: string = '(320vp<=width<600vp)';
  /**   * Range of the middle device width.   */
  static readonly RANGE_MD: string = '(600vp<=width<840vp)';
  /**   * Range of the large device width.   */
  static readonly RANGE_LG: string = '(840vp<=width<1200vp)';
  static readonly RANGE_XL: string = '(1200vp<=width)';
}

效果展示不能上传视频,抱歉啦!


更多关于HarmonyOS 鸿蒙Next 媒体查询中,折叠屏手机折叠起来,监听器监听不到的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

register函数更新一下:

public register() {

//重新初始化一下
this.smlistener = mediaquery.matchMediaSync(BreakPointConstants.BREAKPOINT_SM)
this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_SM)

//绑定change事件
this.smlistener.on('change', this.isBreakpointSM)

this.mdlistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_MD); //表示这个是折叠屏范围。返回值是true或false
this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_MD)
this.mdlistener.on('change', this.isBreakpointMD)

this.lglistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_LG); //表示这个是平板范围。返回值是true或false
this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_LG)
this.lglistener.on('change', this.isBreakpointLG)

this.xllistener = mediaquery.matchMediaSync(BreakPointConstants.RANGE_XL); //表示这个是大屏范围。返回值是true或false
this.updateCurrentBreakpoint(BreakPointConstants.BREAKPOINT_XL)
this.xllistener.on('change', this.isBreakpointXL)

}

更多关于HarmonyOS 鸿蒙Next 媒体查询中,折叠屏手机折叠起来,监听器监听不到的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


谢谢你呀,刚才试了一下,这样是不可以的,后面每一次都调用一次updateCurrentBreakpoint这个函数,后面的会把前面的值覆盖掉,这个函数不能单独拿出来调用。

  1. 可以先判断是什么设备,在aboutToAppear的时候就使用deviceInfo.deviceType来获取出是平板还是手机什么的设备。

  2. 如果是折叠屏可以试下使用getFoldStatus来判断折叠屏的状态呢,比如:

import { display } from '@kit.ArkUI';

let data: display.FoldStatus = display.getFoldStatus();
console.info('Succeeded in obtaining fold status. Data: ' + JSON.stringify(data));

然后根据FoldStatus来判断目前的屏幕展开状态。

你是目前折叠手机的适配员吗?

不是不是,我就是一个大四的学生哈哈哈,

加上的话,也没问题啊。注册的时候调用,可以用媒体查询的结果,覆盖随意的初始值。

对于折叠屏,你可以试一下,为breakpointSystem增加装饰器@State,这样屏幕尺寸发生变化,UI会同步更新。

@State private breakpointSystem = new BreakPointSystem();

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

调用的时候,函数体里面的所有内容都会执行,这个updateCurrentBreakpoint函数就是一个赋值函数,他不存在判断,肯定就是调用一次复制一次,最后的结果就是最后调用的结果呀,我试了你上面给我说的都添加一下updateCurrentBreakpoint这个的方法,测试的是不可以的。

针对HarmonyOS鸿蒙Next系统中,折叠屏手机在折叠状态下媒体查询的监听器无法正常工作的问题,可能的原因及解决方案如下:

  1. 系统权限与配置

    • 确保应用已获得必要的系统权限,特别是与屏幕状态变化相关的权限。
    • 检查应用是否在系统设置中启用了对折叠屏状态变化的监听功能。
  2. 监听器实现

    • 验证监听器的实现是否正确,包括注册与注销逻辑是否完善。
    • 确认监听器是否针对正确的屏幕状态变化事件进行了注册。
  3. 系统兼容性

    • 检查当前使用的鸿蒙系统版本是否支持折叠屏状态的监听。
    • 尝试在不同型号的折叠屏手机上复现问题,以排除特定硬件或软件版本的问题。
  4. 代码与逻辑检查

    • 仔细检查与监听器相关的代码逻辑,确保没有遗漏或错误。
    • 使用日志输出等方式,验证监听器是否被正确触发和执行。

如果上述方法均未能解决问题,可能是由于系统或硬件层面的特定问题导致。此时,建议联系鸿蒙系统的官方技术支持团队进行进一步的排查和解决。如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部