HarmonyOS相应式布局

打印 上一主题 下一主题

主题 815|帖子 815|积分 2445

布局

自顺应布局

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

断点


  • 以应用窗口为切入点,将应用窗口在宽维度上分成几个差异的区间即差异的断点,在差异的区间下,根据需求实现差异的页面布局效果
  • 即将断点将窗口分别为差异的范围,监听窗口的变化(需使用到BreakpointSystem类

  • 常见的监听断点变化的方法:

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

媒体查询


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

breakPointSystem.ets
  1. // common/breakpointsystem.ets
  2. import { mediaquery } from '@kit.ArkUI'
  3. //断点类型
  4. export type BreakpointType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
  5. //断点
  6. export interface Breakpoint {
  7.   //类型
  8.   name: BreakpointType
  9.   //值
  10.   size: number
  11.   //媒体查询的句柄,并包含了申请句柄时的首次查询结果。媒体查询根据设置的条件语句,
  12.   // 比如'(width <= 600vp)',比较系统信息,若首次查询时相关信息未初始化,matches返回false。
  13.   // 定义MediaQuery监听器
  14.   mediaQueryListener?: mediaquery.MediaQueryListener
  15. }
  16. // 断点查询方法类
  17. export class BreakpointSystem {
  18.   private static instance: BreakpointSystem
  19.   //断点值(设置为只读)
  20.   private readonly breakpoints: Breakpoint[] = [
  21.     { name: 'xs', size: 0 },
  22.     { name: 'sm', size: 320 },
  23.     { name: 'md', size: 600 },
  24.     { name: 'lg', size: 840 }
  25.   ]
  26.   //是一系列无序,没有重复数值的数据集合。
  27.   private states: Set<BreakpointState<Object>>
  28.   private constructor() {
  29.     this.states = new Set()
  30.   }
  31. //获得实例
  32.   public static getInstance(): BreakpointSystem {
  33.     if (!BreakpointSystem.instance) {
  34.       BreakpointSystem.instance = new BreakpointSystem();
  35.     }
  36.     return BreakpointSystem.instance
  37.   }
  38.   //增加状态(给set集合中添加状态)
  39.   public attach(state: BreakpointState<Object>): void {
  40.     this.states.add(state)
  41.   }
  42.   //删除状态(从set集合中删除状态)
  43.   public detach(state: BreakpointState<Object>): void {
  44.     this.states.delete(state)
  45.   }
  46.   public start() {
  47.     // 遍历循环设置的断点值
  48.     this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
  49.       //条件设置
  50.       let condition: string
  51.       if (index === this.breakpoints.length - 1) {
  52.         condition = `(${breakpoint.size}vp<=width)`
  53.       } else {
  54.         condition = `(${breakpoint.size}vp<=width<${this.breakpoints[index + 1].size}vp)`
  55.       }
  56.       //设置媒体查询的查询条件,并返回对应的监听句柄。
  57.       //mediaQueryListener 媒体查询的句柄,并包含了申请句柄时的首次查询结果。
  58.       // 媒体查询根据设置的条件语句,比如'(width <= 600vp)',
  59.       // 比较系统信息,若首次查询时相关信息未初始化,matches返回false。
  60.       // matchMediaSync:设置媒体查询的操作,并返回相对应的监听句柄(breakpoint.mediaQueryListener)
  61.       breakpoint.mediaQueryListener = mediaquery.matchMediaSync(condition)
  62.       // 判断是否满足匹配的条件
  63.       if (breakpoint.mediaQueryListener.matches) {
  64.         //更新状态
  65.         this.updateAllState(breakpoint.name)
  66.       }
  67.       // 监听状态
  68.       breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
  69.         if (mediaQueryResult.matches) {
  70.           console.log(`当前屏幕状态态为:${breakpoint.name}`)
  71.           console.log(`当前屏幕大小为:${breakpoint.size}`)
  72.           AppStorage.setOrCreate('currentBreakpoint',breakpoint.name)
  73.           //监听并更新状态
  74.           this.updateAllState(breakpoint.name)
  75.         }
  76.       })
  77.     })
  78.   }
  79.   private updateAllState(type: BreakpointType): void {
  80.     this.states.forEach((state): Object | undefined => state.update(type))
  81.   }
  82.   public stop() {
  83.     //停止监听并清除状态
  84.     this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
  85.       if (breakpoint.mediaQueryListener) {
  86.         breakpoint.mediaQueryListener.off('change')
  87.       }
  88.     })
  89.     this.states.clear()
  90.   }
  91. }
  92. // 可间断点可选项
  93. export interface BreakpointOptions<T> {
  94.   xs?: T
  95.   sm?: T
  96.   md?: T
  97.   lg?: T
  98.   xl?: T
  99.   xxl?: T
  100. }
  101. export class BreakpointState<T extends Object> {
  102.   public value: T | undefined = undefined;
  103.   private options: BreakpointOptions<T>
  104.   constructor(options: BreakpointOptions<T>) {
  105.     this.options = options
  106.   }
  107.   // 开发者自定义对应断点的返回参数
  108.   static of<T extends Object>(options: BreakpointOptions<T>): BreakpointState<T> {
  109.     return new BreakpointState(options)
  110.   }
  111.   // 更新and返回开发者需要的且设置的值
  112.   // breakpointType:断点的类型
  113.   public update(type: BreakpointType) {
  114.     if (type === 'xs') {
  115.       //this.options.xs 开发者给予的值
  116.       this.value = this.options.xs
  117.       return this.value
  118.     } else if (type === 'sm') {
  119.       this.value = this.options.sm
  120.       return this.value
  121.     } else if (type === 'md') {
  122.       this.value = this.options.md
  123.       return this.value
  124.     } else if (type === 'lg') {
  125.       this.value = this.options.lg
  126.       return this.value
  127.     } else if (type === 'xl') {
  128.       this.value = this.options.xl
  129.       return this.value
  130.     } else if (type === 'xxl') {
  131.       this.value = this.options.xxl
  132.       return this.value
  133.     } else {
  134.       this.value = undefined
  135.       return this.value
  136.     }
  137.   }
  138. }
  139. // 创建断点枚举类,提供静态常量表示不同的断点
  140. export class BreakpointTypeEnum {
  141.   static readonly SM: string = 'sm'; // 小屏幕断点
  142.   static readonly MD: string = 'md'; // 中等屏幕断点
  143.   static readonly LG: string = 'lg'; // 大屏幕断点
  144. }
