HarmonyOS开发之GridRow&GridCol

GridRow/GridCol(栅格布局)

GridRow/GridCol(栅格布局)是响应式布局的一种,响应式布局可以实现界面随外部容器尺寸分级不连续变化而变化。

所以GridRow/GridCol(栅格布局)的适用场景:随尺寸变化组件结构不同的场景,比如:外部容器大小发生变化时,组件元素可以根据断点、栅格或特定的特征(如横竖屏方向切换、窗口宽高变化,不同设备的尺寸等)自动变化以适应外部容器变化的布局能力

GridRow:栅格容器组件,需与结合其子组件GridCol开发,可以适配不同尺寸的设备,让各个设备可以合理的显示,以此亦完成不同屏幕尺寸的UI适配。

一、GridRow参数:breakpoints、columns和gutter(文章里会详细说明)

断点:breakpoint

官方:栅格系统以设备的水平宽度(屏幕密度像素值,单位vp)作为断点依据,定义设备的宽度类型,形成了一套断点规则。开发者可根据需求在不同的断点区间实现不同的页面布局效果。

为了便于理解,通过下面的示例代码进行说明。阅览示例代码可知,brerakpoints是GridRow的参数。value(数组)和reference(枚举值)是breakpoints的两个成员变量。

示例代码:breakpoints: { 

value: ['300vp','600vp','800vp','1000vp','1200vp'],

 reference:BreakpointsReference.WindowSize

 }

1、WindowSize:reference的默认值为BreakpointsReference.WindowSize,此值表示是以设备的宽度作为参照,通过屏宽与value内的每个元素进行比较。跟设备有关,因为不同设备,屏宽可能不同。

屏宽属于[0, 300vp)就是xs,表示最小宽度类型设备。(屏宽 < 300)

屏宽属于[300, 600vp)就是sm,表示小宽度类型设备。(屏宽 >= 300 && 屏宽 < 600)

屏宽属于[600, 800vp)就是md,表示中等宽度类型设备。

屏宽属于[800, 1000vp)就lg,表示大宽度类型设备。

屏宽属于[1000, 1200vp)就是xl,表示特大宽度类型设备。

屏宽属于[1200, +∞)就是xxl,表示超大宽度类型设备。

2、ComponentSize:若reference的值为BreakpointsReference.ComponentSize,表示是以容器(GridRow)的尺寸作为参照,通过容器的width与value内的每个元素进行比较,比较原理与屏宽一致。

需要注意:因为此时是用容器的尺寸的进行比较,所以与当前的设备就无关了(若按设备百分比设置宽度,那跟屏宽还是有关系的)。

重点说明:在示例代码中,values =  ['300vp', '600vp', '800vp', '1000vp', '1200vp'],但values中元素的值是不固定的,理论上只要从小到大排列即可,但这需要跟当前的需求做出相应的调整,因为官方要求最多只能有xs、sm、md、lg、xl、xxl六个断点,所以value中最多只能有五个元素,若只有四个元素,则xxl自动失效,可省去,以此类推,若里面只有一个元素,那就意味着所有情况都只有xs[0, '300vp')和sm['300vp', +∞)两个断点。

span中的xs等断点所传入的值是所占列数,不理解可以暂时先跳过,下面会详细讲解

@Entry

@Component

struct Index {

  @State gridRowWidth: number = 200;

  colors: Color[] = [Color.Red, Color.Yellow, Color.Pink, Color.Orange, Color.Brown, Color.Blue, Color.Orange, Color.Gray]

