HarmonyOS-布局

在上一节介绍了ArkUI的架构图,ArkUI两种开发范式--基于ArkTS的声明式开发范式(简称“声明式开发范式”)和兼容JS的类Web开发范式(简称“类Web开发范式”)。

后面的章节将基于ArkTS的声明式开发范式进行后面内容的基础介绍,包括布局、组件、状态管理、页面路由导航等。本节主要先介绍一下ArkUI的基本布局。

布局概述

布局指用特定的组件或者属性来管理用户页面所放置UI组件的大小和位置。在实际的开发过程中,需要遵守以下流程保证整体的布局效果:

布局结构

布局的结构通常是分层级的,代表了用户界面中的整体架构。一个常见的页面结构如下所示:

常见页面结构图

为实现上述效果,开发者需要在页面中声明对应的元素。其中,Page表示页面的根节点,Column/Row等元素为系统组件。针对不同的页面结构,ArkUI提供了不同的布局组件来帮助开发者实现对应布局的效果,例如Row用于实现线性布局。

布局元素的组成

布局相关的容器组件可形成对应的布局效果。

布局元素组成图

如何选择布局

声明式UI提供了以下9种常见布局,开发者可根据实际应用场景选择合适的布局进行页面开发。

布局

应用场景

线性布局(Row、Column)

如果布局内子元素超过1个,且能够以某种方式线性排列时优先考虑此布局。

层叠布局(Stack)

组件需要有堆叠效果时优先考虑此布局,层叠布局的堆叠效果不会占用或影响其他同容器内子组件的布局空间。例如Panel作为子组件弹出时将其他组件覆盖更为合理,则优先考虑在外层使用堆叠布局。

弹性布局(Flex)

弹性布局是与线性布局类似的布局方式。区别在于弹性布局默认能够使子组件压缩或拉伸。在子组件需要计算拉伸或压缩比例时优先使用此布局,可使得多个容器内子组件能有更好的视觉上的填充容器效果。

相对布局(RelativeContainer)

相对布局是在二维空间中的布局方式,不需要遵循线性布局的规则,布局方式更为自由。通过在子组件上设置锚点规则(AlignRules)使子组件能够将自己在横轴、纵轴中的位置与容器或容器内其他子组件的位置对齐。设置的锚点规则可以天然支持子元素压缩、拉伸,堆叠或形成多行效果。在页面元素分布复杂或通过线性布局会使容器嵌套层数过深时推荐使用。

栅格布局(GridRow、GridCol)

栅格是多设备场景下通用的辅助定位工具,通过将空间分割为有规律的栅格。栅格不同于网格布局固定的空间划分,它可以实现不同设备下不同的布局,空间划分更随心所欲,从而显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。推荐手机、大屏、平板等不同设备,内容相同但布局不同时使用。

媒体查询(@ohos.mediaquery)

媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。例如根据设备和应用的不同属性信息设计不同的布局,以及屏幕发生动态改变时更新应用的页面布局。

列表(List)

使用列表可以轻松高效地显示结构化、可滚动的信息。在ArkUI中,列表具有垂直和水平布局能力和自适应交叉轴方向上排列个数的布局能力,超出屏幕时可以滚动。列表适合用于呈现同类数据类型或数据类型集,例如图片和文本。

网格(Grid)

网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局。网格布局可以控制元素所占的网格数量、设置子组件横跨几行或者几列,当网格容器尺寸发生变化时,所有子组件以及间距等比例调整。推荐在需要按照固定比例或者均匀分配空间的布局场景下使用,例如计算器、相册、日历等。

轮播(Swiper)

轮播组件通常用于实现广告轮播、图片预览、可滚动应用等。

布局位置

position、offset等属性影响了布局容器相对于自身或其他组件的位置。

定位能力

使用场景

实现方式

绝对定位

对于不同尺寸的设备,使用绝对定位的适应性会比较差,在屏幕的适配上有缺陷。

使用position实现绝对定位,设置元素左上角相对于父容器左上角偏移位置。在布局容器中,设置该属性不影响父容器布局,仅在绘制时进行位置调整。

