不到断气不罢休 发表于 2025-1-19 15:09:13

HarmonyOS相应式布局

布局

自顺应布局

详情见开辟文档
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/adaptive-layout-V13
相应式布局

断点


[*] 以应用窗口为切入点,将应用窗口在宽维度上分成几个差异的区间即差异的断点,在差异的区间下,根据需求实现差异的页面布局效果
[*] 即将断点将窗口分别为差异的范围,监听窗口的变化(需使用到BreakpointSystem类)
[*] https://i-blog.csdnimg.cn/direct/5d3296d7ffb4450e9fac08007211d101.png#pic_center
[*] 常见的监听断点变化的方法:

[*]获取窗口对象,并监听窗口尺寸变化
[*]通过媒体查询监听应用窗口尺寸变化
[*]借助栅格组件本领监听差异断点的变化

媒体查询


[*]媒体查询作为相应式计划的焦点,在移动装备应用上非常广泛
[*]媒体查询提供了丰富的媒体特性监听本领,监听表现地域的变化,横竖屏,深浅色,装备类型
案例一

breakPointSystem.ets
// common/breakpointsystem.ets
import { mediaquery } from '@kit.ArkUI'

//断点类型
export type BreakpointType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'

//断点
export interface Breakpoint {
//类型
name: BreakpointType
//值
size: number
//媒体查询的句柄,并包含了申请句柄时的首次查询结果。媒体查询根据设置的条件语句,
// 比如'(width <= 600vp)',比较系统信息,若首次查询时相关信息未初始化,matches返回false。
// 定义MediaQuery监听器
mediaQueryListener?: mediaquery.MediaQueryListener
}

// 断点查询方法类
export class BreakpointSystem {

private static instance: BreakpointSystem
//断点值(设置为只读)
private readonly breakpoints: Breakpoint[] = [
    { name: 'xs', size: 0 },
    { name: 'sm', size: 320 },
    { name: 'md', size: 600 },
    { name: 'lg', size: 840 }
]
//是一系列无序,没有重复数值的数据集合。
private states: Set<BreakpointState<Object>>

private constructor() {
    this.states = new Set()
}
//获得实例
public static getInstance(): BreakpointSystem {
    if (!BreakpointSystem.instance) {
      BreakpointSystem.instance = new BreakpointSystem();
    }
    return BreakpointSystem.instance
}

//增加状态(给set集合中添加状态)
public attach(state: BreakpointState<Object>): void {
    this.states.add(state)
}

//删除状态(从set集合中删除状态)
public detach(state: BreakpointState<Object>): void {
    this.states.delete(state)
}

public start() {
    // 遍历循环设置的断点值
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      //条件设置
      let condition: string
      if (index === this.breakpoints.length - 1) {
      condition = `(${breakpoint.size}vp<=width)`
      } else {
      condition = `(${breakpoint.size}vp<=width<${this.breakpoints.size}vp)`
      }
      //设置媒体查询的查询条件,并返回对应的监听句柄。
      //mediaQueryListener 媒体查询的句柄,并包含了申请句柄时的首次查询结果。
      // 媒体查询根据设置的条件语句,比如'(width <= 600vp)',
      // 比较系统信息,若首次查询时相关信息未初始化,matches返回false。
      // matchMediaSync:设置媒体查询的操作,并返回相对应的监听句柄(breakpoint.mediaQueryListener)
      breakpoint.mediaQueryListener = mediaquery.matchMediaSync(condition)
      // 判断是否满足匹配的条件
      if (breakpoint.mediaQueryListener.matches) {
      //更新状态
      this.updateAllState(breakpoint.name)
      }
      // 监听状态
      breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
      if (mediaQueryResult.matches) {
          console.log(`当前屏幕状态态为:${breakpoint.name}`)
          console.log(`当前屏幕大小为:${breakpoint.size}`)
          AppStorage.setOrCreate('currentBreakpoint',breakpoint.name)
          //监听并更新状态
          this.updateAllState(breakpoint.name)

      }
      })
    })
}

