【鸿蒙开发实战篇】详细介绍ArkUI中线性布局,层叠布局和弹性布局

前言

我们知道学习任何一个语言,都是要先从基础语法开始,而对于一个前端语言来讲,基础语法肯定是要从学习它的布局用法开始,在ArkUI里面,也有它自己的布局组件,本篇内容里面将会先了解一下ArkUI里面线性布局,层叠布局和弹性布局的用法

线性布局(Row/Column)

学过Flutter或者Compose的基本都不会对这俩个布局感到陌生,基本在哪里概念都是相同的,Row代表着布局子元素可以在水平方向上排列布局,它的主轴就是水平方向,交叉轴就是垂直方向,Column代表着布局子元素在垂直方向上排列,它的主轴就是垂直方向,交叉轴就是水平方向,下面就是一些常见属性在ArkTS里面的是如何设置的

间距

所谓距离产生美,在任何一个线性布局里面的元素之间,相信多多少少都会存在一些间距,那么在ArkTS里面我们使用space属性来设置间距,来看下面这段代码
在这里插入图片描述

这里有个Column组件,在组件里面添加了三个Row组件并且使用不同的颜色区分开来,现在Row之间是没有设置任何间距的,页面展示的样子是这样的
在这里插入图片描述

而通过添加space属性就可以让Column的子元素在主轴方向上设置间距
在这里插入图片描述
在这里插入图片描述

看到这里添加完space属性之后,Column里面的元素之间就有间距了,当然我们也可以给子元素设置margin,这样也可以达到同样的效果,但是space是最直观的,Row的间距是同样的设置方式,这里就省略了,感兴趣的可以自行尝试

对齐方式

除了间距,对齐方式也是比较常用的,对齐方式主要分为在主轴上的对齐方式和在交叉轴上的对齐方式,在主轴上我们使用justifyContent函数来设置,入参是一个枚举类FlexAlign,有以下几个值
在这里插入图片描述

下面是每个枚举值所对应的样式

FlexAlign.Start

在这里插入图片描述

FlexAlign.Center

在这里插入图片描述

FlexAlign.End

在这里插入图片描述

FlexAlign.SpaceBetween

在这里插入图片描述

FlexAlign.SpaceEvenly

在这里插入图片描述

FlexAlign.SpaceAround

在这里插入图片描述

与主轴上对齐相对应的,还有交叉轴上的对齐方式,在交叉轴上使用alignItems函数去对齐元素,接收的参数是,如果交叉轴是水平方向的,那么使用枚举类HorizontalAlign作为参数,所支持的枚举属性是Start,Center,End,如果交叉轴方向是垂直方向的,那么使用枚举类VerticalAlign作为参数,所支持的枚举属性是Top,Center,Bottom,下面以Row组件为例看一下交叉轴方向上如何对齐

VerticalAlign.Top

在这里插入图片描述

VerticalAlign.Center

在这里插入图片描述

VerticalAlign.Bottom

在这里插入图片描述

如果元素中某一个元素有自己的想法,不想用父组件定义的对齐方式,那么可以单独在子元素上设置alignSelf,传参是一个ItemAlign,有以下几个值
在这里插入图片描述

其中Baseline,Auto,Stretch适用于Flex布局,在Column与Row布局中只使用其他三个值Start,Center,End,理解起来也很容易,分别都是在交叉轴方向上的开始位置,中间位置和结束位置,比如在上面的例子中,我们在给所有子元素设置了交叉轴方向底部对齐的基础上,给中间的元素设置顶部对齐,代码与效果图如下所示
在这里插入图片描述

可以看到虽然父组件设置了alignItems(VerticalAlign.Bottom),但是由于中间的绿色视图单独设置了alignSelf(ItemAlign.Start),所以它并没有底部对齐而是在父组件的顶部对齐

自适应拉伸

之前遇到过这样一个问题,在一个Row里面有三个元素,要求是其中两个刚好是在组件左边并排着,而第三个元素是在组件的最右边,刚开始是这样实现的
在这里插入图片描述

可是我们现在已经知道alignSelf是在交叉轴方向上设置元素的对齐方式的,所以肯定是不起作用的,实际效果也如同下图所示
在这里插入图片描述

还有一种做法是将前两个元素包在一个组件内,然后在最外层的Row组件上设置
justifyContent(FlexAlign.SpaceBetween),虽说这样可以实现,但是需要多嵌套一层布局,有没有更加简便一点的方法呢,在ArkTS里面就提供了一个叫做Blank的组件来解决这个问题,这个组件的作用就是填充线性布局里面剩余的空间,用法也很简单,想要填充哪两个元素之间的空间,就将Blank加在哪,就像下面这样
在这里插入图片描述