相对定位

相对定位不脱离文档流,即原位置依然保留,不影响元素本身的特性,仅相对于原位置进行偏移。

使用offset可以实现相对定位,设置元素相对于自身的偏移量。设置该属性,不影响父容器布局,仅在绘制时进行位置调整。

对子元素的约束

对子元素的约束能力

使用场景

实现方式

拉伸

容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。

flexGrow和flexShrink属性:

  1. flexGrow基于父容器的剩余空间分配来控制组件拉伸。
  2. flexShrink设置父容器的压缩尺寸来控制组件压缩。

缩放

子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。

aspectRatio属性指定当前组件的宽高比来控制缩放,公式为:aspectRatio=width/height。

占比

占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。

基于通用属性的两种实现方式:

1. 将子组件的宽高设置为父组件宽高的百分比。

2. layoutWeight属性,使得子元素自适应占满剩余空间。

隐藏

隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。

通过displayPriority属性来控制页面的显示和隐藏。

线性布局(Row/Column)

线性布局(LinearLayout)是开发中最常用的布局,通过线性容器RowColumn构建。线性布局是其他布局的基础,其子元素在线性方向上(水平方向和垂直方向)依次排列。线性布局的排列方向由所选容器组件决定,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。根据不同的排列方向,开发者可选择使用Row或Column容器创建线性布局。

Column容器内子元素排列示意图

Row容器内子元素排列示意图

布局子元素在排列方向上的间距

在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。


Column容器内排列方向的间距图

示例代码如下:

Column({ space: 20 }) { 
  Text('space: 20').fontSize(15).fontColor(Color.Gray).width('90%')  
  Row().width('90%').height(50).backgroundColor(0xF5DEB3)  
  Row().width('90%').height(50).backgroundColor(0xD2B48C)  
  Row().width('90%').height(50).backgroundColor(0xF5DEB3)
}.width('100%')

运行效果图:

Row容器内排列方向上间距与Column基本类似,就不再赘述。

对齐方式

垂直方向取值为VerticalAlign类型,水平方向取值为HorizontalAlign类型。

Column容器内子元素在水平方向上的排列:

Column容器内子元素在水平方向上的排列图

示例代码:

Column({}) {
  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)

  Column() {
  }.width('80%').height(50).backgroundColor(0xD2B48C)

  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)
}.width('100%').alignItems(HorizontalAlign.Start).backgroundColor('rgb(242,242,242)')

运行结果

示例代码:

Column({}) {
  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)

  Column() {
  }.width('80%').height(50).backgroundColor(0xD2B48C)

  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)
}.width('100%').alignItems(HorizontalAlign.Center).backgroundColor('rgb(242,242,242)')

运行结果

示例代码:

Column({}) {
  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)

  Column() {
  }.width('80%').height(50).backgroundColor(0xD2B48C)

  Column() {
  }.width('80%').height(50).backgroundColor(0xF5DEB3)
}.width('100%').alignItems(HorizontalAlign.End).backgroundColor('rgb(242,242,242)')

运行结果


Row容器内子元素在垂直方向上的排列:

Row容器内子元素在垂直方向上的排列图

布局子元素在主轴上的排列方式:

Column容器内子元素在垂直方向上的排列图


Row容器内子元素在水平方向上的排列图

自适应拉伸

在线性布局下,常用空白填充组件Blank,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。Row和Column作为容器,只需要添加宽高为百分比,当屏幕宽高发生变化时,会产生自适应效果。

@Entry@Componentstruct 
BlankExample { 
  build() {    
    Column() {      
      Row() {        
        Text('Bluetooth').fontSize(18)        
        Blank()        
        Toggle({ type: ToggleType.Switch, isOn: true })      
      }.backgroundColor(0xFFFFFF).borderRadius(15).padding({ left: 12 }).width('100%')   
    }.backgroundColor(0xEFEFEF).padding(20).width('100%')  
  }
}


竖屏效果图


横屏效果图

自适应缩放