private updateAllState(type: BreakpointType): void {
    this.states.forEach((state): Object | undefined => state.update(type))
}

public stop() {
    //停止监听并清除状态
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      if (breakpoint.mediaQueryListener) {
      breakpoint.mediaQueryListener.off('change')
      }
    })
    this.states.clear()
}
}

// 可间断点可选项
export interface BreakpointOptions<T> {
xs?: T
sm?: T
md?: T
lg?: T
xl?: T
xxl?: T
}

export class BreakpointState<T extends Object> {
public value: T | undefined = undefined;
private options: BreakpointOptions<T>

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

// 开发者自定义对应断点的返回参数
static of<T extends Object>(options: BreakpointOptions<T>): BreakpointState<T> {
    return new BreakpointState(options)
}

// 更新and返回开发者需要的且设置的值
// breakpointType:断点的类型
public update(type: BreakpointType) {
    if (type === 'xs') {
      //this.options.xs 开发者给予的值
      this.value = this.options.xs
      return this.value
    } else if (type === 'sm') {
      this.value = this.options.sm
      return this.value
    } else if (type === 'md') {
      this.value = this.options.md
      return this.value
    } else if (type === 'lg') {
      this.value = this.options.lg
      return this.value
    } else if (type === 'xl') {
      this.value = this.options.xl
      return this.value
    } else if (type === 'xxl') {
      this.value = this.options.xxl
      return this.value
    } else {
      this.value = undefined
      return this.value
    }
}
}
// 创建断点枚举类,提供静态常量表示不同的断点
export class BreakpointTypeEnum {
static readonly SM: string = 'sm'; // 小屏幕断点
static readonly MD: string = 'md'; // 中等屏幕断点
static readonly LG: string = 'lg'; // 大屏幕断点
}

mediaquery.ets

[*]设置变量吸收状态值
[*]获取BreakpointSystem实例,并将状态值添加进去
[*]获取BreakpointSystem实例,屏幕进行监听
[*]将状态删除
[*]取消监听屏幕
import { BreakpointSystem,BreakpointState } from '../common/breakPointSystem'


