#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】 原创

是个狼灭
发布于 2025-10-27 13:31
浏览
1收藏

一、非鸿蒙响应式布局

1.核心逻辑:

用一套弹性布局适应所有尺寸,

随屏幕大小 “连续伸缩调整”,哪怕尺寸仅变化5px,布局也会平滑过渡。

2.典型表现:

小屏 1 列商品卡片→中屏 2 列→大屏 3 列,卡片大小、间距按比例同步调整,

全程仅用一套布局。

3.技术特点:

仅需 1 套布局文件,依赖媒体查询(@media)、Flex/Grid、相对单位(vw/vh),

变化呈 “连续” 特征,维护成本低但规则调试较复杂。








二、鸿蒙官方定义:响应式布局

(提示:实操部分只演示窗口对象获取断点,因为媒体用到不多)

1.核心定位

页面级 “智能结构调整能力”,

解决 “不同设备 / 屏幕特性下,页面整体结构如何优化” 的问题,

可改变组件排列、形态及交互逻辑。

2.核心能力与实现

=>断点(Breakpoint)

划分 xs(手表)sm(手机)md(折叠屏)lg(平板、2in1二合一笔记本电脑)尺寸范围

跨断点切换布局(如小屏单列→大屏双列)。


=>媒体查询

监听屏幕方向(横竖屏)、颜色模式 (深浅色) 触发布局调整

(如横屏侧边导航→竖屏底部导航)

提示: 媒体查询不常用,常用断点(Breakpoint)与 栅格布局


=>栅格布局

将页面划分为 12 列,不同断点调整子组件占列数(如小屏 12 列→大屏 6 列)。

=>响应式组件

Tabs(小屏顶部→大屏侧边)、​Grid/GridRow(自动调列数)等内置适配能力

3.技术特点(调整UI元素与UI结构)

依赖 “主动感知”(断点、媒体查询),调整页面整体结构。

是鸿蒙 “一次开发,多端部署” 的 “上层策略”,常与自适应布局配合使用。







三、获取设备可视区的宽度:

