在上一篇鸿蒙布局第一篇--详细介绍ArkUI中线性布局,层叠布局和弹性布局中,我们学习了ArkUI中线性布局,层叠布局和弹性布局的用法,了解到了这三种布局的特性以及各自都适用于哪种场景,那么这篇文章里面继续针对鸿蒙的布局组件做介绍,今天的主角是相对布局,网格布局和轮播组件
相对布局(RelativeContainer)
ArkUI的相对布局有点类似于Android里面的RelativeLayout
,相对布局里面的元素通过指定父布局或者其他元素作为锚点来设置自己的位置,跟RelativeLayout
一样,在相对布局中每一个元素都必须有一个属于自己的唯一id,父布局的id是" __ Container __ "
注意:这里的Container前后其实是各两条下划线,文档里面是看不出来两条,如果Container前后只输入一条下划线的话,那么针对父布局作为锚点的布局将会失效,另外,也必须注意一点的是每一个元素的id是必须设置的,如果不设置id,该元素将不会在布局中出现
下面来敲几个例子来切身体会下这个相对布局,首先在一个相对布局中的四个角上各放置一个视图,代码如下
可以看到在相对布局中设置位置是通过函数alignRules
来完成的,在函数中,垂直方向可以设置top
,center
,bottom
位置的锚点,水平方向可以设置left
,middle
,right
位置的锚点,锚点对象则是通过anchor
属性来设置,anchor
就是每一个元素设置的id,而对齐方式就是通过align
属性来设置,水平方向上有HorizontalAlign.Start
,HorizontalAlign.Center
,HorizontalAlign.End
这三个选项,垂直方向上有VerticalAlign.Top
,VerticalAlign.Center
,VerticalAlign.Bottom
这三个选项,比如现在我们想让text2
在text1
的下方,text2
的左边与text1
的右边对齐,让text3
在text4
的上方,并且text3
的右边与text4
的左边对齐,那么可以通过更改anchor
与align
来实现,代码如下
只需要更改锚点对象以及对齐方式,元素的位置就发生改变了,基本上同Android里面的RelativeLayout
思想差不多
网格布局(Grid/GridItem)
网格布局也是比较常用的几个布局之一,比如日历,相册之类的应用都用到了网格布局,在ArkUI中的网格布局使用Grid
组件,并且Grid
的子组件必须使用GridItem
,接下来通过几个主要的属性来讲下如何使用网格布局
设置行列数量以及占比
网格布局里面分别使用rowsTemplate
函数来设置行数以及占比,使用columnsTemplate
函数来设置列数以及占比,设置方法都一样,都是在函数里面传入一个字符串,字符串类似于下面这个样子
通过空格将每个数字+fr的字符串分割开来,这串字符串代表的意义有两个,有多少个fr就代表行或者列的数量,fr前面的数字表示分割比例,下面看个例子
看到这里有个网格布局,并且将网格横向等分成四份,纵向也将网格等分成4份,但是总的数据有17个,我们运行下代码看看效果
可以看到只出现了十六个元素,第十七个元素不见了,被挡在了视图的外面,如果我们也想看到第十七个元素,就必须让网格布局滚动起来,滚动起来的方式很简单,只设置行列方向占比的其中一个,比如只保留列数和列占比设置,那么网格的主轴方向就是水平的,反之主轴方向就是垂直的,这样一来元素就会先沿着主轴方向排版,交叉轴方向元素布局如果超出Grid
的大小,超出的元素就可以通过滚动来查看,比如上面这个例子,我们去掉行设置rowsTemplate
看看效果
由于是去掉了行高的比例,所以给每个单项设置了120vp的高度,运行后的效果如下
可以看到如果元素在交叉轴方向超出了Grid
的大小,超出部分我们就可以向上滑动屏幕看到了,同样的,我们如果只设置行高的比例,不设置列的比例,那么布局元素的交叉轴就变成了水平方向,更改下代码我们再看看实际效果
设置行间距,列间距
上述例子中可能有一点让大家感到不适,就是元素与元素之间都挤在了一起,分不清哪些区域属于某一个元素,所以通常这个时候我们就需要给元素之间设置间距了,而对于网格布局,它的间距分为行间距与列间距,分别用函数rowsGap
和columnsGap
来设置,传进去的参数就代表间距大小,比如给上面的例子添加间距,代码就是这样的
增加了5vp的行间距,10vp的列间距,现在运行一遍代码后效果稍微好看一点了
设置子组件所占的行列数
现在很多app的瀑布列经常会出现某一项item的宽高要比其他item要大,比如其他item高度占了一行,这个大一点的item占了两行,那么像这个样子的场景在网格布局中如何做呢?我们可以给GridItem
设置rowStart
和rowEnd
来跨越对应的行数,设置columnStart
和columnEnd
来跨越对应的列数,同样是上面的例子,我们现在想让元素6可以向下跨一行,元素10可以向右跨一行,可以这样做
代码中元素6调用了rowStart
函数,传入了它本身所在的行数1,然后调用rowEnd
函数,传入了它所需要跨入的行数2,同样给元素10也设置了columnStart(2)
与columnEnd(3)
,然后看下效果
正如代码中设置的一样,6跟10都跨越了自己的行数或者列数,可能细心的朋友们已经发现了,这里同时给网格布局设置了横向与纵向的比例,如果我只设置其中一个比例,那么子组件还会完成跨越吗,下面来试试看
这里将列的比例给去掉了,只剩下行的比例,那么最终元素6与10还能不能正常跨越呢,跑下看看
由于列的比例去掉了,子组件也没有设置width
,所以展示的效果子组件才会变得这么窄,这个可以忽略,我们发现,元素6依然可以成功跨越行数,但是元素10就不一样了,没有跨越2列与3列,只占了第3列的格子,第2列是空着的,那么同样的,保留列的比例设置,去除行的比例,那是不是元素6也不能跨了呢,再试下
的确如此,所以我们可以得出这样的结论,网格布局的子组件如果想要横向跨越,那么必须设置列数和列占比,如果想要纵向跨越,那么必须设置行数和行占比
设置主轴方向
前面有尝试过分别只设置行比例或者列比例的时候,网格布局的主轴和交叉轴会来回切换,那么如果行列比例都不设置,那么该如何设置主轴方向呢,可以通过设置layoutDirection
和maxCount
来实现,前者是确定主轴方向,有四个值分别为GridDirection.Row
,GridDirection.RowReverse
,GridDirection.Column
和GridDirection.ColumnReverse
,后者是确定主轴上的最大数量,接下来通过上面的例子分别使用这四个方向来感受下布局方向以及排版,maxCount
就设置为3
GridDirection.Row
GridDirection.RowReverse
GridDirection.Column
GridDirection.ColumnReverse
轮播组件(Swiper)
ArkUI里面的这个组件我还是比较喜欢的,有了这个组件就可以更加轻松的去实现类似于banner一样的轮播图功能,想想在Android原生中如果想要去实现一个轮播图,基本都会去找三方组件,就算自己去实现也是一大段代码,Compose里面虽然使用Pager
也可以很容易的去实现轮播图,但Pager
组件在Compose1.4.0之前还在Accompanist库里面,必须额外去依赖进来才可以使用,而ArkUI一上来就给我们提供了Swiper
这个组件,接下来就看看Swiper
组件都有啥特性
布局与约束
Swiper
组件当自身没有设置大小的时候,它的大小随着子组件的变化而改变,当自身设置了大小之后,所有子组件都以Swiper
大小展示,下面来看两个例子
Swiper没有设置容器高度
代码中我们给第一个子组件设置了100vp的高度,后面两个组件分别设置了200vp跟150vp的高度,而Swiper
是没有设置高度的,从效果图中我们发现,每个子组件的高度都以自身的高度为准
Swiper设置了自身高度
从这个例子中可以看到,当Swiper
设置了容器高度之后,尽管子组件的高度都不一样,但是最终展现的效果子组件都以容器的高度来展示
自动轮播
前面说了Swiper
可以实现banner一样效果,而banner是可以自动轮播的,所以Swiper
该如何实现自动轮播这个功能呢?很简单,可以设置autoPlay
属性,当它为true
的时候,Swiper
就可以实现自动轮播功能了
上述代码只是在之前的例子中多设置了一个autoPLay(true)
的属性,我们这个Swiper
就能够自动轮播了,效果如下
当自动轮播的时候,每一次切换的时间间隔是3秒,如果想要自己设置切换的时间间隔,可以通过设置interval
属性来实现,比如将上述例子的时间间隔改成1秒,就可以这样设置
也是通过一个属性,就将Swiper
的切换时间给改变了
导航点
可能大家也都发现了,当我们创建了一个Swiper
组件的时候,组件会默认自带一个导航点样式,就算Swiper
里面只有一个组件,导航点依然会存在,默认与Swiper
底部对齐,居中显示,但有时候,我们只想要实现类似于Android中ViewPager
一样的翻页的效果,不想要导航点,那么该如何去掉呢?可以去设置indicator
属性,它默认为true
,表示展示导航点,只要将它设置成false
,导航点就没有了,我们看下面的代码
可以从效果图中看到,我们只是在上面的例子中多添加了一个indicator(false)
的属性,就成功的去掉了导航点,还是很容易的,但是对于导航点来说,大家遇到的更多的情况就是去更改导航点的样式以及它的位置,而Swiper
中的indicatorStyle
属性就是用来更改导航点的样式以及位置的,首先可以通过top
,left
,bottom
,right
去设置导航点相对于Swiper
的间距,比如现在默认是居中与底部对齐,我们想要让导航点与Swiper左边间距10vp,与顶部间距10vp,就可以这样设置
得到的效果就如图所示导航点就靠Swiper
的左上位置了,而如果想要设置导航点的大小,就可以使用size
去设置,比如我们想要让导航点的圆点直径大小变成30vp,就可以这样设置
这样就获得了一个直径大小为30vp的导航点,另外选中与未选中的色值,也可以通过selectedColor
与color
来设置
这里将选中状态的颜色设置成了#757575
,将未选中的色值颜色改成了#2e212121
,得到的效果图如下
总结
这三种布局算是在日常开发中比较常用的,而且使用起来也比较简单,但尽管这样,有些细节如果不注意,依然会产生一些很困惑的问题,比如相对布局里面父布局的id,要不是我将官方文档里面的示例代码复制出来才发现原来有两个下划线,我可能还会指着模拟器上怎么都无法与父布局右边对齐的元素对隔壁同事说:快看!我找到个bug!