@Entry
@Component
struct Mediaquery {
//设置状态值(是该状态返回显示的字符)
@State compStr:BreakpointState<string> = BreakpointState.of({
    sm:"sm",
    md:"md",
    lg:"lg",
})
aboutToAppear(): void {
    //将设置好的状态值添加
    BreakpointSystem.getInstance().attach(this.compStr)
    //监听屏幕状态
    BreakpointSystem.getInstance().start()
}
aboutToDisappear(): void {
    //将状态删除
    BreakpointSystem.getInstance().detach(this.compStr)
    //取消监听屏幕状态
    BreakpointSystem.getInstance().stop()
}
build() {
    Column(){
      Text(this.compStr.value)
      .fontSize(24)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
}
}
案例二

TabPage

import { DisplayUtil } from '@pura/harmony-utils'
import {
BreakpointSystem,
BreakpointState,
BreakpointType,
Breakpoint,
BreakpointTypeEnum
} from '../common/breakPointSystem'
import Home from '../Component/Home'
// 学习地图
import Learning_map from '../Component/Learning_map'
import display from '@ohos.display'


class tabItem {
title: string = ''
tabIndex: number = 0
Icon: ResourceStr = ''
selectIcon: ResourceStr = ''
}

@Entry
@Component
struct TabPage {
@Provide pageInfo: NavPathStack = new NavPathStack()
@State foldStatusStr: string = ''
@State compStr: BreakpointState<string> =
    BreakpointState.of({
      sm: 'sm',
      md: 'md',
      lg: 'lg'
    });
//定义一个断点的初始值
private BreakPointType_Lg: BreakpointType = 'lg';

aboutToAppear(): void {
    //将定义的断点值添加至断点状态
    BreakpointSystem.getInstance().attach(this.compStr)
    //开始监听屏幕断点
    BreakpointSystem.getInstance().start()
    //监听可折叠设备的状态
    display.on('foldStatusChange', (data: display.FoldStatus) => {
      this.foldStatusStr = JSON.stringify(data)
      console.info(`<<< `+JSON.stringify(data))
      console.log(`<<<+++>>>${this.foldStatusStr}`)
      AppStorage.setOrCreate('foldStatusStr', this.foldStatusStr)
    })

}

aboutToDisappear(): void {
    //删除断点状态
    BreakpointSystem.getInstance().detach(this.compStr)
    //停止监听屏幕断点
    BreakpointSystem.getInstance().stop()

}

//使用@StorageProp 装饰器从存储中读取当前断点,默认值为中屏幕
@StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
//定义标签页的索引
@State currentIndex: number = 0
//创建Tabs控制器
private tabsController: TabsController = new TabsController()

//定义构建器方法,创建标签项
@Builder
tabBarItem(tabItem: tabItem) {
    //创建垂直排列容器间距为5
    Column({ space: 5 }) {
      //显示图片,根据是否选中采用不同的图片
      Image(this.currentIndex === tabItem.tabIndex ? tabItem.selectIcon : tabItem.Icon)
      .width(32)
      .aspectRatio(1)
      .objectFit(ImageFit.Contain)
      //标签文字,根据是否选中采用不同的颜色
      Text(tabItem.title)
      .font({
          size: 14,
          weight: 600
      })
      .fontColor(
          this.currentIndex === tabItem.tabIndex ?
          $r('sys.color.ohos_id_color_focused_outline') : '#3c3c3c'
      )
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)

}

build() {
    Tabs({
      //Tab页签的一多适配
      barPosition: this.currentBreakPoint
      == BreakpointTypeEnum.LG ? BarPosition.Start : BarPosition.End
    }) {
      TabContent() {
      Home()
      }
      .tabBar(this.tabBarItem({
      title: '快速入门',
      tabIndex: 0,
      Icon: $r('app.media.ic_01_off'),
      selectIcon: $r('app.media.ic_01_on'),
      }))

      TabContent()
      .tabBar(this.tabBarItem({
          title: '课程学习',
          tabIndex: 1,
          Icon: $r('app.media.ic_02_off'),
          selectIcon: $r('app.media.ic_02_on'),
      }))
      TabContent() {
      Learning_map()
      }
      .tabBar(this.tabBarItem({
      title: '知识地图',
      tabIndex: 2,
      Icon: $r('app.media.ic_03_off'),
      selectIcon: $r('app.media.ic_03_on'),
      }))
    }
    // 页签切换进行截取
    .onContentWillChange((currentIndex, comingIndex) => {
      console.log(`当前的页签${currentIndex}`)
      console.log(`将要显示的页签${comingIndex}`)
      if (comingIndex === 2) {
      if (this.currentBreakPoint != BreakpointTypeEnum.SM) {
          this.pageInfo.pushPath({
            name: 'OnePage'
          })
      } else {
          this.pageInfo.clear()
      }
      }
      return true
    })
    // ********************灵魂!!!!
    // 用this.currentBreakPoint当前设备的值进行比对
    .barWidth(
      BreakpointState.of({
      sm: '100%',
      md: '100%',
      lg: '80vp'
      }).update(this.currentBreakPoint)
    )
    .onChange((index: number) => {
      //将当前索引变为点击的目标索引
      this.currentIndex = index
    })
    // 在确定制表符是否垂直时调用 默认false
    .vertical(this.currentBreakPoint == BreakpointTypeEnum.LG ? true : false)

}
}
Home

import {
BreakpointSystem,
BreakpointState,
BreakpointType,
Breakpoint,
BreakpointTypeEnum
} from '../common/breakPointSystem'

@Entry
@Component
export default struct Home {
@State compStr: BreakpointState<string> =
    BreakpointState.of({
      sm: 'sm',
      md: 'md',
      lg: 'lg'
    });
//定义一个断点的初始值
private BreakPointType_Lg: BreakpointType = 'lg';
//使用@StorageProp 装饰器从存储中读取当前断点,默认值为中屏幕
@StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
@State list_swiper: ResourceStr[] = [
    $r('app.media.banner_pic0'),
    $r('app.media.banner_pic1'),
    $r('app.media.banner_pic2'),
    $r('app.media.banner_pic3'),
    $r('app.media.banner_pic4'),
    $r('app.media.banner_pic5')
]
@State list_Grid: Resource[] = [
    $r('app.media.enablement_pic1'),
    $r('app.media.enablement_pic2'),
    $r('app.media.enablement_pic3'),
    $r('app.media.enablement_pic4'),
    $r('app.media.enablement_pic5'),
    $r('app.media.enablement_pic6'),
    $r('app.media.enablement_pic7'),
    $r('app.media.enablement_pic8'),
]

build() {
    Column() {
      //创建Swiper组件,显示轮播图 Swiper容器的一多适配
      Swiper() {
      ForEach(this.list_swiper, (item: ResourceStr) => {
          Image(item)
            .width('100%')
            .height(120)
            .borderRadius(12)
      })
      }
      .itemSpace(10)
      .padding(10)
      .autoPlay(true)
      .loop(true)
      //根据当前断点设置显示的项目数量
      .displayCount(
      BreakpointState.of({
          sm: 1,
          md: 2,
          lg: 2
      }).update(this.currentBreakPoint)
      )
      //设置显示模式为拉伸********************?
      .displayMode(SwiperDisplayMode.AutoLinear)
      //显示下一张卡片的间距
      .nextMargin(
      BreakpointState.of({
          sm: 0,
          md: 12,
          lg: 266
      }).update(this.currentBreakPoint)
      )
      //显示导航索引
      .indicator(
      this.currentBreakPoint == BreakpointTypeEnum.SM ?
      Indicator.dot()
          .color('#3c3c3c') : false
      )


      //Grid容器的一多适配
      Column() {
      Row() {
          Text('赋能套件')
          Row() {
            Text('更多')
            Image($r('app.media.ic_arrow'))
            .width(15)
          }
          .width(40)
          .justifyContent(FlexAlign.SpaceBetween)
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)

      //创建Grid容器
      Grid() {
          ForEach(this.list_Grid, (item: Resource) => {
            GridItem() {
            Column() {
                //上图片
                Image(item)
                  .width('100%')
                  .height('50%')
                Column() {
                  Text('HarmonyOS 第一节课')
                  .maxLines(1)
                  .textOverflow({
                      overflow: TextOverflow.Ellipsis
                  })
                  Text('豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟')
                  .maxLines(2)
                  .textOverflow({
                      overflow: TextOverflow.Ellipsis
                  })
                  .fontSize(12)
                }
                .width('100%')
                .height('50%')
                .padding(5)
            }
            .width('100%')
            .aspectRatio(1)
            .borderRadius(16)
            .clip(true)
            .backgroundColor(Color.White)
            }
            //根据断点的不同,设置不同的GridItem宽度
            .width(
            BreakpointState.of({
                sm: 160,
                md: 164,
                lg: 180
            }).update(this.currentBreakPoint)
            )
          })
      }
      .width('100%')
      .height(240)
      .rowsTemplate('1fr')
      //根据不同的断点设置Grid的列间距
      .columnsGap(
          BreakpointState.of({
            sm: 8,
            md: 12,
            lg: 20
          }).update(this.currentBreakPoint)
      )
      // 行与行的间距
      .rowsGap(10)
      .scrollBar(BarState.Off)
      // 设置滚动的效果
      .edgeEffect(EdgeEffect.Spring)
      }

      //List容器的一多适配
      Column() {
      // 文本图片
      Row() {
          Text('入门教程')
          Row() {
            Text('更多')
            Image($r('app.media.ic_arrow'))
            .width(15)
          }
          .width(40)
          .justifyContent(FlexAlign.SpaceBetween)
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)

      //创建List组件,用于显示列表布局
      List({ space: 10 }) {
          ForEach(this.list_Grid, (item: Resource) => {
            ListItem() {
            Row() {
                Column() {
                  Text('Step1 鸿蒙世界快速入门介绍')
                  .fontSize(14)
                  .fontWeight(700)
                  Text('豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟')
                  .fontSize(12)
                  .maxLines(2)
                  .textOverflow({
                      overflow: TextOverflow.Ellipsis
                  })
                }
                .alignItems(HorizontalAlign.Start)
                .width('66%')

                Image(item)
                  .width('33%')
                  .borderRadius(12)
                  .height('70%')
            }
            .width('100%')
            .height(120)
            .backgroundColor(Color.White)
            .padding(10)
            .borderRadius(12)
            }
          })
      }
      //设置List列表的列数and列间距***************!
      .lanes(
          // 列的列数
          BreakpointState.of({
            sm: 1,
            md: 2,
            lg: 3
          }).update(this.currentBreakPoint),
          // 列间距
          BreakpointState.of({
            sm: 0,
            md: 12,
            lg: 16
          }).update(this.currentBreakPoint)
      )
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .padding(10)
    .backgroundColor('#f1f3f5')
}
}
Learning_map

import {
BreakpointSystem,
BreakpointState,
BreakpointType,
Breakpoint,
BreakpointTypeEnum
} from '../common/breakPointSystem'
import display from '@ohos.display';


@Component
export default struct Learning_map {
@State fold_state: string = ''
@StorageProp('foldStatusStr') @Watch('display_str') foldStatusStr: string = '-1'

display_str() {
    console.log(`<<<zz${this.foldStatusStr}`)
    if (this.foldStatusStr === '2') {
      this.pageInfo.clear()
    } else if (this.foldStatusStr === '1' || this.foldStatusStr === '3') {
      this.pageInfo.pushPath({
      name: 'OnePage'
      })
    }
}

@State compStr: BreakpointState<string> =
    BreakpointState.of({
      sm: 'sm',
      md: 'md',
      lg: 'lg'
    });
// 获取监听中屏幕的尺寸
@StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
@State list_: string[] = [
    '准备与学习',
    '构建应用',
    '应用测试',
    '上架',
    '运营增长',
    '商业变现'
]
@Consume pageInfo: NavPathStack

aboutToDisappear(): void {

    //console.log(`<<<<<<${this.foldStatusStr}`)
}

build() {
    Navigation(this.pageInfo) {

      Column() {
      Text('知识地图')
          .fontSize(30)
          .fontWeight(700)
      Image($r('app.media.knowledge_map_banner'))
          .width('100%')
          .borderRadius(16)
      Text('通过循序渐进的学习路径,无经验和有经验的开发者都可以轻松掌握ArkTS语言声明式开发范式,体验更简洁、更友好的HarmonyOS应用开旅程')
          .fontColor(Color.Gray)
          .width('100%')
          .fontSize(14)
          .margin({
            bottom: 20
          })
      List() {
          ForEach(this.list_, (item: string, index) => {
            ListItem() {
            Row() {
                Row({ space: 5 }) {
                  Text(`0${index + 1}`)
                  .fontWeight(700)
                  .fontSize(18)

                  Text(item)
                  .fontSize(18)
                }

                Image($r('app.media.ic_arrow'))
                  .width(20)
            }
            .padding({
                left: 10,
                right: 10
            })
            .height(50)
            .width('100%')
            .justifyContent(FlexAlign.SpaceBetween)
            .onClick(() => {
                this.pageInfo.pushPath({
                  name: 'OnePage'
                })
            })
            }
          })
      }
      .layoutWeight(1)
      }
      .width('100%')
      .height('100%')
      .alignItems(HorizontalAlign.Start)
      .padding(10)

    }
    .hideTitleBar(true)
    .hideToolBar(true)
    // !!!!!!!!!!!!!!!!!!
    /*.onNavigationModeChange((value) => {
      console.log(`Navigation页面当前折叠状态${JSON.stringify(value)}`)
      //0 为手机模式 NavigationMode.Stack
      //1 手机模式向平板模式展开中
      //手机模式
      if (value == NavigationMode.Stack) {
      this.pageInfo.clear()
      //如果是平板模式
      } else if (value == NavigationMode.Split) {
      this.pageInfo.pushPath({
          name: 'OnePage'
      })
      }
    })*/
    //
    .mode(NavigationMode.Auto)
    .width('100%')
}
}
breakPointSystem

// common/breakpointsystem.ets
import { mediaquery } from '@kit.ArkUI'

//断点类型
export type BreakpointType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'

//断点
export interface Breakpoint {
//类型
name: BreakpointType
//值
size: number
//媒体查询的句柄,并包含了申请句柄时的首次查询结果。媒体查询根据设置的条件语句,
// 比如'(width <= 600vp)',比较系统信息,若首次查询时相关信息未初始化,matches返回false。
// 定义MediaQuery监听器
mediaQueryListener?: mediaquery.MediaQueryListener
}

// 断点查询方法类
export class BreakpointSystem {

private static instance: BreakpointSystem
//断点值(设置为只读)
private readonly breakpoints: Breakpoint[] = [
    { name: 'xs', size: 0 },
    { name: 'sm', size: 320 },
    { name: 'md', size: 600 },
    { name: 'lg', size: 840 }
]
//是一系列无序,没有重复数值的数据集合。
private states: Set<BreakpointState<Object>>

private constructor() {
    this.states = new Set()
}
//获得实例
public static getInstance(): BreakpointSystem {
    if (!BreakpointSystem.instance) {
      BreakpointSystem.instance = new BreakpointSystem();
    }
    // BreakpointSystem的实例
    return BreakpointSystem.instance
}

//增加状态(给set集合中添加状态)
public attach(state: BreakpointState<Object>): void {
    this.states.add(state)
}

//删除状态(从set集合中删除状态)
public detach(state: BreakpointState<Object>): void {
    this.states.delete(state)
}

public start() {
    // 遍历循环设置的断点值
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      //条件设置
      let condition: string
      if (index === this.breakpoints.length - 1) {
      condition = `(${breakpoint.size}vp<=width)`
      } else {
      condition = `(${breakpoint.size}vp<=width<${this.breakpoints.size}vp)`
      }
      //设置媒体查询的查询条件,并返回对应的监听句柄。
      //mediaQueryListener 媒体查询的句柄,并包含了申请句柄时的首次查询结果。
      // 媒体查询根据设置的条件语句,比如'(width <= 600vp)',
      // 比较系统信息,若首次查询时相关信息未初始化,matches返回false。
      // matchMediaSync:设置媒体查询的操作,并返回相对应的监听句柄(breakpoint.mediaQueryListener)
      breakpoint.mediaQueryListener = mediaquery.matchMediaSync(condition)
      // 判断是否满足匹配的条件
      if (breakpoint.mediaQueryListener.matches) {
      //更新状态
      this.updateAllState(breakpoint.name)
      }
      // 监听状态
      breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
      if (mediaQueryResult.matches) {
          console.log(`当前屏幕状态态为:${breakpoint.name}`)
          console.log(`当前屏幕大小为:${breakpoint.size}`)
          // 将屏幕状态存入到appStorage中
          AppStorage.setOrCreate('currentBreakpoint',breakpoint.name)
          //监听并更新状态
          this.updateAllState(breakpoint.name)

      }
      })
    })
}