复制代码
mediaquery.ets

  • 设置变量吸收状态值
  • 获取BreakpointSystem实例,并将状态值添加进去
  • 获取BreakpointSystem实例,屏幕进行监听
  • 将状态删除
  • 取消监听屏幕
  1. import { BreakpointSystem,BreakpointState } from '../common/breakPointSystem'
  2. @Entry
  3. @Component
  4. struct Mediaquery {
  5.   //设置状态值(是该状态返回显示的字符)
  6.   @State compStr:BreakpointState<string> = BreakpointState.of({
  7.     sm:"sm",
  8.     md:"md",
  9.     lg:"lg",
  10.   })
  11.   aboutToAppear(): void {
  12.     //将设置好的状态值添加
  13.     BreakpointSystem.getInstance().attach(this.compStr)
  14.     //监听屏幕状态
  15.     BreakpointSystem.getInstance().start()
  16.   }
  17.   aboutToDisappear(): void {
  18.     //将状态删除
  19.     BreakpointSystem.getInstance().detach(this.compStr)
  20.     //取消监听屏幕状态
  21.     BreakpointSystem.getInstance().stop()
  22.   }
  23.   build() {
  24.     Column(){
  25.       Text(this.compStr.value)
  26.         .fontSize(24)
  27.     }
  28.     .width('100%')
  29.     .height('100%')
  30.     .justifyContent(FlexAlign.Center)
  31.   }
  32. }
复制代码
案例二