我们看到最后呈现的效果的确是第三个文案在最右边了

权重

我们知道组件可以通过设置with(“100%”)来占满父组件宽度,height(“100%”)来占满父组件高度,但是如果不去设置这俩属性,能不能也可以达到占满父组件高度或者宽度呢,我们可以通过设置权重来完成,来看下面这个例子
在这里插入图片描述

父组件Row没有设置宽度,里面的元素也没有设置宽度,如果没有使用layoutWeight来设置权重的话,屏幕上是不会出现任何元素的,但是现在因为设置了layoutWeight,所以Row里面的三个子元素刚好占满父组件的宽度,效果如下
在这里插入图片描述

让线性布局滚起来

当使用线性布局开发的时候,有一个情况不得不考虑一下,要知道如果线性布局里面的子元素在主轴方向上一屏展示不下的时候是不会换行的,那么我们如果想要看屏幕之外的元素就不得不让线性布局滚动起来,在Android里面我们会给线性布局外面套个ScrollView,在Compose里面我们会使用scrollable操作符,那么在ArkTS里面如何做呢,我们使用Scroll组件,注意使用Scroll组件的时候需要传入一个Scroller的参数,具体用法如下所示
在这里插入图片描述
在这里插入图片描述

我们看到只需要在布局的外层套一个Scroll组件就可以实现线性布局滚动,Scroll还可以定义滚动条的样式以及是否常驻的属性,但不属于本篇内容就不细讲了,但是这里需要注意一点的是,当套了Scroll组件之后,Scroll里面的组件不能设置height属性,不然是没法滚动的

层叠布局(Stack)

对齐方式

层叠布局Stack可以使它的子元素可以叠在一起显示,类似于Android里面的Framelayout,但是有区别的是FrameLayout默认都是将子元素左上角放置,而Stack是将子元素居中显示,我们举个栗子
在这里插入图片描述

这里有三个Row组件添加在了一个Stack组件里面,最底下的Row宽高占了父组件宽高的80%,然后上面的占了60%,最上面的Row占了40%,我们运行一下代码得到效果如下
在这里插入图片描述

可以看到三个元素都是居中显示的,如果说我们想要更改一下对齐的方式,就要使用Stack组件提供的alignContent参数,总共有如下几个值可供选择
在这里插入图片描述

比如说我们想要让子元素的对齐方式改成左上对齐,那么就可以使用Alignment.TopStart来设置
在这里插入图片描述
在这里插入图片描述

可以看到现在的效果已经是左上角对齐了,另外我们在使用层叠布局的时候经常会遇到这种情况,就是在上面的布局经常会把下面的布局给挡住,造成的原因可能是排列顺序上出现了错误,比如我们将上面的代码更改一下
在这里插入图片描述

这里将原来在最下面的,宽高最大的元素放到最上面了,而将原来最上面,宽高最小的元素放在了最下面,那么得到的效果不用说肯定是下面这样的
在这里插入图片描述

看起来像只有一个,事实上是另外两个被蓝色的色块给遮挡住了,如果想要将三个色块都展示出来,我们可以更改一下色块的尺寸,将蓝色的色块调小,底部小的色块调大,但是我们平时开发中,布局组件大小肯定是不能随便更改的,这样做了的话设计师肯定会来找你要个说法,那么还有中办法就是更改一下Stack里面元素的排列顺序,但是简单的布局这样改比较容易,但是复杂一点的布局改顺序就比较麻烦了,不然顺序更改错了回头再调整就会更加头大,那么还有别的办法吗?有的,我们可以使用ArkTS提供的Z序控制来解决

Z序控制

这个看名字就知道大概的意思,就是控制元素在Z轴方向上的顺序,怎么控制呢?使用zIndex函数来实现,它里面接收一个number类型的参数,值越大,那么显示的层级就越高,值越小,层级就越低,如果不设置zIndex,那么层级是最低的,我们给上面的例子中添上zIndex参数再看看效果
在这里插入图片描述
在这里插入图片描述

可以看到原本由于顺序关系在最上面的蓝色色块,现在设置了一个最小的zIndex,就跑到最下面去了,相反原本在最下面的红色色块,由于zIndex最大,跑到了层级的最上面,现在我们再改下代码,之前说不设置zIndex的话层级是最小的,我们看看是不是这样
在这里插入图片描述

代码中我们将中间灰色色块的zIndex给去掉了,那么我们看看原本在中间层级的灰色色块,现在还在不在
在这里插入图片描述