private updateAllState(type: BreakpointType): void {
    this.states.forEach((state): Object | undefined => state.update(type))
}

public stop() {
    //停止监听并清除状态
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      if (breakpoint.mediaQueryListener) {
      breakpoint.mediaQueryListener.off('change')
      }
    })
    this.states.clear()
}
}

// 可间断点可选项
export interface BreakpointOptions<T> {
xs?: T
sm?: T
md?: T
lg?: T
xl?: T
xxl?: T
}

export class BreakpointState<T extends Object> {
public value: T | undefined = undefined;
private options: BreakpointOptions<T>

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

// 开发者自定义对应断点的返回参数
static of<T extends Object>(options: BreakpointOptions<T>): BreakpointState<T> {
    return new BreakpointState(options)
}

// 更新and返回开发者需要的且设置的值
// breakpointType:断点的类型
public update(type: BreakpointType) {
    if (type === 'xs') {
      //this.options.xs 开发者给予的值
      this.value = this.options.xs
      return this.value
    } else if (type === 'sm') {
      this.value = this.options.sm
      return this.value
    } else if (type === 'md') {
      this.value = this.options.md
      return this.value
    } else if (type === 'lg') {
      this.value = this.options.lg
      return this.value
    } else if (type === 'xl') {
      this.value = this.options.xl
      return this.value
    } else if (type === 'xxl') {
      this.value = this.options.xxl
      return this.value
    } else {
      this.value = undefined
      return this.value
    }
}
}
// 创建断点枚举类,提供静态常量表示不同的断点
export class BreakpointTypeEnum {
static readonly SM: string = 'sm'; // 小屏幕断点
static readonly MD: string = 'md'; // 中等屏幕断点
static readonly LG: string = 'lg'; // 大屏幕断点
}