TabPage

  1. import { DisplayUtil } from '@pura/harmony-utils'
  2. import {
  3.   BreakpointSystem,
  4.   BreakpointState,
  5.   BreakpointType,
  6.   Breakpoint,
  7.   BreakpointTypeEnum
  8. } from '../common/breakPointSystem'
  9. import Home from '../Component/Home'
  10. // 学习地图
  11. import Learning_map from '../Component/Learning_map'
  12. import display from '@ohos.display'
  13. class tabItem {
  14.   title: string = ''
  15.   tabIndex: number = 0
  16.   Icon: ResourceStr = ''
  17.   selectIcon: ResourceStr = ''
  18. }
  19. @Entry
  20. @Component
  21. struct TabPage {
  22.   @Provide pageInfo: NavPathStack = new NavPathStack()
  23.   @State foldStatusStr: string = ''
  24.   @State compStr: BreakpointState<string> =
  25.     BreakpointState.of({
  26.       sm: 'sm',
  27.       md: 'md',
  28.       lg: 'lg'
  29.     });
  30.   //定义一个断点的初始值
  31.   private BreakPointType_Lg: BreakpointType = 'lg';
  32.   aboutToAppear(): void {
  33.     //将定义的断点值添加至断点状态
  34.     BreakpointSystem.getInstance().attach(this.compStr)
  35.     //开始监听屏幕断点
  36.     BreakpointSystem.getInstance().start()
  37.     //监听可折叠设备的状态
  38.     display.on('foldStatusChange', (data: display.FoldStatus) => {
  39.       this.foldStatusStr = JSON.stringify(data)
  40.       console.info(`<<< `+JSON.stringify(data))
  41.       console.log(`<<<+++>>>${this.foldStatusStr}`)
  42.       AppStorage.setOrCreate('foldStatusStr', this.foldStatusStr)
  43.     })
  44.   }
  45.   aboutToDisappear(): void {
  46.     //删除断点状态
  47.     BreakpointSystem.getInstance().detach(this.compStr)
  48.     //停止监听屏幕断点
  49.     BreakpointSystem.getInstance().stop()
  50.   }
  51.   //使用@StorageProp 装饰器从存储中读取当前断点,默认值为中屏幕
  52.   @StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
  53.   //定义标签页的索引
  54.   @State currentIndex: number = 0
  55.   //创建Tabs控制器
  56.   private tabsController: TabsController = new TabsController()
  57.   //定义构建器方法,创建标签项
  58.   @Builder
  59.   tabBarItem(tabItem: tabItem) {
  60.     //创建垂直排列容器  间距为5
  61.     Column({ space: 5 }) {
  62.       //显示图片,根据是否选中采用不同的图片
  63.       Image(this.currentIndex === tabItem.tabIndex ? tabItem.selectIcon : tabItem.Icon)
  64.         .width(32)
  65.         .aspectRatio(1)
  66.         .objectFit(ImageFit.Contain)
  67.       //标签文字,根据是否选中采用不同的颜色
  68.       Text(tabItem.title)
  69.         .font({
  70.           size: 14,
  71.           weight: 600
  72.         })
  73.         .fontColor(
  74.           this.currentIndex === tabItem.tabIndex ?
  75.           $r('sys.color.ohos_id_color_focused_outline') : '#3c3c3c'
  76.         )
  77.     }
  78.     .width('100%')
  79.     .height('100%')
  80.     .justifyContent(FlexAlign.Center)
  81.   }
  82.   build() {
  83.     Tabs({
  84.       //Tab页签的一多适配
  85.       barPosition: this.currentBreakPoint
  86.         == BreakpointTypeEnum.LG ? BarPosition.Start : BarPosition.End
  87.     }) {
  88.       TabContent() {
  89.         Home()
  90.       }
  91.       .tabBar(this.tabBarItem({
  92.         title: '快速入门',
  93.         tabIndex: 0,
  94.         Icon: $r('app.media.ic_01_off'),
  95.         selectIcon: $r('app.media.ic_01_on'),
  96.       }))
  97.       TabContent()
  98.         .tabBar(this.tabBarItem({
  99.           title: '课程学习',
  100.           tabIndex: 1,
  101.           Icon: $r('app.media.ic_02_off'),
  102.           selectIcon: $r('app.media.ic_02_on'),
  103.         }))
  104.       TabContent() {
  105.         Learning_map()
  106.       }
  107.       .tabBar(this.tabBarItem({
  108.         title: '知识地图',
  109.         tabIndex: 2,
  110.         Icon: $r('app.media.ic_03_off'),
  111.         selectIcon: $r('app.media.ic_03_on'),
  112.       }))
  113.     }
  114.     // 页签切换进行截取
  115.     .onContentWillChange((currentIndex, comingIndex) => {
  116.       console.log(`当前的页签${currentIndex}`)
  117.       console.log(`将要显示的页签${comingIndex}`)
  118.       if (comingIndex === 2) {
  119.         if (this.currentBreakPoint != BreakpointTypeEnum.SM) {
  120.           this.pageInfo.pushPath({
  121.             name: 'OnePage'
  122.           })
  123.         } else {
  124.           this.pageInfo.clear()
  125.         }
  126.       }
  127.       return true
  128.     })
  129.     // ********************灵魂!!!!
  130.     // 用this.currentBreakPoint当前设备的值进行比对
  131.     .barWidth(
  132.       BreakpointState.of({
  133.         sm: '100%',
  134.         md: '100%',
  135.         lg: '80vp'
  136.       }).update(this.currentBreakPoint)
  137.     )
  138.     .onChange((index: number) => {
  139.       //将当前索引变为点击的目标索引
  140.       this.currentIndex = index
  141.     })
  142.     // 在确定制表符是否垂直时调用 默认false
  143.     .vertical(this.currentBreakPoint == BreakpointTypeEnum.LG ? true : false)
  144.   }
  145. }