自适应缩放是指子组件随容器尺寸的变化而按照预设的比例自动调整尺寸,适应各种不同大小的设备。在线性布局中,可以使用以下两种方法实现自适应缩放。

@Entry
@Component
struct layoutWeightExample {
  build() {
    Column() {
      Text('1:2:3').width('100%')
      Row() {
        Column() {
          Text('layoutWeight(1)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(1).backgroundColor(0xF5DEB3).height('100%')

        Column() {
          Text('layoutWeight(2)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(0xD2B48C).height('100%')

        Column() {
          Text('layoutWeight(3)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%')

      }.backgroundColor(0xffd306).height('30%')

      Text('2:5:3').width('100%')
      Row() {
        Column() {
          Text('layoutWeight(2)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(2).backgroundColor(0xF5DEB3).height('100%')

        Column() {
          Text('layoutWeight(5)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(5).backgroundColor(0xD2B48C).height('100%')

        Column() {
          Text('layoutWeight(3)')
            .textAlign(TextAlign.Center)
        }.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%')
      }.backgroundColor(0xffd306).height('30%')
    }
  }
}

运行效果如下:

@Entry
@Component
struct WidthExample {
  build() {
    Column() {
      Row() {
        Column() {
          Text('left width 20%')
            .textAlign(TextAlign.Center)
        }.width('20%').backgroundColor(0xF5DEB3).height('100%')

        Column() {
          Text('center width 50%')
            .textAlign(TextAlign.Center)
        }.width('50%').backgroundColor(0xD2B48C).height('100%')

        Column() {
          Text('right width 30%')
            .textAlign(TextAlign.Center)
        }.width('30%').backgroundColor(0xF5DEB3).height('100%')
      }.backgroundColor(0xffd306).height('30%')
    }
  }
}

运行效果如下:

自适应延伸

自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示。这种方法适用于线性布局中内容无法一屏展示的场景。通常有以下两种实现方式。

@Entry
@Component
struct ScrollExample {
  scroller: Scroller = new Scroller();
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  build() {
    Scroll(this.scroller) {
      Column() {
        ForEach(this.arr, (item) => {
          Text(item.toString())
            .width('90%')
            .height(150)
            .backgroundColor(0xFFFFFF)
            .borderRadius(15)
            .fontSize(16)
            .textAlign(TextAlign.Center)
            .margin({ top: 10 })
        }, item => item)
      }.width('100%')
    }
    .backgroundColor(0xDCDCDC)
    .scrollable(ScrollDirection.Vertical) // 滚动方向为垂直方向
    .scrollBar(BarState.On) // 滚动条常驻显示
    .scrollBarColor(Color.Gray) // 滚动条颜色
    .scrollBarWidth(10) // 滚动条宽度
    .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
  }
}

层叠布局(Stack)

层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠,容器中的子元素(子组件)依次入栈,后一个子元素覆盖前一个子元素,子元素可以叠加,也可以设置位置。

层叠布局具有较强的页面层叠、位置定位能力,其使用场景有广告、卡片层叠效果等。

如下图,Stack作为容器,容器内的子元素(子组件)的顺序为Item1->Item2->Item3。

层叠布局

示例代码:

Column(){
  Stack({ }) {
    Column(){}.width('90%').height('100%').backgroundColor('#ff58b87c')
    Text('text').width('60%').height('60%').backgroundColor('#ffc3f6aa')
    Button('button').width('30%').height('30%').backgroundColor('#ff8ff3eb').fontColor('#000')
  }.width('100%').height(150).margin({ top: 50 })
}

运行效果:

对齐方式

Stack组件通过alignContent参数实现位置的相对移动。如图2所示,支持九种对齐方式。

Stack容器内元素的对齐方式

Z序控制

Stack容器中兄弟组件显示层级关系可以通过Z序控制的zIndex属性改变。zIndex值越大,显示层级越高,即zIndex值大的组件会覆盖在zIndex值小的组件上方。

在层叠布局中,如果后面子元素尺寸大于前面子元素尺寸,则前面子元素完全隐藏。

示例代码:

Stack({ alignContent: Alignment.BottomStart }) {
  Column() {
    Text('Stack子元素1').textAlign(TextAlign.End).fontSize(20)
  }.width(100).height(100).backgroundColor(0xffd306)

  Column() {
    Text('Stack子元素2').fontSize(20)
  }.width(150).height(150).backgroundColor(Color.Pink)

  Column() {
    Text('Stack子元素3').fontSize(20)
  }.width(200).height(200).backgroundColor(Color.Grey)
}.margin({ top: 100 }).width(350).height(350).backgroundColor(0xe0e0e0)

运行效果:

上图中,最后的子元素3的尺寸大于前面的所有子元素,所以,前面两个元素完全隐藏。改变子元素1,子元素2的zIndex属性后,可以将元素展示出来。

Stack({ alignContent: Alignment.BottomStart }) {
  Column() {
    Text('Stack子元素1').fontSize(20)
  }.width(100).height(100).backgroundColor(0xffd306).zIndex(2)

  Column() {
    Text('Stack子元素2').fontSize(20)
  }.width(150).height(150).backgroundColor(Color.Pink).zIndex(1)

  Column() {
    Text('Stack子元素3').fontSize(20)
  }.width(200).height(200).backgroundColor(Color.Grey)
}.margin({ top: 100 }).width(350).height(350).backgroundColor(0xe0e0e0)

运行效果:

弹性布局(Flex)

弹性布局(Flex)提供更加有效的方式对容器中的子元素进行排列、对齐和分配剩余空间。容器默认存在主轴与交叉轴,子元素默认沿主轴排列,子元素在主轴方向的尺寸称为主轴尺寸,在交叉轴方向的尺寸称为交叉轴尺寸。弹性布局在开发场景中用例特别多,比如页面头部导航栏的均匀分布、页面框架的搭建、多行数据的排列等等。


主轴为水平方向的Flex容器示意图

布局方向

在弹性布局中,容器的子元素可以按照任意方向排列。通过设置参数direction,可以决定主轴的方向,从而控制子组件的排列方向。

FlexDirection.Row(默认值):主轴为水平方向,子组件从起始端沿着水平方向开始排布。

Flex({ direction: FlexDirection.Row }) {
  Text('1').width('33%').height(50).backgroundColor(0xF5DEB3)
  Text('2').width('33%').height(50).backgroundColor(0xD2B48C)
  Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
}
.height(70)
.width('90%')
.padding(10)
.backgroundColor(0xAFEEEE)

布局换行

弹性布局分为单行布局和多行布局。默认情况下,Flex容器中的子元素都排在一条线(又称“轴线”)上。wrap属性控制当子元素主轴尺寸之和大于容器主轴尺寸时,Flex是单行布局还是多行布局。在多行布局时,通过交叉轴方向,确认新行堆叠方向。

主轴对齐方式

通过justifyContent参数设置在主轴方向的对齐方式。

示例代码:

Flex({ justifyContent: FlexAlign.Start }) {  
  Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
  Text('2').width('20%').height(50).backgroundColor(0xD2B48C)    
  Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
}
.width('90%')
.padding({ top: 10, bottom: 10 })
.backgroundColor(0xAFEEEE)

运行效果:

交叉轴对齐方式

可以通过Flex组件的alignItems参数设置子组件在交叉轴的对齐方式。

内容对齐

可以通过alignContent参数设置子组件各行在交叉轴剩余空间内的对齐方式,只在多行的flex布局中生效,可选值有:

自适应拉伸

在弹性布局父组件尺寸不够大的时候,通过子组件的下面几个属性设置其在父容器的占比,达到自适应布局能力。

Flex() {
  Text('flexBasis("auto")')
    .flexBasis('auto') // 未设置width以及flexBasis值为auto,内容自身宽度
    .height(100)
    .backgroundColor(0xF5DEB3)
  Text('flexBasis("auto")' + ' width("40%")')
    .width('40%')
    .flexBasis('auto') //设置width以及flexBasis值auto,使用width的值
    .height(100)
    .backgroundColor(0xD2B48C)

  Text('flexBasis(100)') // 未设置width以及flexBasis值为100,宽度为100vp
    .fontSize(15)
    .flexBasis(100)
    .height(100)
    .backgroundColor(0xF5DEB3)

  Text('flexBasis(100)')
    .fontSize(15)
    .flexBasis(100)
    .width(200) // flexBasis值为100,覆盖width的设置值,宽度为100vp
    .height(100)
    .backgroundColor(0xD2B48C)
}.width('90%').height(120).padding(10).backgroundColor(0xAFEEEE)

Flex() {
Text('flexGrow(2)')
  .flexGrow(2) 
  .width(100)
  .height(100)
  .backgroundColor(0xF5DEB3)

Text('flexGrow(3)')
  .flexGrow(3)
  .width(100)
  .height(100)
  .backgroundColor(0xD2B48C)

Text('no flexGrow')
  .width(100) 
  .height(100)
  .backgroundColor(0xF5DEB3)
}.width(420).height(120).padding(10).backgroundColor(0xAFEEEE)

Flex({ direction: FlexDirection.Row }) {
  Text('flexShrink(3)')
    .fontSize(15)
    .flexShrink(3)
    .width(200)
    .height(100)
    .backgroundColor(0xF5DEB3)

  Text('no flexShrink')
    .width(200)
    .height(100)
    .backgroundColor(0xD2B48C)

  Text('flexShrink(2)')
    .flexShrink(2)
    .width(200)
    .height(100)
    .backgroundColor(0xF5DEB3)
}.width(400).height(120).padding(10).backgroundColor(0xAFEEEE)

相对布局(RelativeContainer)

RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。下图是一个RelativeContainer的概念图,图中的虚线表示位置的依赖关系。

锚点设置

锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。为了明确定义锚点,必须为RelativeContainer及其子元素设置ID,用于指定锚点信息。ID默认为“__container__”,其余子元素的ID通过id属性设置。未设置ID的子元素在RelativeContainer中不会显示。

RelativeContainer() {
  Row()
    // 添加其他属性
    .alignRules({
      top: { anchor: '__container__', align: VerticalAlign.Top },
      left: { anchor: '__container__', align: HorizontalAlign.Start }
    })
    .id("row1")

  Row()
    .alignRules({
      top: { anchor: '__container__', align: VerticalAlign.Top },
      right: { anchor: '__container__', align: HorizontalAlign.End }
    })
    .id("row2")
}

RelativeContainer() {
  Row()
    // 添加其他属性
    .alignRules({
      top: { anchor: '__container__', align: VerticalAlign.Top },
      left: { anchor: '__container__', align: HorizontalAlign.Start }
    })
    .id("row1")

  Row()
    .alignRules({
      top: { anchor: 'row1', align: VerticalAlign.Bottom },
    })
    .id("row2")
}

设置相对于锚点的对齐位置

设置了锚点之后,可以通过align设置相对于锚点的对齐位置。

在水平方向上,对齐位置可以设置为HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End。

在竖直方向上,对齐位置可以设置为VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom。

示例代码:

@Entry
@Component
struct Index {
  build() {
    Row() {
      RelativeContainer() {
        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF3333')
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },  //以父容器为锚点,竖直方向顶头对齐
            middle: { anchor: '__container__', align: HorizontalAlign.Center }  //以父容器为锚点,水平方向居中对齐
          })
          .id('row1')  //设置锚点为row1

        Row() {
          Image($r('app.media.icon'))
        }
        .height(100).width(100)
        .alignRules({
          top: { anchor: 'row1', align: VerticalAlign.Bottom },  //以row1组件为锚点,竖直方向底端对齐
          left: { anchor: 'row1', align: HorizontalAlign.Start }  //以row1组件为锚点,水平方向开头对齐
        })
        .id('row2')  //设置锚点为row2

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FFCC00')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Top }
          })
          .id('row3')  //设置锚点为row3

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF9966')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Top },
            left: { anchor: 'row2', align: HorizontalAlign.End },
          })
          .id('row4')  //设置锚点为row4

        Row()
          .width(100)
          .height(100)
          .backgroundColor('#FF66FF')
          .alignRules({
            top: { anchor: 'row2', align: VerticalAlign.Bottom },
            middle: { anchor: 'row2', align: HorizontalAlign.Center }
          })
          .id('row5')  //设置锚点为row5
      }
      .width(300).height(300)
      .border({ width: 2, color: '#6699FF' })
    }
    .height('100%').margin({ left: 30 })
  }
}

运行效果:

网格(Grid/GridItem)

网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。

ArkUI提供了Grid容器组件和子组件GridItem,用于构建网格布局。Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。Grid组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。

网格布局

网格布局是一种二维布局。Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。当网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,从而实现网格布局的自适应能力。根据Grid的这些布局能力,可以构建出不同样式的网格布局,如下图所示。

如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。

Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:

排列方式

通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。

rowsTemplate和columnsTemplate属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列的宽度。

如上图所示,构建的是一个三行三列的的网格布局,其在垂直方向上分为三等份,每行占一份;在水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份。

只要将rowsTemplate的值为'1fr 1fr 1fr',同时将columnsTemplate的值为'1fr 2fr 1fr',即可实现上述网格布局。

Grid() {
  ...
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')

说明

当Grid组件设置了rowsTemplate或columnsTemplate时,Grid的layoutDirection、maxCount、minCount、cellLength属性不生效,属性说明可参考Grid-属性。

除了大小相同的等比例网格布局,由不同大小的网格组成不均匀分布的网格布局场景在实际应用中十分常见,如下图所示。在Grid组件中,通过设置GridItem的rowStart、rowEnd、columnStart和columnEnd可以实现如图所示的单个网格横跨多行或多列的场景。

不均匀网格布局

在单个网格单元中,rowStart和rowEnd属性表示指定当前元素起始行号和终点行号,columnStart和columnEnd属性表示指定当前元素的起始列号和终点列号。

使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。

主轴方向示意图

当前layoutDirection设置为Row时,先从左到右排列,排满一行再排一下一行。当前layoutDirection设置为Column时,先从上到下排列,排满一列再排一下一列,如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。

Grid() {
  ...
}
.maxCount(3)
.layoutDirection(GridDirection.Row)

说明

1. layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效,此时元素在layoutDirection方向上排列。

2. 仅设置rowsTemplate时,Grid主轴为水平方向,交叉轴为垂直方向。

2. 仅设置columnsTemplate时,Grid主轴为垂直方向,交叉轴为水平方向。

在网格布局中显示数据

设置行列间距

在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距,如下图所示。

通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。在图5所示的计算器中,行间距为15vp,列间距为10vp。

Grid() {  ...}
  .columnsGap(10)
  .rowsGap(15)

可滚动的网格布局

可滚动的网格布局常用在文件管理、购物或视频列表等页面中,如下图所示。在设置Grid的行列数量与占比时,如果仅设置行、列数量与占比中的一个,即仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。

如果设置的是columnsTemplate,Grid的滚动方向为垂直方向;如果设置的是rowsTemplate,Grid的滚动方向为水平方向。

控制滚动位置

与新闻列表的返回顶部场景类似,控制滚动位置功能在网格布局中也很常用,例如下图所示日历的翻页功能。

日历翻页

Grid组件初始化时,可以绑定一个Scroller对象,用于进行滚动控制,例如通过Scroller对象的scrollPage方法进行翻页。

private scroller: Scroller = new Scroller()

在日历页面中,用户在点击“下一页”按钮时,应用响应点击事件,通过指定scrollPage方法的参数next为true,滚动到下一页。

Column({ space: 5 }) {
  Grid(this.scroller) {
    ...
  }
  .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
  ...
 
 Row({space: 20}) {
   Button('上一页')
     .onClick(() => {
       this.scroller.scrollPage({
         next: false
       })
     })

   Button('下一页')
     .onClick(() => {
       this.scroller.scrollPage({
         next: true
       })
     })
 }
}
...
展开阅读全文

页面更新:2024-05-13

标签:布局   主轴   网格   容器   排列   组件   属性   元素   尺寸   方向

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top