小结

TabPage
1:设置对应的状态变量,从AppStorage中获取断点,判断当前的屏幕大小。
       (1)@Provide pageInfo:NavPathStack = new NavPathStack()
2:在aboutToAppear
        (1)将断点值添加至断点状态
        (2)监听屏幕断点
        (3)监听可折叠设备的状态,并将其值存入到AppStorage中
3:在aboutToDisappear
        (1)删除断点状态
        (2)停止监听屏幕断点
4:使用@Buider自定义tabBar样式
5:在tabs的value中进行断点判定
        (1)(barPosition: this.currentBreakPoint== BreakpointTypeEnum.LG ? BarPosition.Start : BarPosition.End)
6:tabs属性操纵
        (1).onContentWillChange:页签的切换进行截取,判断是否是要跳转至对应的页面且屏幕大小为不为sm,true向路由栈存取对应路由
        (2)barWidth:页签的宽度(需要进行断点判断)
        (3)vertical:确定页签的方向(需要进行断点判断)
Home
1:设置对应的状态变量
2:主布局由Swiper,Grid,List容器进行布局
3:Swiper
        (1)displayCount:设置子组件滑动显示数量(需要进行断点判断)
        (2)indicator:导航索引显示
        (3)nextMargin:下一张轮播图的间距
4:Grid
        (1)根据断点的不同,需要设置不同的GridItem的宽度
        (2)columnsGap:根据断点的不同,设置Grid的列间距