复制代码
Home

  1. import {
  2.   BreakpointSystem,
  3.   BreakpointState,
  4.   BreakpointType,
  5.   Breakpoint,
  6.   BreakpointTypeEnum
  7. } from '../common/breakPointSystem'
  8. @Entry
  9. @Component
  10. export default struct Home {
  11.   @State compStr: BreakpointState<string> =
  12.     BreakpointState.of({
  13.       sm: 'sm',
  14.       md: 'md',
  15.       lg: 'lg'
  16.     });
  17.   //定义一个断点的初始值
  18.   private BreakPointType_Lg: BreakpointType = 'lg';
  19.   //使用@StorageProp 装饰器从存储中读取当前断点,默认值为中屏幕
  20.   @StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
  21.   @State list_swiper: ResourceStr[] = [
  22.     $r('app.media.banner_pic0'),
  23.     $r('app.media.banner_pic1'),
  24.     $r('app.media.banner_pic2'),
  25.     $r('app.media.banner_pic3'),
  26.     $r('app.media.banner_pic4'),
  27.     $r('app.media.banner_pic5')
  28.   ]
  29.   @State list_Grid: Resource[] = [
  30.     $r('app.media.enablement_pic1'),
  31.     $r('app.media.enablement_pic2'),
  32.     $r('app.media.enablement_pic3'),
  33.     $r('app.media.enablement_pic4'),
  34.     $r('app.media.enablement_pic5'),
  35.     $r('app.media.enablement_pic6'),
  36.     $r('app.media.enablement_pic7'),
  37.     $r('app.media.enablement_pic8'),
  38.   ]
  39.   build() {
  40.     Column() {
  41.       //创建Swiper组件,显示轮播图 Swiper容器的一多适配
  42.       Swiper() {
  43.         ForEach(this.list_swiper, (item: ResourceStr) => {
  44.           Image(item)
  45.             .width('100%')
  46.             .height(120)
  47.             .borderRadius(12)
  48.         })
  49.       }
  50.       .itemSpace(10)
  51.       .padding(10)
  52.       .autoPlay(true)
  53.       .loop(true)
  54.       //根据当前断点设置显示的项目数量
  55.       .displayCount(
  56.         BreakpointState.of({
  57.           sm: 1,
  58.           md: 2,
  59.           lg: 2
  60.         }).update(this.currentBreakPoint)
  61.       )
  62.       //设置显示模式为拉伸********************?
  63.       .displayMode(SwiperDisplayMode.AutoLinear)
  64.       //显示下一张卡片的间距
  65.       .nextMargin(
  66.         BreakpointState.of({
  67.           sm: 0,
  68.           md: 12,
  69.           lg: 266
  70.         }).update(this.currentBreakPoint)
  71.       )
  72.       //显示导航索引
  73.       .indicator(
  74.         this.currentBreakPoint == BreakpointTypeEnum.SM ?
  75.         Indicator.dot()
  76.           .color('#3c3c3c') : false
  77.       )
  78.       //Grid容器的一多适配
  79.       Column() {
  80.         Row() {
  81.           Text('赋能套件')
  82.           Row() {
  83.             Text('更多')
  84.             Image($r('app.media.ic_arrow'))
  85.               .width(15)
  86.           }
  87.           .width(40)
  88.           .justifyContent(FlexAlign.SpaceBetween)
  89.         }
  90.         .width('100%')
  91.         .justifyContent(FlexAlign.SpaceBetween)
  92.         //创建Grid容器
  93.         Grid() {
  94.           ForEach(this.list_Grid, (item: Resource) => {
  95.             GridItem() {
  96.               Column() {
  97.                 //上图片
  98.                 Image(item)
  99.                   .width('100%')
  100.                   .height('50%')
  101.                 Column() {
  102.                   Text('HarmonyOS 第一节课')
  103.                     .maxLines(1)
  104.                     .textOverflow({
  105.                       overflow: TextOverflow.Ellipsis
  106.                     })
  107.                   Text('豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟')
  108.                     .maxLines(2)
  109.                     .textOverflow({
  110.                       overflow: TextOverflow.Ellipsis
  111.                     })
  112.                     .fontSize(12)
  113.                 }
  114.                 .width('100%')
  115.                 .height('50%')
  116.                 .padding(5)
  117.               }
  118.               .width('100%')
  119.               .aspectRatio(1)
  120.               .borderRadius(16)
  121.               .clip(true)
  122.               .backgroundColor(Color.White)
  123.             }
  124.             //根据断点的不同,设置不同的GridItem宽度
  125.             .width(
  126.               BreakpointState.of({
  127.                 sm: 160,
  128.                 md: 164,
  129.                 lg: 180
  130.               }).update(this.currentBreakPoint)
  131.             )
  132.           })
  133.         }
  134.         .width('100%')
  135.         .height(240)
  136.         .rowsTemplate('1fr')
  137.         //根据不同的断点设置Grid的列间距
  138.         .columnsGap(
  139.           BreakpointState.of({
  140.             sm: 8,
  141.             md: 12,
  142.             lg: 20
  143.           }).update(this.currentBreakPoint)
  144.         )
  145.         // 行与行的间距
  146.         .rowsGap(10)
  147.         .scrollBar(BarState.Off)
  148.         // 设置滚动的效果
  149.         .edgeEffect(EdgeEffect.Spring)
  150.       }
  151.       //List容器的一多适配
  152.       Column() {
  153.         // 文本图片
  154.         Row() {
  155.           Text('入门教程')
  156.           Row() {
  157.             Text('更多')
  158.             Image($r('app.media.ic_arrow'))
  159.               .width(15)
  160.           }
  161.           .width(40)
  162.           .justifyContent(FlexAlign.SpaceBetween)
  163.         }
  164.         .width('100%')
  165.         .justifyContent(FlexAlign.SpaceBetween)
  166.         //创建List组件,用于显示列表布局
  167.         List({ space: 10 }) {
  168.           ForEach(this.list_Grid, (item: Resource) => {
  169.             ListItem() {
  170.               Row() {
  171.                 Column() {
  172.                   Text('Step1 鸿蒙世界快速入门介绍')
  173.                     .fontSize(14)
  174.                     .fontWeight(700)
  175.                   Text('豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟')
  176.                     .fontSize(12)
  177.                     .maxLines(2)
  178.                     .textOverflow({
  179.                       overflow: TextOverflow.Ellipsis
  180.                     })
  181.                 }
  182.                 .alignItems(HorizontalAlign.Start)
  183.                 .width('66%')
  184.                 Image(item)
  185.                   .width('33%')
  186.                   .borderRadius(12)
  187.                   .height('70%')
  188.               }
  189.               .width('100%')
  190.               .height(120)
  191.               .backgroundColor(Color.White)
  192.               .padding(10)
  193.               .borderRadius(12)
  194.             }
  195.           })
  196.         }
  197.         //设置List列表的列数and列间距***************!
  198.         .lanes(
  199.           // 列的列数
  200.           BreakpointState.of({
  201.             sm: 1,
  202.             md: 2,
  203.             lg: 3
  204.           }).update(this.currentBreakPoint),
  205.           // 列间距
  206.           BreakpointState.of({
  207.             sm: 0,
  208.             md: 12,
  209.             lg: 16
  210.           }).update(this.currentBreakPoint)
  211.         )
  212.       }
  213.       .layoutWeight(1)
  214.     }
  215.     .width('100%')
  216.     .height('100%')
  217.     .padding(10)
  218.     .backgroundColor('#f1f3f5')
  219.   }
  220. }