可以看到灰色色块不见了,哪去了呢?跑到蓝色色块的后面去了,所以当你想把一个布局放在所有布局的最下面,除了给它设置一个最小的zIndex之外,还可以不给它设置,达到的效果是一样的

弹性布局(Flex)

有时候在使用Column或者Row的时候会遇到这样的一个情况,如果我想让元素的主轴排列顺序更改一下,就一定要改一下组件,Column与Row互相切换,着实有点太麻烦了,有没有一种组件能像Android的LinearLayout一样,改一个orientation就可以切换主轴的排列顺序呢?那么这里就可以使用弹性布局Flex,弹性布局更像是在Row与Column的并集的基础上又添加了一些自己的特性,也就是说上面我们介绍的Row与Column的特性在Flex上基本也都是通用的,下面就来看一下如何使用Flex

排列方向

之前就说Flex可以切换元素的主轴方向,那么切换的方式就是通过direction属性来切换,我们来看下面这段代码
在这里插入图片描述

这里在Flex里面放了三个Text,然后我们给Flex的direction属性设置了FlexDirection.Row,那么说明我们这个Flex就相当于一个Row组件了,看下效果
在这里插入图片描述

可以看到三个Text的确是按照主轴方向为水平并且从左到右方向上排列,为什么这里要强调说明一下是从左到右呢,因为Flex还可以设置子元素在水平方向上从右到左排列,使用FlexDirection.RowReverse实现,我们更改一下上面这段代码
在这里插入图片描述

看到这里已经将Flex的direction更改为FlexDirection.RowReverse,那么得到的效果就是下面这样
在这里插入图片描述

看到元素的排列方向已经更改为从右到左的了,这个是Row组件无法实现的,在Flex上做了一些扩展,同样的也可以在垂直方向上设置从上到下排列和从下到上排列
在这里插入图片描述
在这里插入图片描述

换行

之前在介绍Row组件的时候说起过一点,如果Row组件里面的元素在主轴方向上排列超过一屏了,那么超出部分将会看不到的,如果想要看到超出部分的元素,那么就必须让Row组件套在一个Scroll里面让它可以滚动,但是这个问题在Flex里面就不存在了,因为Flex允许它的子元素可以换行,通过设置wrap属性,默认是FlexWrap.NoWrap的,表示不换行,但是如果子元素在主轴上超出了一个屏幕,那么子元素会等比例缩放直到可以铺满一个屏幕,我们看下面这段代码
在这里插入图片描述

这里有个Column组件,里面有一个Flex跟Row,分别都水平方向上展示10个Text组件,但是每个Text的宽度都设置为80,那么明显所有Text的总宽度是会超出一个屏幕的,我们看下实际效果
在这里插入图片描述

可以看到在Row里面超出部分是看不到的,而在Flex里面,所有元素通过等比例缩放全部都展示在一个屏幕里面,这就是Flex在线性布局上属于自己的特性,而除了FlexWrap.NoWrap之外,我们还可以设置FlexWrap.Wrap允许Flex在元素超出一行的时候换行,我们更改一下上面的代码
在这里插入图片描述

现在Flex设置了FlexWrap.Wrap,那么里面的元素在超出一行的时候,就不会等比例缩放了,而是会换行显示,效果如下
在这里插入图片描述

FlexWrap还有另一个值,那就是FlexWrap.WrapReverse,看名字就知道干什么用的,Flex正常排序都是从左到右的,而FlexWrap.WrapReverse可以让元素从右到左排序,上面的例子换成FlexWrap.WrapReverse后的效果如下
在这里插入图片描述
在这里插入图片描述

主轴对齐

Flex主轴上的对齐方式与上面的Row/Column基本相同,唯一的差别是Flex是通过一个属性设置的,而Row/Column是通过一个函数设置的
在这里插入图片描述

可以看到无论是属性名字还是属性值,都与之前讲的Row与Column主轴上的对齐方式相同,所以由于上面已经讲过这类对齐方式的用法了,这里就不再重复讲了

交叉轴对齐

Flex在交叉轴上的对齐方式分为在容器上设置与给子元素设置,在容器上我们同样使用属性alignItems来设置,属性值同样有以下几种
在这里插入图片描述

其中ItemAlign.Start,ItemAlign.Center,ItemAlign.End在讲Row与Column时候已经说过了,这里讲一下其他三个ItemAlign.Auto,ItemAlign.Baseline,ItemAlign.Stretch

ItemAlign.Auto

这是Flex默认设置,不管是官方api文档或者是源码注释都是只有这一个说法,那到底ItemAlign.Auto是怎么样的一个呈现样式呢,我们写一个例子看看
在这里插入图片描述