5:List
        (1)lanes:设置List列表的列数and列间距
Learning_map
1:设置对应状态变量
        (1)@Consume pageInfo:NaPathStack
2:主布局由List来支撑
        (1)onNavigationModeChange:当导航模式变动时触发(折叠屏打开或者闭合会触发导航模式的变动)
3:可以通过display.on('foldStatusChange',callback)来监听折叠屏幕的状态(打开还是折叠)
        (1)在TabPage中进行监听,将结果存入到AppStorage中,在Learing_map进行@Watch监听调用
        (2)进行监听判断,对pageInfo路由栈进行对应的操作
样例图

https://i-blog.csdnimg.cn/direct/a528157bd1e8492eb0d80da331826298.png#pic_center
https://i-blog.csdnimg.cn/direct/20fcfbafa5c84ff7bf213233c0522953.png#pic_center
https://i-blog.csdnimg.cn/direct/5a6ff550ea074f978aded445eab26339.png#pic_center
栅格布局


[*]根据装备的水平宽度,将差异屏幕的尺寸分别为差异数目的栅格来实现屏幕的自顺应
[*]栅格多装备下通用辅助定位工具,通过将空间分割为有规律的栅格,显著降低适配差异屏幕尺寸的计划开辟及成本,是整体计划开辟流程更有秩序和节奏感
栅格容器的断点