复制代码
Learning_map

  1. import {
  2.   BreakpointSystem,
  3.   BreakpointState,
  4.   BreakpointType,
  5.   Breakpoint,
  6.   BreakpointTypeEnum
  7. } from '../common/breakPointSystem'
  8. import display from '@ohos.display';
  9. @Component
  10. export default struct Learning_map {
  11.   @State fold_state: string = ''
  12.   @StorageProp('foldStatusStr') @Watch('display_str') foldStatusStr: string = '-1'
  13.   display_str() {
  14.     console.log(`<<<zz${this.foldStatusStr}`)
  15.     if (this.foldStatusStr === '2') {
  16.       this.pageInfo.clear()
  17.     } else if (this.foldStatusStr === '1' || this.foldStatusStr === '3') {
  18.       this.pageInfo.pushPath({
  19.         name: 'OnePage'
  20.       })
  21.     }
  22.   }
  23.   @State compStr: BreakpointState<string> =
  24.     BreakpointState.of({
  25.       sm: 'sm',
  26.       md: 'md',
  27.       lg: 'lg'
  28.     });
  29.   // 获取监听中屏幕的尺寸
  30.   @StorageProp('currentBreakpoint') currentBreakPoint: BreakpointType = 'md'
  31.   @State list_: string[] = [
  32.     '准备与学习',
  33.     '构建应用',
  34.     '应用测试',
  35.     '上架',
  36.     '运营增长',
  37.     '商业变现'
  38.   ]
  39.   @Consume pageInfo: NavPathStack
  40.   aboutToDisappear(): void {
  41.     //console.log(`<<<<<<${this.foldStatusStr}`)
  42.   }
  43.   build() {
  44.     Navigation(this.pageInfo) {
  45.       Column() {
  46.         Text('知识地图')
  47.           .fontSize(30)
  48.           .fontWeight(700)
  49.         Image($r('app.media.knowledge_map_banner'))
  50.           .width('100%')
  51.           .borderRadius(16)
  52.         Text('通过循序渐进的学习路径,无经验和有经验的开发者都可以轻松掌握ArkTS语言声明式开发范式,体验更简洁、更友好的HarmonyOS应用开旅程')
  53.           .fontColor(Color.Gray)
  54.           .width('100%')
  55.           .fontSize(14)
  56.           .margin({
  57.             bottom: 20
  58.           })
  59.         List() {
  60.           ForEach(this.list_, (item: string, index) => {
  61.             ListItem() {
  62.               Row() {
  63.                 Row({ space: 5 }) {
  64.                   Text(`0${index + 1}`)
  65.                     .fontWeight(700)
  66.                     .fontSize(18)
  67.                   Text(item)
  68.                     .fontSize(18)
  69.                 }
  70.                 Image($r('app.media.ic_arrow'))
  71.                   .width(20)
  72.               }
  73.               .padding({
  74.                 left: 10,
  75.                 right: 10
  76.               })
  77.               .height(50)
  78.               .width('100%')
  79.               .justifyContent(FlexAlign.SpaceBetween)
  80.               .onClick(() => {
  81.                 this.pageInfo.pushPath({
  82.                   name: 'OnePage'
  83.                 })
  84.               })
  85.             }
  86.           })
  87.         }
  88.         .layoutWeight(1)
  89.       }
  90.       .width('100%')
  91.       .height('100%')
  92.       .alignItems(HorizontalAlign.Start)
  93.       .padding(10)
  94.     }
  95.     .hideTitleBar(true)
  96.     .hideToolBar(true)
  97.     // !!!!!!!!!!!!!!!!!!
  98.     /*.onNavigationModeChange((value) => {
  99.       console.log(`Navigation页面当前折叠状态${JSON.stringify(value)}`)
  100.       //0 为手机模式 NavigationMode.Stack
  101.       //1 手机模式向平板模式展开中
  102.       //手机模式
  103.       if (value == NavigationMode.Stack) {
  104.         this.pageInfo.clear()
  105.         //如果是平板模式
  106.       } else if (value == NavigationMode.Split) {
  107.         this.pageInfo.pushPath({
  108.           name: 'OnePage'
  109.         })
  110.       }
  111.     })*/
  112.     //
  113.     .mode(NavigationMode.Auto)
  114.     .width('100%')
  115.   }
  116. }