这里同样在一个Flex组件里面放了三个Text,Text上没有设置任何对齐方式,Flex给子组件在交叉轴上设置了一个ItemAlign.Auto的对齐方式,当然由于是默认设置,这里写不写ItemAlign.Auto都是一样的,我们看下效果
在这里插入图片描述

所以ItemAlign.Auto表示的意思就是子组件在交叉轴上顶部对齐,同ItemAlign.Start的效果是一致的

ItemAlign.Baseline

再来看下ItemAlign.Baseline,这个表示基于文本的baseline对齐,我们将上述例子中交叉轴的对齐方式改成ItemAlign.Baseline试试看
在这里插入图片描述
在这里插入图片描述

这里看起来好像跟ItemAlign.Center没啥区别,我们加点代码让效果明显一些
在这里插入图片描述

这里将每个Text的宽度加大一些,然后字体大小也设置成不一样,再来看看效果
在这里插入图片描述

现在效果就明显多了,ItemAlign.Baseline就是让元素在交叉轴方向上基于文本底部对齐

ItemAlign.Strech

再来看下ItemAlign.Strech,这个表示在交叉轴方向上拉伸填充,上面的代码再稍作修改
在这里插入图片描述

这里将交叉轴方向的对齐方式改成ItemAlign.Strech了,并且将第一个第三个元素的高度设置去掉,最终的效果是这样的
在这里插入图片描述

可以看到子组件不管是有没有设置高度,只要容器设置了ItemAlign.Strech,那么子组件在交叉轴方向上都是填充整个容器的

跟Row或者Column相似,除了可以在容器上设置子组件在交叉轴上的对齐方式之外,还可以单独在某个子组件上设置交叉轴上的对齐方式,同样也是用alignSelf函数,子组件的设置可以覆盖容器上的设置,下面是一个具体例子
在这里插入图片描述

我们在上面的例子中又新增了两个Text组件,容器上设置的交叉轴的对齐方式是居中,然后子组件里面除了最后一个,其他子组件都设置了与容器不一样的对齐方式,实际效果如下
在这里插入图片描述

可以看到只有第五个组件是按照容器的设置来对齐,其余的都是按照各自的设置来对齐

内容对齐

由于Flex组件支持子组件换行展示,所以在交叉轴方向上子组件数量也有可能超出一个,所以针对Flex的这个特性,在交叉轴方向也增加了同主轴一样的对齐方式,我们使用alignContent属性去设置,取值与主轴一样
在这里插入图片描述

下面是这六个取值与它们各自的呈现效果

FlexAlign.Start

在这里插入图片描述

FlexAlign.Center

在这里插入图片描述

FlexAlign.End

在这里插入图片描述

FlexAlign.SpaceBetween

在这里插入图片描述

FlexAlign.SpaceAround

在这里插入图片描述

FlexAlign.SpaceEvenly

在这里插入图片描述

注意这里的alignContent属性只有当wrap为FlexWrap.Wrap或者FlexWrap.WrapReverse才有效

自适应拉伸

这个也能体现出Flex“弹性”的特征,Flex里面的子组件可以使用几个属性来更改自身在主轴上的大小来适应父组件的大小,下面逐个介绍下

flexBasis

当子组件设置了这个属性,并且值为auto的时候,子组件的大小以自身的宽高为准,当flexBasis属性设置了某一个具体的值的时候子组件主轴上的大小以flexBasis设置的值为准,来看下面这段代码
在这里插入图片描述

这个例子里,在Flex里面也放了三个Text,Flex的主轴方向为水平方向,其中第一个Text设置了宽度为50,flexBasis设置为auto,第二个Text宽度为50,flexBasis设置成100,第三个Text没有设置宽度,flexBasis设置成80,我们来看下这三个Text最终呈现的效果如何
在这里插入图片描述

可以看到第一个Text由于flexBasis设置了auto,所以宽度还是按照设置的width的大小,第二个Text由于flexBasis设置了成100,所以最终宽度以flexBasis为准也是100,第三个Text虽然没有设置width,但由于flexBasis设置了成80,所以最终也是有80的宽度

flexGrow

当子组件设置了这个属性的时候,那就意味着要瓜分父组件里面剩余的空间了,瓜分的规则就是按照每个子组件设置的flexGrow的值来按比例瓜分
在这里插入图片描述