[*] 提供了丰富的断点定制功能
[*] 开辟者可以修改断点取值范围,支持启用最多6个断点
[*] value:['100vp','200vp']
// 表示启动xs,sm,md三个断点
// 小于100vp的为xs,100-200vp为sm,200以上为md

value:['320vp','520vp','840vp','1080vp']
// 表示启动xs,sm,md,lg,sl五个断点

GridRow



[*]子组件只能是GridCol
参数

breakpoints
        value:自定义断点的范围
        reference:判断的目标        BreakpointsReference.WindowSize
                        WindowSize窗口大小,ComponentSize组件的大小
columns 规定忒定断点下将容器分割为多少个栅格
gutter 栅格与栅格之间的距离
子组件

span:占据多少栅格
offset:偏移多少栅格
属性

onBreakpointChange:当断点发生变化时触发回调,断点值可以是xs、sm、md、lg、xl、xxl
样例一

@Entry
@Component
struct GridRow_Col {
@State message: string = 'Hello World';
@State current:string = 'unKnown'
build() {
    Column(){
      GridRow({
      breakpoints:{
          //自定义断点范围,最多不超过5个
          value:['200vp','300vp','400vp','500vp','600vp'],
          //判断的目标 WindowSize窗口大小 ComponentSize组件大小
          reference:BreakpointsReference.WindowSize
      },
      //规定特定断点下将容器分割为多少个栅格
      columns:{
          xs:2,
          sm:4,
          md:8,
          lg:12,
          xl:16,
          xxl:20
      },
      //栅格与栅格之间的间距
      gutter:{
          x:'12vp'
      }
      }){
      GridCol({
          //占据多少栅格
          span:{
            xs:2,
            sm:4,
            md:1,
            lg:8,
            xl:12,
            xxl:12
          },
          //偏移多少栅格
          offset:{
            xs:0,
            sm:0,
            md:0,
            lg:2,
            xl:2,
            xxl:4
          }
      }){
          Column(){
            Text(this.current)
            .fontSize(30)
          }
          .border({
            width:1
          })

      }
      GridCol({
          //占据多少栅格
          span:{
            xs:2,
            sm:4,
            md:6,
            lg:8,
            xl:12,
            xxl:12
          },
          //偏移多少栅格
          offset:{
            xs:0,
            sm:0,
            md:0,
            lg:2,
            xl:2,
            xxl:4
          }
      }){
          Column(){
            Text(this.current)
            .fontSize(30)
          }
          .border({
            width:1
          })

      }
      GridCol({
          //占据多少栅格
          span:{
            xs:2,
            sm:4,
            md:1,
            lg:8,
            xl:12,
            xxl:12
          },
          //偏移多少栅格
          offset:{
            xs:0,
            sm:0,
            md:0,
            lg:2,
            xl:2,
            xxl:4
          }
      }){
          Column(){
            Text(this.current)
            .fontSize(30)
          }
          .border({
            width:1
          })

      }

      }
      .onBreakpointChange((currentBreakpoint:string) => {
      this.current = currentBreakpoint
      })
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
}
}
样例图

https://i-blog.csdnimg.cn/direct/150fb40209304de99176fa21f48071cf.jpeg#pic_center
https://i-blog.csdnimg.cn/direct/9168acd67e034cb0a4ec290c4915a35f.jpeg#pic_center
https://i-blog.csdnimg.cn/direct/cf4199ef5eba467db02e68cb9d3435f3.jpeg#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: HarmonyOS相应式布局