复制代码
breakPointSystem

  1. // common/breakpointsystem.ets
  2. import { mediaquery } from '@kit.ArkUI'
  3. //断点类型
  4. export type BreakpointType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
  5. //断点
  6. export interface Breakpoint {
  7.   //类型
  8.   name: BreakpointType
  9.   //值
  10.   size: number
  11.   //媒体查询的句柄,并包含了申请句柄时的首次查询结果。媒体查询根据设置的条件语句,
  12.   // 比如'(width <= 600vp)',比较系统信息,若首次查询时相关信息未初始化,matches返回false。
  13.   // 定义MediaQuery监听器
  14.   mediaQueryListener?: mediaquery.MediaQueryListener
  15. }
  16. // 断点查询方法类
  17. export class BreakpointSystem {
  18.   private static instance: BreakpointSystem
  19.   //断点值(设置为只读)
  20.   private readonly breakpoints: Breakpoint[] = [
  21.     { name: 'xs', size: 0 },
  22.     { name: 'sm', size: 320 },
  23.     { name: 'md', size: 600 },
  24.     { name: 'lg', size: 840 }
  25.   ]
  26.   //是一系列无序,没有重复数值的数据集合。
  27.   private states: Set<BreakpointState<Object>>
  28.   private constructor() {
  29.     this.states = new Set()
  30.   }
  31. //获得实例
  32.   public static getInstance(): BreakpointSystem {
  33.     if (!BreakpointSystem.instance) {
  34.       BreakpointSystem.instance = new BreakpointSystem();
  35.     }
  36.     // BreakpointSystem的实例
  37.     return BreakpointSystem.instance
  38.   }
  39.   //增加状态(给set集合中添加状态)
  40.   public attach(state: BreakpointState<Object>): void {
  41.     this.states.add(state)
  42.   }
  43.   //删除状态(从set集合中删除状态)
  44.   public detach(state: BreakpointState<Object>): void {
  45.     this.states.delete(state)
  46.   }
  47.   public start() {
  48.     // 遍历循环设置的断点值
  49.     this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
  50.       //条件设置
  51.       let condition: string
  52.       if (index === this.breakpoints.length - 1) {
  53.         condition = `(${breakpoint.size}vp<=width)`
  54.       } else {
  55.         condition = `(${breakpoint.size}vp<=width<${this.breakpoints[index + 1].size}vp)`
  56.       }
  57.       //设置媒体查询的查询条件,并返回对应的监听句柄。
  58.       //mediaQueryListener 媒体查询的句柄,并包含了申请句柄时的首次查询结果。
  59.       // 媒体查询根据设置的条件语句,比如'(width <= 600vp)',
  60.       // 比较系统信息,若首次查询时相关信息未初始化,matches返回false。
  61.       // matchMediaSync:设置媒体查询的操作,并返回相对应的监听句柄(breakpoint.mediaQueryListener)
  62.       breakpoint.mediaQueryListener = mediaquery.matchMediaSync(condition)
  63.       // 判断是否满足匹配的条件
  64.       if (breakpoint.mediaQueryListener.matches) {
  65.         //更新状态
  66.         this.updateAllState(breakpoint.name)
  67.       }
  68.       // 监听状态
  69.       breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
  70.         if (mediaQueryResult.matches) {
  71.           console.log(`当前屏幕状态态为:${breakpoint.name}`)
  72.           console.log(`当前屏幕大小为:${breakpoint.size}`)
  73.           // 将屏幕状态存入到appStorage中
  74.           AppStorage.setOrCreate('currentBreakpoint',breakpoint.name)
  75.           //监听并更新状态
  76.           this.updateAllState(breakpoint.name)
  77.         }
  78.       })
  79.     })
  80.   }
  81.   private updateAllState(type: BreakpointType): void {
  82.     this.states.forEach((state): Object | undefined => state.update(type))
  83.   }
  84.   public stop() {
  85.     //停止监听并清除状态
  86.     this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
  87.       if (breakpoint.mediaQueryListener) {
  88.         breakpoint.mediaQueryListener.off('change')
  89.       }
  90.     })
  91.     this.states.clear()
  92.   }
  93. }
  94. // 可间断点可选项
  95. export interface BreakpointOptions<T> {
  96.   xs?: T
  97.   sm?: T
  98.   md?: T
  99.   lg?: T
  100.   xl?: T
  101.   xxl?: T
  102. }
  103. export class BreakpointState<T extends Object> {
  104.   public value: T | undefined = undefined;
  105.   private options: BreakpointOptions<T>
  106.   constructor(options: BreakpointOptions<T>) {
  107.     this.options = options
  108.   }
  109.   // 开发者自定义对应断点的返回参数
  110.   static of<T extends Object>(options: BreakpointOptions<T>): BreakpointState<T> {
  111.     return new BreakpointState(options)
  112.   }
  113.   // 更新and返回开发者需要的且设置的值
  114.   // breakpointType:断点的类型
  115.   public update(type: BreakpointType) {
  116.     if (type === 'xs') {
  117.       //this.options.xs 开发者给予的值
  118.       this.value = this.options.xs
  119.       return this.value
  120.     } else if (type === 'sm') {
  121.       this.value = this.options.sm
  122.       return this.value
  123.     } else if (type === 'md') {
  124.       this.value = this.options.md
  125.       return this.value
  126.     } else if (type === 'lg') {
  127.       this.value = this.options.lg
  128.       return this.value
  129.     } else if (type === 'xl') {
  130.       this.value = this.options.xl
  131.       return this.value
  132.     } else if (type === 'xxl') {
  133.       this.value = this.options.xxl
  134.       return this.value
  135.     } else {
  136.       this.value = undefined
  137.       return this.value
  138.     }
  139.   }
  140. }
  141. // 创建断点枚举类,提供静态常量表示不同的断点
  142. export class BreakpointTypeEnum {
  143.   static readonly SM: string = 'sm'; // 小屏幕断点
  144.   static readonly MD: string = 'md'; // 中等屏幕断点
  145.   static readonly LG: string = 'lg'; // 大屏幕断点
  146. }
