上文学习了List布局容器的基本概念,了解List布局容器的相关约束,详细学习了List容器组件数据展示(包括迭代展示)、列表样式定义(分割线)、数据分组展示等相关常见使用场景的应用方法,本文将学习网格布局容器相关知识。
?
网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。
????Grid容器组件和子组件GridItem,用于构建网格布局。
Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。
Grid组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。
Grid与GridItem组件关系,Grid的子组件必须是GridItem组件
网格布局是一种二维布局,Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,具有自适应能力
网格布局可以实现下图所示的效果
Grid组件宽高属性:如果设置了宽高属性,则其尺寸为设置值。如果没有,Grid组件的尺寸默认适应其父组件的尺寸
Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况
行、列数量与占比同时设置:Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)
只设置行、列数量与占比中的一个:元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。
行列数量与占比都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且Grid不可滚动。
1.设置行列数量与占比
Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比,属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列的宽度
Grid() {
...
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')
如上代码所示,构建的是一个三行三列的的网格布局,其在水平方向上分为三等份,每行占一份;在垂直方向上分为四等份,第一列占一份,第二列占两份,第三列占一份,布局效果如下图所示。
注:当Grid组件设置了rowsTemplate或columnsTemplate时,Grid的layoutDirection、maxCount、minCount、cellLength属性不生效
2.设置子组件所占行列数
由不同大小的网格组成不均匀分布的网格布局场景在实际应用中十分常见
在Grid组件中,通过设置GridItem的rowStart、rowEnd、columnStart和columnEnd可以实现单个网格横跨多行或多列的场景,布局效果如下图所示
单个网格单元中,rowStart和rowEnd属性表示指定当前元素起始行号和终点行号,columnStart和columnEnd属性表示指定当前元素的起始列号和终点列号
GridItem() {
Text(key)
...
}
.columnStart(3)
.columnEnd(4)
以上代码表示,网格中单元格占用第3列和第4列,如上图布局效果图中右上角的单元格
3.设置主轴方向
使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量,主轴方向示意图如下
当layoutDirection设置为Row时,先从左到右排列,排满一行再排一下一行。
当layoutDirection设置为Column时,先从上到下排列,排满一列再排一下一列。
如上图所示。layoutDirection属性结合maxCount属性,layoutDirection决定主轴方向,maxCount属性决定主轴方向上最大单元格数量,maxCount设置的3,如上图主轴方向上单元格3个。
注:layoutDirection属性仅在同时不设置rowsTemplate和columnsTemplate时生效;仅设置rowsTemplate时,Grid主轴为水平方向,交叉轴为垂直方向;仅设置columnsTemplate时,Grid主轴为垂直方向,交叉轴为水平方向。
在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距,如下图所示
通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距
Grid() {
...
}
.columnsGap(10)
.rowsGap(15)
1.静态展示:Grid组件可以通过二维布局的方式显示一组GridItem子组件
Grid() {
GridItem() {
Text('会议')
...
}
GridItem() {
Text('签到')
...
}
GridItem() {
Text('投票')
...
}
GridItem() {
Text('打印')
...
}
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr')
布局效果:
1.动态展示:通常使用循环渲染ForEach语句中嵌套GridItem的形式
@Component
struct OfficeService {
@State services: Array<string> = ['会议', '投票', '签到', '打印']
...
build() {
Column() {
Grid() {
ForEach(this.services, service => {
GridItem() {
Text(service)
...
}
}, service => service)
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr')
...
}
...
}
}
可滚动的网格布局常用在文件管理、购物或视频列表等页面中。
在设置Grid的行列数量与占比时,如果仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。
如果设置的是columnsTemplate,Grid的滚动方向为垂直方向;如果设置的是rowsTemplate,Grid的滚动方向为水平方向。
@Component
struct Shopping {
@State services: Array<string> = ['直播', '进口', ...]
...
build() {
Column({ space: 5 }) {
Grid() {
ForEach(this.services, (service: string, index) => {
GridItem() {
...
}
.width('25%')
}, service => service)
}
.rowsTemplate('1fr 1fr') // 只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动。
.rowsGap(15)
...
}
...
}
}
以上代码只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动
与新闻列表的返回顶部场景类似,控制滚动位置功能在网格布局中也很常用,例如下图所示日历的翻页功能。
//Grid组件初始化时,可以绑定一个Scroller对象,用于进行滚动控制,通过Scroller对象的scrollPage方法进行翻页
private scroller: Scroller = new Scroller()
Column({ space: 5 }) {
Grid(this.scroller) {
...
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
...
Row({space: 20}) {
Button('上一页')
.onClick(() => {
this.scroller.scrollPage({
next: false
})
})
//用户点击“下一页”按钮时,响应点击事件,通过指定scrollPage方法的参数next为true,滚动到下一页
Button('下一页')
.onClick(() => {
this.scroller.scrollPage({
next: true
})
})
}
}
...
循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载的方式实现按需迭代加载数据,从而提升列表性能。
当使用懒加载方式渲染网格时,为了更好的滚动体验,减少滑动时出现白块,Grid组件中也可通过cachedCount属性设置GridItem的预加载数量,只在懒加载LazyForEach中生效。
设置预加载数量后,会在Grid显示区域前后各缓存cachedCount*列数个GridItem,超出显示和缓存范围的GridItem会被释放
Grid() {
LazyForEach(this.dataSource, item => {
GridItem() {
...
}
})
}
.cachedCount(3)
本文详细学习了网格布局相关概念,以及网格布局的相关约束,详细学习了网格布局排列方式以及网格行列间距的设置,了解了网格布局常用的使用场景以及性能优化。下文将学习轮播布局。