鸿蒙多端适配,响应式断点解决方案

224 阅读2分钟

鸿蒙多端适配响应式断点解决方案

1获取屏幕尺寸,注册监听事件(entryability)

  export default class EntryAbility extends UIAbility {
    ......
   private windowObj?: window.Window
  private curBp: string = ''
     private updateBreakpoint(windowWidth: number) :void{
     // 拿到当前窗口对象获取当前所在displayId
   let displayId = this.windowObj?.getWindowProperties().displayId

     // 将长度的单位由px换算为vp
     let windowWidthVp = windowWidth / display.getDisplayByIdSync(displayId).densityPixels
    let newBp: string = ''
    if (windowWidthVp < 320) {
      newBp = 'xs'
    } else if (windowWidthVp < 600) {
      newBp = 'sm'
    } else if (windowWidthVp < 840) {
      newBp = 'md'
    } else {
      newBp = 'lg'
    }
    if (this.curBp !== newBp) {
      this.curBp = newBp
      // 使用状态变量记录当前断点值
      AppStorage.setOrCreate('currentBreakpoint',
      this.curBp)
    }
     }
  .....
    onWindowStageCreate(windowStage: window.WindowStage) :void{
      // 注册监听窗口尺寸变化
     windowStage.getMainWindow().then((windowObj) => {
      this.windowObj = windowObj
      // 获取应用启动时的窗口尺寸
      this.updateBreakpoint(windowObj.getWindowProperties().windowRect.width)
      // 注册回调函数,监听窗口尺寸变化
      windowObj.on('windowSizeChange', (windowSize)=>{
        this.updateBreakpoint(windowSize.width)
      })
    });
  }
     .....
  } 

封装一个基于断点判断的工具类


// 断点常量
export class BreakpointConstants {
  // 手表等超小屏
  static readonly XS: string = 'xs';
  // 手机竖屏
  static readonly SM: string = 'sm';
  // 手机横屏,折叠屏
  static readonly MD: string = 'md';
  // 平板,2in1 设备
  static readonly LG: string = 'lg';
  // AppStorage 中的 key
  static readonly BREAK_POINT_KEY: string = 'currentBreakpoint'
}


declare interface BreakPointTypeOption<T> {
  xs?: T
  sm?: T
  md?: T
  lg?: T
}

export class BreakPointType<T> {
  options: BreakPointTypeOption<T>

  constructor(option: BreakPointTypeOption<T>) {
    this.options = option
  }

  // 根据断点取值
  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
    }
  }
}

3.使用

import { BreakpointConstants, BreakPointType } from '../model'

@Entry
@Component
struct test {
  list: string[] = ['首页', '方向', '分享', '我的']
  @StorageProp(BreakpointConstants.BREAK_POINT_KEY) breakPoint:string=''
  build() {
    Tabs() {
      ForEach(this.list, (item: string, index) => {
        TabContent() {
          if (index == 0) {
            this.testlist()
          } else {
            Text(item)
          }
        }.tabBar(this.breakPoint)
      })
    }.barPosition(BarPosition.Start)
    .vertical(this.breakPoint === BreakpointConstants.LG ? true : false)
  }

  @Builder
  testlist() {
    Scroll(){

    WaterFlow() {
      ForEach(Array.from({ length: 20 }), (i: string) => {
        FlowItem(){
        Text()
          .width('100%')
          .height(300)
        }.backgroundColor('#888')

      })
//使用断点工具类就可以进行响应式布局
    }.columnsTemplate(new BreakPointType<string>({
      xs: '1fr',
      sm: '1fr',
      md: '1fr 1fr',
      lg: '1fr 1fr 1fr '
    }).getValue(this.breakPoint))
      .rowsGap(10)
      .columnsGap(10)
    }
    .width('100%')
    .height('100%')

  }
}

运行效果

平板端

836beb2e-7253-448a-8029-692deb35aefd.png

折叠屏端

1d71c65b-36d4-42a9-b203-91c0b0618456.png

手机端

2bf7ca84-47b7-477d-a6e3-a7afa02981de.png

断点工具可以进行很多适配比如宽高也可以使用断点工具来对不同屏幕进行适配!