复制代码
小结

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




栅格布局


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


  • 提供了丰富的断点定制功能
  • 开辟者可以修改断点取值范围,支持启用最多6个断点
    1. value:['100vp','200vp']
    2. // 表示启动xs,sm,md三个断点
    3. // 小于100vp的为xs,100-200vp为sm,200以上为md
    4. value:['320vp','520vp','840vp','1080vp']
    5. // 表示启动xs,sm,md,lg,sl五个断点
    复制代码
GridRow



  • 子组件只能是GridCol
参数

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

  1. span:占据多少栅格
  2. offset:偏移多少栅格
复制代码
属性

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

  1. @Entry
  2. @Component
  3. struct GridRow_Col {
  4.   @State message: string = 'Hello World';
  5.   @State current:string = 'unKnown'
  6.   build() {
  7.     Column(){
  8.       GridRow({
  9.         breakpoints:{
  10.           //自定义断点范围,最多不超过5个
  11.           value:['200vp','300vp','400vp','500vp','600vp'],
  12.           //判断的目标 WindowSize窗口大小 ComponentSize组件大小
  13.           reference:BreakpointsReference.WindowSize
  14.         },
  15.         //规定特定断点下将容器分割为多少个栅格
  16.         columns:{
  17.           xs:2,
  18.           sm:4,
  19.           md:8,
  20.           lg:12,
  21.           xl:16,
  22.           xxl:20
  23.         },
  24.         //栅格与栅格之间的间距
  25.         gutter:{
  26.           x:'12vp'
  27.         }
  28.       }){
  29.         GridCol({
  30.           //占据多少栅格
  31.           span:{
  32.             xs:2,
  33.             sm:4,
  34.             md:1,
  35.             lg:8,
  36.             xl:12,
  37.             xxl:12
  38.           },
  39.           //偏移多少栅格
  40.           offset:{
  41.             xs:0,
  42.             sm:0,
  43.             md:0,
  44.             lg:2,
  45.             xl:2,
  46.             xxl:4
  47.           }
  48.         }){
  49.           Column(){
  50.             Text(this.current)
  51.               .fontSize(30)
  52.           }
  53.           .border({
  54.             width:1
  55.           })
  56.         }
  57.         GridCol({
  58.           //占据多少栅格
  59.           span:{
  60.             xs:2,
  61.             sm:4,
  62.             md:6,
  63.             lg:8,
  64.             xl:12,
  65.             xxl:12
  66.           },
  67.           //偏移多少栅格
  68.           offset:{
  69.             xs:0,
  70.             sm:0,
  71.             md:0,
  72.             lg:2,
  73.             xl:2,
  74.             xxl:4
  75.           }
  76.         }){
  77.           Column(){
  78.             Text(this.current)
  79.               .fontSize(30)
  80.           }
  81.           .border({
  82.             width:1
  83.           })
  84.         }
  85.         GridCol({
  86.           //占据多少栅格
  87.           span:{
  88.             xs:2,
  89.             sm:4,
  90.             md:1,
  91.             lg:8,
  92.             xl:12,
  93.             xxl:12
  94.           },
  95.           //偏移多少栅格
  96.           offset:{
  97.             xs:0,
  98.             sm:0,
  99.             md:0,
  100.             lg:2,
  101.             xl:2,
  102.             xxl:4
  103.           }
  104.         }){
  105.           Column(){
  106.             Text(this.current)
  107.               .fontSize(30)
  108.           }
  109.           .border({
  110.             width:1
  111.           })
  112.         }
  113.       }
  114.       .onBreakpointChange((currentBreakpoint:string) => {
  115.         this.current = currentBreakpoint
  116.       })
  117.       .width('100%')
  118.       .height('100%')
  119.     }
  120.     .width('100%')
  121.     .height('100%')
  122.   }
  123. }
复制代码
样例图





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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

不到断气不罢休

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表