  build() {

    Column() {

      GridRow({

        breakpoints: {

          value: ['300vp', '600vp', '800vp', '1000vp', '1200vp'],

          // reference: BreakpointsReference.WindowSize, // 以设备尺寸作为参照,跟设备有关

          reference: BreakpointsReference.ComponentSize // 以容器组件尺寸作为参照,绝对尺寸,此处与设备无关

        },

        direction: GridRowDirection.Row // 排列方式:从左至右

      }) {

        ForEach(this.colors, (item: Color, index: Number) => {

          GridCol({

            span: {

              xs: 12, //设备/容器组件宽度在【0, 300) 之间,即为xs。 在最小宽度类型设备上,GridCol占据的GridRow中的12列。

              sm: 6, // 设备/容器组件宽度在【300, 600) 之间,即为sm。在小宽度类型设备上,GridCol占据的GridRow中的6列。

              md: 4, // 设备/容器组件宽度在【600, 800) 之间,即为md。在中等宽度类型设备上,GridCol占据的GridRow中的4列。

              lg: 3, // 设备/容器组件宽度在【800, 1000) 之间,即为lg。在大宽度类型设备上,GridCol占据的GridRow中的3列。

              xl: 2, // 设备/容器组件宽度在【1000, 1300) 之间,即为xl。在特大宽度类型设备上,GridCol占据的GridRow中的2列。

              xxl: 1 // 设备/容器组件宽度在【1200, +∞)之间,即为xxl。在超大宽度类型设备上,GridCol占据的GridRow中的1列。

            }

          }) {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

                .onClick(() => {

                  this.gridRowWidth += 50; //修改容器组件GridRow的宽度,用于测试,前提:以容器组件为参照

                })

            }.width('100%').height(50)

          }

          .backgroundColor(item)

        }, (item: Color) => item.toString())

      }

      .width(`${this.gridRowWidth}vp`)

      .height(500)

      .backgroundColor('#f5f5f5')

    }

    .width('100%')

  }

}


columns

columns默认值是12,即在不设此参数时,默认12列,也可以自定义

同样通过下面示例代码进行说明:

1、columns是一个复合值类型(number | GridRowColumnOption)。

当columns为number类型时,比如columns: 10,在任何情况下GridRow都被分为10列。下面分别设置GridRow列数为6和10,子元素分别占2列和5列,下面代码就是columns为number类型的示例代码。

当columns类型为GridRowColumnOption时,比如columns: { sm: 4, md: 8 },表示在断点为sm时,GridRow被分为4列;点断为md时,GridRow被分为8列,其他情况默认还是12列。GridRowColumnOption的代码就不做演示了,原理大同小异。

gutter

gutter也是一个复合值类型(Length | GutterOption)。

当gutter为Length类型时,例如:gutter: 20,表示GridCol之间的距离上下左右的距离均为20。

也可以为GutterOption类型,例如:gutter: {x:20, y: 10},表示水平方向间距20,垂直方向间距10。

备注:当一行展示不下时,自动折行。

代码与效果图如下:

@Entry

@Component

struct Index {

  colors: Color[] = [

    Color.Red, Color.Yellow, Color.Pink, Color.Orange,

    Color.Brown, Color.Blue, Color.Yellow, Color.Orange,

    Color.Gray, Color.Pink, Color.Orange, Color.Brown];

  build() {

    Column({space: 30}) {

      GridRow({

        gutter: 20, // GridCol之间的间距为20,也可以设置为{x:20, y: 10},表示水平方向间距20,垂直方向间距10

        columns: 6 // 表示一共把GridRow的宽度分为6列(为了更好理解,可以理解成分为了6份)

      }) {

        ForEach(this.colors, (item: Color, index: Number) => {

          GridCol({

            span: 2 // 共6份,此设置表示占2份的宽度, 所以会展示3列

          }) {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }.width('100%').height(50)

          }

          .backgroundColor(item)

        }, (item: Color) => item.toString())

      }

      .width('100%')

      .height(500)

      .backgroundColor('#f5f5f5')

      GridRow({

        gutter: {x: 20, y: 10}, // 表示为{x:20, y: 10},表示水平方向间距20,垂直方向间距10

        columns: 10 // 10列

      }){

        ForEach(this.colors, (item: Color, index: number) => {

          GridCol({

            span: 5 // 共10份,此设置表示占5份的宽度, 所以会展示2列

          }) {

            Row(){

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }

            .backgroundColor(item)

            .width('100%')

            .height(50)

          }

        }, (item: Color) => item.toString())

      }

      .width('100%')

      .height(500)

      .backgroundColor('#f5f5f5')

    }

    .width('100%')

  }

}


3、columns默认值为12,没传入columns时,栅格布局被分成12列,与断点无关了,如下代码与效果图如下:

@Entry

@Component

struct Index {