我们更改了一下上面那段代码,让三个色块的宽度都为50,并且第一个色块设置了flexGrow为1,第二个色块设置了flexGrow为4,我们看到由于它们所在的父组件宽度为300,所以第一,二个色块会瓜分剩余的150的空间,第三个色块由于没有设置flexGrow,将不参与瓜分,那么如何瓜分呢,就是按照各自设置的比例来,第一个色块除了自身宽度,还会加上150 * 1/5的宽度,第二个色块会加上150 * 4/5的宽度,为了验证我说的对不对,我们在上面这段代码中再加点代码
在这里插入图片描述

我们在这三个色块的下面同时再放上一个宽度为80的色块和一个宽度为170的色块,看看最终如果上下两边的前两个色块大小如果一样的话,那就说明我说的瓜分规则是对的,来看下效果
在这里插入图片描述

说明没有问题,我们再来看下一个属性

flexShrink

这个刚好与上面那个flexGrow的作用相反,flexGrow是当父组件有剩余空间时候,瓜分剩余空间,而flexShrink是当父组件空间不足的时候,将子组件按照比例压缩来适配父组件,同样来看下下面这段代码
在这里插入图片描述

在这段代码里面,我们有两个Flex组件分别套在一个Column里面,上面那个Flex宽度为300,里面有三个宽度分别为150的Text,由于这三个Text的宽度之和是大于父组件的宽度的,所以将前两个设置了flexShrink,让它们可以按照设置的比例压缩一下它们的宽度,第三个则没有设置,在第二个Flex里面,宽度也设置为300,里面放了两个Text,并且宽度都设置为150,这样做的目的是让第一个Flex里面的Text经过压缩后与第二个Flex里面的Text做下比较,看看最终的压缩效果如何,运行代码之后效果图如下
在这里插入图片描述

这里开始让我感到困惑的地方就来了,可能是刚看完flexGrow的原因,让我惯性思维的觉得只有设置了flexShrink的组件才会压缩自己,但我们明显可以从效果图中发现,在上面Flex中没有设置flexShrink的第三个Text,它的宽度也已经不再是150了,明显要比下面Flex中第二个Text要短,显然也是压缩了一定的长度,那么究竟第三个Text压缩了多少呢?前两个设置了flexShrink的意义又在哪里呢?当我觉得这有可能是ArkTS里面的一个bug的时候,忽然想到了Flex不是默认就可以让子组件在主轴方向上压缩尺寸吗?这个特性与我们现在讲的这个flexShrink是不是有某种关联呢?有没有可能Flex的子组件就默认自带了flexShrink属性,为了验证这一点,我打算做个实验,来看下面这段代码
在这里插入图片描述

依然还是上下两个宽度为300的Flex,里面子组件也都是宽度150的Text,唯一区别在于上面的Text都设置了flexShrink(1),下面的Text没有设置flexShrink,我们运行下看看上下Text压缩后的实际效果
在这里插入图片描述

可以看到完全一样,所以可以得出结论,Flex的子组件当Flex不能换行的时候,默认自带flexShrink(1)的属性,那么又引出来一个问题,Flex的子组件是如何通过flexShrink设置的值来计算实际压缩的大小呢?这个比较简单,我们先来计算下实际三个Text的宽度之和与父组件的宽度差,得到150的值,也就是总共压缩了150的宽度,然后除以所有组件设置的flexShrink之和,得到单位压缩长度50,由于这里每个Text都是设置的flexShrink(1),所以每个Text都减小了50的宽度,最终每个Text的宽度都变成了100,我们讲上述代码中第二个Flex中的Text的宽度都固定为100,与第一个Flex中的Text做个比较,看看我们的结论是否正确
在这里插入图片描述
在这里插入图片描述

完全一样,说明第一个Flex里面的Text最终压缩后的宽度就是100,现在我们再回到第一个例子中,第一个Text压缩比例是2,第二个Text压缩比例是3,第三个Text压缩比例是1,那么实际各自减去的宽度为2 * 150/6 = 50,3 * 150/6 = 75,1 * 150/6 = 25,我们在这个Flex的底下放上一个Row,里面添加三个宽度分别为100,75,125的Text组件对比下是否一样
在这里插入图片描述
在这里插入图片描述

好了,flexShrink如何压缩子组件的,现在也算是给整明白了。

总结

三个布局组件讲完了,篇幅还是蛮大的,其实看过鸿蒙开发者官方文档的人应该也都发现了,本篇文章知识点的讲解顺序就是按照官方文档来的,看了每个知识点,然后分别手写下对应的demo和自己的理解,后面其他布局组件都也会以这种方式讲解,枯燥是枯燥了点,但相比于仅仅是看文档来说,这才是最有效的掌握知识点的方法。
在这里插入图片描述

  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值