第一种实现技术响应式布局断点(常用

将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。

3.1获取设备可视区宽度vp-(旧方法:全局px2vp方法))

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('/Demo/Demo-09-1-AppStorageV2-pageone'.slice(1), (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      /*
        窗口创建时生效的onWindowStageCreate生命周期函数中,
        其形参接收的实参为系统内置的window.WindowStage窗口阶段管理对象,
        通过窗口阶段实例对象windowStage的内置方法getMainWindow中的方法可得到设备宽度的多少px,
        最后调用系统内置好的全局方法px2Vp转为我们需要的vp宽度
       */
      windowStage.getMainWindow().then((windowObj) => {
        console.log("获取的设备宽度为px单位:", windowObj.getWindowProperties().windowRect.width)
        const widthPx = windowObj.getWindowProperties().windowRect.width
        /*
        使用全局px2vp,在简单场景下可能有效,但在复杂场景下可能出现转换偏差,
        (如非UI线程或特殊上下文),全局函数可能无法正确获取设备的像素密度(dpi),导致转换精度有偏差。
        */
        const widthVp = px2vp(widthPx) // 用系统内置好的px2vp方法将px变为vp值
        console.log("得到设备宽度Vp值为:", JSON.stringify(widthVp))
      });

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

3.1.2获取手机设备的宽度效果如下:


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区

3.1.3获取平板设备的宽度效果如下:


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区


3.2获取设备宽度vp-(新方法:当前设备上下文对象中内置的px2vp方法)

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('/Demo/Demo-09-1-AppStorageV2-pageone'.slice(1), (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }

      windowStage.getMainWindow().then((windowObj) => {
        const uiContext = windowObj.getUIContext();
        const widthPx = windowObj.getWindowProperties().windowRect.width
        // 通过设备窗口上下文内置方法px2vp获取设备宽度vp
        /*
        UIContext是与当前窗口绑定的 UI 上下文,
        包含了当前窗口的设备信息(如像素密度),
        因此其px2vp方法能更精准地针对当前窗口进行单位转换,尤其在多窗口、分屏等场景下更可靠。
        */
        const widthVp = uiContext.px2vp(widthPx);
        console.info(`当前设备的宽度vp尺寸: ${widthVp}vp`);
      });

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

3.2.1获取平板设备的宽度效果如下:

#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区

3.2.2获取2in1设备(电脑或电脑平板二合一设备)的宽度效果如下:


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区



四、得到设备类型窗口对象监听窗口示例代码:

main/ets/utils/MKApplication.ets文件中代码:

@ObservedV2
export class MKApplication {  //【本地持久化存储数据的数据结构】
  @Trace newBp: string = "xs"
}
EntryAbility.ets文件中代码:

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AppStorageV2, window } from '@kit.ArkUI';
import { MKApplication } from '../utils/MKApplication';

const DOMAIN = 0x0000;


export default class EntryAbility extends UIAbility {
  // 当前的屏幕的种类 修改前
  beforeBp = ""

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('/Demo/Demo-10-windoObject_on_even-getDeviceType'.slice(1), (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      // 【1.获取窗口对象,再传递局部函数进行判断设备类型】
      windowStage.getMainWindow().then((windowClass) => {


        // 马上得到了 窗口尺寸 存在全局
        this.updateBreakpoint(windowClass)

        //  【设备窗口可见区域尺寸发生变化,也应该再次调用局部函数,更新本地存储中的设备类型】
        windowClass.on('windowSizeChange', () => {
          this.updateBreakpoint(windowClass)
        })


      });

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }

  //【》》2.接收传递过来的窗口对象,获取设备窗口宽度,进行判断属于哪个断点区间,确定是什么类型的设备《《】
  private updateBreakpoint(windowClass: window.Window): void {
    try {
      const uiContext = windowClass.getUIContext();
      const widthPx = windowClass.getWindowProperties().windowRect.width
      const windowWidthVp = uiContext.px2vp(widthPx);
      console.log('当前设备的尺寸宽度:' + windowWidthVp)
      let newBp: string = ''
      //【》》得到当前窗口可视区域宽度vp值,进行判断当前设备属于什么类型设备《《】
      if (windowWidthVp < 320) {
        newBp = 'xs'
      } else if (windowWidthVp < 600) {
        newBp = 'sm'
      } else if (windowWidthVp < 840) {
        newBp = 'md'
      } else {
        newBp = 'lg'
      }
      // 如果上次的设备类型等于最新的设备类型那就不用更新本地存储中的设备类型
      //(比如说[0,320)之间都属于sm类型设备)
      if (this.beforeBp === newBp) {
        return
      }
      // 本地持久化存储设备类型
      const mkAPP = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!
      mkAPP.newBp = newBp
      this.beforeBp = newBp // 上次的设备类型被赋值为当前的设备类型
    } catch (err) {
      console.log("getDisplayByIdSync failed err" + err.code)
    }
  }
}
Demo测试文件代码:

import { MKApplication } from '../utils/MKApplication'
import { AppStorageV2 } from '@kit.ArkUI'

@ComponentV2
@Entry
struct Index {
  // 【获取本地全局存储的数据=>当前的设备类型】
  @Local mkAPP: MKApplication = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!

  build() {
    Column() {
      Button('当前的设备类型为:' + this.mkAPP.newBp)
        .fontWeight(700)
        .fontSize(30)
    }
    .width("100%")
    .height("100%")
    .backgroundColor(Color.Brown)
    .justifyContent(FlexAlign.Center)
  }
}
效果图如下:


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区



#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区


五、封装断点工具类

=>实现不同的设备类型,可实现不同的样式变化

5.1.首先定义本地存储中的数据结构(PersistenceV2.connect第一个参数需传数据类型)

=>main/ets/utils/MKApplication.ets文件中代码:

@ObservedV2
export class MKApplication {  //【本地持久化存储数据的数据结构】
  @Trace newBp: string = "xs"
}


5.2.窗口对象方法获取设备宽度,然后判断出设备类型持久化全局存储到本地中

=>EntryAbility.ets文件中代码:

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AppStorageV2, window } from '@kit.ArkUI';
import { MKApplication } from '../utils/MKApplication';

const DOMAIN = 0x0000;


export default class EntryAbility extends UIAbility {
  // 当前的屏幕的种类 修改前
  beforeBp = ""

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('/Demo/Demo-10-windoObject_on_even-getDeviceType'.slice(1), (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      // 【1.获取窗口对象,再传递局部函数进行判断设备类型】
      windowStage.getMainWindow().then((windowClass) => {


        // 马上得到了 窗口尺寸 存在全局
        this.updateBreakpoint(windowClass)

        //  【设备窗口可见区域尺寸发生变化,也应该再次调用局部函数,更新本地存储中的设备类型】
        windowClass.on('windowSizeChange', () => {
          this.updateBreakpoint(windowClass)
        })


      });

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }

  //【》》2.接收传递过来的窗口对象,获取设备窗口宽度,进行判断属于哪个断点区间,确定是什么类型的设备《《】
  private updateBreakpoint(windowClass: window.Window): void {
    try {
      const uiContext = windowClass.getUIContext();
      const widthPx = windowClass.getWindowProperties().windowRect.width
      const windowWidthVp = uiContext.px2vp(widthPx);
      console.log('当前设备的尺寸宽度:' + windowWidthVp)
      let newBp: string = ''
      //【》》得到当前窗口可视区域宽度vp值,进行判断当前设备属于什么类型设备《《】
      if (windowWidthVp < 320) {
        newBp = 'xs'
      } else if (windowWidthVp < 600) {
        newBp = 'sm'
      } else if (windowWidthVp < 840) {
        newBp = 'md'
      } else {
        newBp = 'lg'
      }
      // 如果上次的设备类型等于最新的设备类型那就不用更新本地存储中的设备类型
      //(比如说[0,320)之间都属于sm类型设备)
      if (this.beforeBp === newBp) {
        return
      }
      // 本地持久化存储设备类型
      const mkAPP = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!
      mkAPP.newBp = newBp
      this.beforeBp = newBp // 上次的设备类型被赋值为当前的设备类型
    } catch (err) {
      console.log("getDisplayByIdSync failed err" + err.code)
    }
  }
}

5.3.封装BreakPointType工具类

=>main/ets/utils/breakpointSystem.ets文件中代码:

/* 封装好的工具类BreakPointType注解如下: */
interface BreakPointTypeOption<T> {
  xs?: T
  sm?: T
  md?: T
  lg?: T
}

//【1.封装工具类BreakPointType】
export class BreakPointType<T> {
  //【》》注意点1: 基于BreakPointTypeOption接口创建对象《《】
  options: BreakPointTypeOption<T>
  //【2.实例化此类创建对象时需传递实参=>数据类型为BreakPointTypeOption<T>,也是个对象】
  // 传递举例: { xs: Color.Red}、{ xs: '我是手环', sm: '我是实际'}
  // 【》》简单来说传递=> 什么设备类型下,你想得到什么值《《】
  constructor(option: BreakPointTypeOption<T>) {
    this.options = option
  }
  //【3.实例化对象后,必须调用此方法传入本地存储中记录的当前设备类型】
  /*》》注意点2: BreakPointTypeOption接口创建的对象
        =>进行逻辑判断,返回之前实例化对象时:相应设备类型所对应的属性值《《】*/
  getValue(currentBreakPoint: string) {
    if (currentBreakPoint === 'xs') {
      return this.options.xs
    } else if (currentBreakPoint === 'sm') {
      return this.options.sm
    } else if (currentBreakPoint === 'md') {
      return this.options.md
    } else if (currentBreakPoint === 'lg') {
      return this.options.lg
    } else {
      return undefined
    }
  }
}

5.4.使用封装好的工具类示例代码:

【注意点:

  平板设备中窗口可见区域宽度最多只能缩小至320,所以展示不出xs设备相应的样式效果】

=>实现xs设备时背景色Red

=>实现sm设备时背景色Green

=>实现md设备时背景色Blue

=>实现lg设备时背景色Pink

import { PersistenceV2 } from '@kit.ArkUI'
import { MKApplication } from '../utils/MKApplication'
import { BreakPointType } from '../utils/breakpointSystem'

@Entry
@ComponentV2
struct use_BreakPointType {
  // 【1.获取本地全局存储的数据=>当前的设备类型】
  @Local mkAPP: MKApplication = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!

  build() {
    Column() {
      Button(`当前是${this.mkAPP.newBp}类型设备`)
        .fontWeight(700)
        .fontSize(30)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    // 【2.使用工具类传递相应设备类型对应的样式,
    //  传递本地存储中的当前设备类型=>工具不同的设备类型,设置不同的样式】
    .backgroundColor(new BreakPointType({
      //【注意点:平板设备中的窗口可见区域宽度最多只能缩小至320,所以展示不出来xs设备相应的样式效果】
      xs: Color.Red,
      sm: Color.Green,
      md: Color.Blue,
      lg: Color.Pink
    }).getValue(this.mkAPP.newBp))
  }
}

5.5.效果如下:

#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区



#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区


#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区




六、实操响应式布局-断点

6.1MKApplication.ets文件中代码

=>(本地持久化存储设备类型数据的数据结构)

@ObservedV2
export class MKApplication {
  @Trace
  newBp: string = "xs"
}


6.2EntryAbility.ets文件中代码

=>(窗口对象动态静态当前设备类型记录存储到本地中)

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AppStorageV2, PersistenceV2, window } from '@kit.ArkUI';
import { MKApplication } from '../utils/MKApplication';

const DOMAIN = 0x0000;


export default class EntryAbility extends UIAbility {
  // 当前的屏幕的种类 修改前
  beforeBp = ""

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('/Demo/Demo-12-case-Grid_use_BreakPointType'.slice(1), (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      // 【1.获取窗口对象,再传递局部函数进行判断设备类型】
      windowStage.getMainWindow().then((windowClass) => {

        // 马上得到了 窗口尺寸 存在全局
        this.updateBreakpoint(windowClass)

        //  【设备窗口可见区域尺寸发生变化,也应该再次调用局部函数,更新本地存储中的设备类型】
        windowClass.on('windowSizeChange', () => {
          this.updateBreakpoint(windowClass)
        })

      });

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }

  // 【》》2.接收传递过来的窗口对象,获取设备窗口宽度,进行判断属于哪个断点区间,确定是什么类型的设备《《】
  private updateBreakpoint(windowClass: window.Window): void {
    try {
      const uiContext = windowClass.getUIContext();
      const widthPx = windowClass.getWindowProperties().windowRect.width
      const windowWidthVp = uiContext.px2vp(widthPx);
      console.log('当前设备的尺寸宽度:' + windowWidthVp)
      let newBp: string = ''
      //  核心代码2: 基于窗口宽度vp值,判断当前设备属于哪个断点范围
      if (windowWidthVp < 320) {
        newBp = 'xs'
      } else if (windowWidthVp < 600) {
        newBp = 'sm'
      } else if (windowWidthVp < 840) {
        newBp = 'md'
      } else {
        newBp = 'lg'
      }
      // 如果上次的设备类型等于最新的设备类型那就不用更新本地存储中的设备类型(比如说[0,320)之间都属于sm类型设备)
      if (this.beforeBp === newBp) {
        return
      }
      // 本地持久化存储设备类型
      const mkAPP = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!
      mkAPP.newBp = newBp
      this.beforeBp = newBp // 上次的设备类型被赋值为当前的设备类型
    } catch (err) {
      console.log("getDisplayByIdSync failed err" + err.code)
    }
  }
}



6.3示例文件中代码:

/*

 目标: 使用封装的断点工具类

 =>实现当前设备是xs与sm时单列排布图片

 =>实现当前设备是md时二列排布图片

 =>实现当前设备是lg时三列排布图片

*/

import { MKApplication } from '../utils/MKApplication'
import { PersistenceV2 } from '@kit.ArkUI'
import { BreakPointType } from '../utils/breakpointSystem'

interface Img {
  title: string
  src: ResourceStr
}

@Entry
@ComponentV2
struct ase_Grid_use_BreakPointType {
  // 1.定义需渲染的数据源
  myImgArr: Img[] = [
    { title: '俺的【华为mate70】拍摄的月亮1', src: $r('app.media.1') },
    { title: '俺的【华为mate70】拍摄的月亮2', src: $r('app.media.2') },
    { title: '俺的【华为mate70】拍摄的月亮3', src: $r('app.media.3') },
    { title: '俺的【华为mate70】拍摄的图片1', src: $r('app.media.4') },
    { title: '俺的【华为mate70】拍摄的图片2', src: $r('app.media.5') },
    { title: '俺的【华为mate70】拍摄的图片3', src: $r('app.media.6') }
  ]
  @Local mkAPP: MKApplication = PersistenceV2.connect(MKApplication, MKApplication.name, () => new MKApplication())!

  build() {
    //【提示=>Grid默认继承父级100%宽,而高需要自己设置,或者由子级元素撑大】
    //2.Grid组件,基于本地存储的当前设备类型与封装的断点工具类,实现不同设备类型组件进行不同的排布(针对列)
    Grid() {
      ForEach(this.myImgArr, (item: Img) => {
        GridItem() {
          Column({ space: 10 }) {
            Image(item.src)
              .borderRadius(10)
            Text(item.title)
              .backgroundColor(Color.Brown)
              .fontColor(Color.White)
              .fontWeight(700)
              .fontSize(22)
          }
        }
      })
    }
    .rowsGap(10)
    .columnsGap(10)
    .padding(10)
    .columnsTemplate(new BreakPointType({
      //【2.使用断点工具,传递不同设备类型与需要设置的样式效果】
      xs: '1fr ',
      sm: '1fr ',
      md: '1fr 1fr',
      lg: '1fr 1fr 1fr'
    }).getValue(this.mkAPP.newBp)) // 传递当前设备类型=>动态的改变组件排布
    .linearGradient({
      colors: [['#fed6e3', 0], ['#a8edea', 0.5], ['#f9f586', 1]],
      direction: GradientDirection.Right
    })
  }
}


6.4效果【图片素材真机拍摄】:

#星光不负 码向未来# 全网最详细的鸿蒙响应式布局带实操【干货满满】-鸿蒙开发者社区









©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2025-10-28 09:36:46修改
2
收藏 1
回复
举报
6条回复
按时间正序
/
按时间倒序
べ_D
べ_D

太好了干货又更新了


1
回复
2025-10-27 14:21:41
是个狼灭
是个狼灭 回复了 べ_D
太好了干货又更新了

必须的


回复
2025-10-27 14:22:25
hjl_22
hjl_22

可以依旧干货

1
回复
2025-10-27 21:05:48
是个狼灭
是个狼灭 回复了 hjl_22
可以依旧干货

必须的

1
回复
2025-10-28 08:20:26
hm688c720cccb5b
hm688c720cccb5b

干货满满

1
回复
2025-10-28 11:34:40
是个狼灭
是个狼灭 回复了 hm688c720cccb5b
干货满满

必须的

回复
2025-10-28 11:44:38
回复
    相关推荐