  colors: Color[] = [

    Color.Red, Color.Yellow, Color.Pink, Color.Orange,

    Color.Brown, Color.Blue, Color.Yellow, Color.Orange,

    Color.Gray, Color.Pink, Color.Orange, Color.Brown];

  build() {

    Column() {

      GridRow() {

        ForEach(this.colors, (item: Color, index: Number) => {

          GridCol() {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }.width('100%').height(50)

          }

          .backgroundColor(item)

        }, (item: Color) => item.toString())

      }

      .width('100%')

      .height(500)

      .backgroundColor('#f5f5f5')

    }

    .width('100%')

  }

}

三、子组件GridCol的参数:span、offset、order

1、span

也是一个复合值类型 (number | GridColColumnOption)。

当span为number类型时,比如span: 4,表示所有情况GridCol都占4列。

当span为GridColColumnOption类型时,如第一份代码中,span{xs: 12}, 表示在对应为xs断点时,当前的GridCol占12列。

2、offset

也是一个复合值类型 (number | GridColColumnOption),表示GridCol相对于前一个GridCol的偏移列数,默认为0。

当类型为number时,GridCol偏移相同列数。例如:offset: 2,偏移量为2列

当类型为GridColColumnOption时,例如:offset: { xs: 1, sm: 2, md: 3, lg: 4 },逻辑与span类型,分断点情况设置的偏移量

当一行的最后偏移量不够时,需要换行继续偏移

3、order

也是一个复合值类型 (number | GridColColumnOption),表示GridCol当前的排序编号,定GridCol排列次序。当GridCol不设置order或者设置相同的order, GridCol按照代码顺序展示。GridCol排序是按order从小到大的排列。未设置order的GridCol依次排序靠前,设置了order的GridCol按照数值从小到大排列。

当类型为number时。例如:order: 2,表示序号为2

当类型为GridColColumnOption时,例如:offset: { xs: 1, sm: 2, md: 3, lg: 4 },逻辑与span类型,分断点情况设置的序号

示例代码和效果图如下:

@Entry

@Component

struct Index {

  colors: Color[] = [

    Color.Red, Color.Yellow, Color.Pink, Color.Orange,

    Color.Brown, Color.Blue, Color.Yellow, Color.Orange,

    Color.Gray, Color.Pink, Color.Orange, Color.Brown];

  build() {

    Column({ space: 30 }) {

      GridRow({

        columns: 10 // 表示一共把GridRow的宽度分为10列

      }) {

        ForEach(this.colors, (item: Color, index: Number) => {

          GridCol({

            span: 2 // 共10份,此设置表示占2份的宽度, 所以会展示5列

          }) {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }.width('100%').height(50)

          }

          .backgroundColor(item)

        }, (item: Color) => item.toString())

      }

      .width('100%')

      .height(500)

      .backgroundColor('#f5f5f5')

      GridRow({

        columns: 10 // 10列

      }) {

        ForEach(this.colors, (item: Color, index: number) => {

          GridCol({

            span: 2,

            offset: 2 // 子组件偏移相同列数2,当一行的最后偏移量不够时,需要换行继续偏移。注意:此处偏移不是指行首子组件偏移,而是所有子组件都会偏移

            // offset: {xs: 2, sm: 3} // 与span属性类似,也支持分断点传值

          }) {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }

            .backgroundColor(item)

            .width('100%')

            .height(50)

          }

        }, (item: Color) => item.toString())

      }

      .width('100%')

      .height(500)

      .backgroundColor('#f5f5f5')

      GridRow({ columns: 12 }) {

        ForEach(this.colors, (item: Color, index: number) => {

          GridCol({

            span: 2,

            order: 12 - index // 与文案相反排列

            // order: { xs: 1, sm: 2, md: 3, lg: 4 } //与span属性类似,也支持分断点传值

          }) {

            Row() {

              Text(index.toString())

                .fontSize(20)

                .fontWeight(FontWeight.Bold)

                .width('100%')

                .textAlign(TextAlign.Center)

            }

            .backgroundColor(item)

            .width('100%')

            .height(50)

          }

        }, (item: Color) => item.toString())

      }

}

    .width('100%')

  }

}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容