![Hello HarmonyOS!:鸿蒙应用开发从入门到精通](https://wfqqreader-1252317822.image.myqcloud.com/cover/437/43738437/b_43738437.jpg)
2.2.1 DirectionalLayout
DirectionalLayout 是一种可以声明子组件排列方向的布局,既是最基础,也是最重要的一种布局,应用场景很广泛,用于将组件按照水平[如图2-8(a)所示]或垂直[如图2-8(b)所示]两种方向排列。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_88_1.jpg?sign=1739543644-9Lga96wUBPoxbHEFI9uxBjlCFGUPZMux-0-5c8c06ce756d7d07dff60bba04159585)
图2-8 DirectionalLayout示意图
DirectionalLayout 通过 ohos:orientation 属性控制组件的排列方向。ohos:orientation有两个属性值,分别是horizontal和vertical。其中,horizontal表示水平显示,vertical表示垂直显示,而且DirectionalLayout默认采用垂直的方式进行排列。接下来,通过配置ohos:orientation属性来实现三个按钮的垂直排列。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_88_2.jpg?sign=1739543644-uwtUi5tnNPCZFywUm18xD0DNILnx2K9Z-0-f6b6ca1d89fcba347239f418af86f40c)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_89_1.jpg?sign=1739543644-rlurZTiI2DjtIegImpuCI7cSAFRL2V9I-0-b0915e29ac1ac1754e15326f7b4fb1b9)
在上述代码中,顶部的<?xml version="1.0"encoding="utf-8"?>声明了XML文件的版本和字符集。
最 外 层 标 签 为 <DirectionalLayout>,表 示 这 里 使 用 的 布 局 是DirectionalLayout。布局的ohos:orientation属性的取值设置为vertical,在布局中包含了三个按钮,这三个按钮会按照垂直方向排列,页面的预览效果如图2-9所示。
在按钮中,通过ohos:text属性设置了按钮显示的内容,通过ohos:text_size指定了显示内容的字号。在 HarmonyOS 中,字号可以使用三种单位设置,分别为px(像素)、vp(虚拟像素)、fp(字体像素)。其中:px为屏幕像素;vp为虚拟像素,它的大小和屏幕密度有关,它使组件尺寸在不同像素密度的设备上具有一致的视觉感受;fp 默认大小和 vp 相同,只是在设置字号后,会乘以对应的系数来计算实际显示大小。
若将 ohos:orientation 的属性值设置为 horizontal,则三个按钮会按照水平方向进行排列,页面的预览效果如图2-10所示。
这里的按钮设置的宽度ohos:width和高度ohos:height都是match_content,意味着组件的宽度和高度会正好包裹其所包含的内容。宽度和高度都还有另一个属性值,叫 match_parent,意思是与父级容器的长度或宽度保持一致。当ohos:orientation的属性值为horizontal时,如果将上面“按钮1”的宽度设置为match_parent,那么“按钮1”的宽度就将整个屏幕占满,由于屏幕已经没有剩余空间,其余按钮就会从屏幕右侧被挤出。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_1.jpg?sign=1739543644-3bAOytQMEnimU0cmiG7YSijKPa83T7OI-0-97d6f86750a444bca88158fddea8f792)
图2-9 垂直排列
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_2.jpg?sign=1739543644-9wMN6QeYEzCfA8MDJ77k7RS2O0emZ9JP-0-cd3115e3c8c4625b5b97f009e0505652)
图2-10 水平排列
例如,将“按钮 1”的 ohos:width 属性值设置为 match_parent,其他按钮便没有空间显示。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_3.jpg?sign=1739543644-ql5x1G3DLR8yR721T3na5iDDfAZ4iUp3-0-0cfedc2d9810ef5ba1ca46ee17feefd0)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_91_1.jpg?sign=1739543644-N1BhUUTFqH0uObgbmG4pvlSLldGQc5go-0-429483b1ec09064231125bbba4be2649)
在上面的代码中,DirectionalLayout的排列方式设置为水平,这时将“按钮1”的ohos:width属性值设置为match_parent,则屏幕上只会显示“按钮1”,其余两个按钮均从屏幕右侧被挤出,从而无法显示,页面的预览效果如图2-11所示。
同理,如果 ohos:orientation 的属性值为 vertical,那么组件的高度就不能设置为match_parent,否则会影响其他组件的显示效果。
DirectionalLayout是按照布局中组件摆放的顺序依次分配空间的,先给“按钮1”设置宽度为 match_content,这时系统已经为“按钮 1”分配了空间,然后将“按钮 2”的宽度设置为 match_parent,最后“按钮 3”的宽度依然为match_content,代码如下。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_91_2.jpg?sign=1739543644-FIgnACv00H3n5gW2BZQe2y4GmykCyDYv-0-5d713c822468d5a72418ac6274e1b461)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_1.jpg?sign=1739543644-n29kPUcFzxWDeK1kNnMwh8jslvBKRNfE-0-284f468f2ef459d553e6632583ddcfd6)
如图2-12所示,屏幕上只显示了“按钮1”和“按钮2”,且“按钮2”的宽度为match_parent,它占据了除去“按钮1”以外的所有右侧的水平空间,“按钮3”就没有多余的位置可以摆放,被挤出屏幕。在本例中,DirectionalLayout被设置为水平方向,那么,match_parent 属性计算的是水平方向剩余可用空间的大小,而非使用水平方向的所有空间来计算组件尺寸。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_2.jpg?sign=1739543644-a8joqfaMmHdE7VK2UCoCstKU8cHpLxxt-0-16a4bcc41bb44d895521d5490db0a1c6)
图2-11 无剩余空间的显示效果
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_3.jpg?sign=1739543644-q156vKYRBT74xOX6euAHObSJO5e0PFxd-0-19c4a07330a8645c94d573caf2040a57)
图2-12 “按钮2”挤占剩余空间
如果都使用match_content来指定组件的宽度,那么在排列完三个按钮后,屏幕右侧还有大片的空白位置,UI显得不美观。DirectionalLayout除了可以规定组件的排列方向,还可以通过 ohos:weight 空间权重属性来设置组件所占据的空间大小。这个属性是按比例计算组件在布局中所占空间的,可以用作对不同分辨率屏幕的适配。下面通过给 Button 设置 weight 值来设置三个按钮的大小,以水平排列布局为例编写代码。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_93_1.jpg?sign=1739543644-sRNfSsSjg67h7OllBdIc5Lh2zJFtGPaU-0-a3727347da7e462ff11ac67b4c028067)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_94_1.jpg?sign=1739543644-nwVTZMHrjvZqbFYZh1jcRYNJAq6KKBWg-0-c1568d1f3ac2137087d52224e62d1a8c)
设置布局的 ohos:orientation属性值为 horizontal,三个按钮的 ohos:weight属性值都为 1,则按钮会把屏幕空间三等分进行排列。此时,组件的宽度不再由ohos:width来决定,这个时候可以将组件的ohos:width属性值设置为0。
在计算组件宽度时,系统会把所有组件指定的ohos:weight相加得到总的权重值,然后计算每个组件的 weight 占总权重值的比例,按照比例去分配组件在DirectionalLayout中的可用空间。上面三个按钮的weight都为1,总权重值为3,所以每个组件的宽度都是1/3屏幕宽度。页面的预览效果如图2-13所示。
如果为“按钮 3”设置了具体的宽度,那么“按钮 1”和“按钮 2”使用ohos:weight来设置宽度又会如何呢?我们看一下下面的例子。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_94_2.jpg?sign=1739543644-vJT3uEf0ChNpU9BeSnnTilsd6BNsBqBH-0-45edf25b47f5ac896f1f59e657b12ded)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_1.jpg?sign=1739543644-5T7ue5zHueZaIsYgxjtEWx5x471qR2Pf-0-d71d6feb451d6954e238efb009243f0d)
图2-14为页面的预览效果图。从图2-14中可以看到,“按钮3”占据了右侧的空间,而“按钮1”和“按钮2”平分了左侧的剩余空间。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_2.jpg?sign=1739543644-90WbvckMwolDXEMMvcAkaNPRTZ5KoR1t-0-e041dbb666de8dad9bccf0f0884820b2)
图2-13 使用weight属性设置宽度
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_3.jpg?sign=1739543644-roaB4iGimgaHZxd5BoVNaugActi6tyU0-0-9344db664f409c4d11a65eaf2747431a)
图2-14 weight与指定宽度混用
DirectionalLayout还有一个特有属性,叫ohos:total_weight。它可以指定布局的总权重值totalWeight。这时,用于计算DirectionalLayout中组件尺寸的权重值不再由所有子组件的 weight 加和得到。每个组件所占用的空间都由计算得到。其中,式子的分子中使用的是屏幕可用宽(高)度,也就是说,在使用weight按比例来计算组件宽(高)度时,使用的不是屏幕在宽或高方向的总尺寸,而是使用减去已被其他组件占用后的屏幕剩余空间。我们看一下下面的例子。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_96_1.jpg?sign=1739543644-7bCMpkYQXHKfrAQDFmS3MwmlbLxYem15-0-75e7a7d7c7ba9da60b033ee38711b810)
在上述代码中,外层的 DirectionalLayout增加了 ohos:total_weight属性,取值为5。布局中包含“按钮1”“按钮2”“按钮3”三个按钮,其中“按钮1”“按钮 2”的 ohos:weight 设置为2,“按钮 3”指定具体的宽度为150vp。页面的预览效果如图2-15所示。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_97_1.jpg?sign=1739543644-BxhXjWdZb96OrFZLaI8mibtLrun975Wn-0-919acfcfba3e26c33e6950d2255fc3c9)
图2-15 使用total_weight和weight设置组件宽度
系统首先为“按钮 3”分配空间,“按钮1”和“按钮2”的宽度各为剩余空间的2/5,在“按钮 3”右侧有剩余的空白区域,空白区域为剩余空间的1/5。
在DirectionalLayout中,组件 的 位 置 还 可 以 通 过ohos:layout_alignment 属性来指定。组件可以通过这个属性来决定自己在DirectionalLayout中的对齐方式。layout_alignment属性值见表2-1。
表2-1 layout_alignment属性值
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_97_2.jpg?sign=1739543644-vAEuaH8EOB2zoqT4ZUEbArOlQcZVxiG6-0-b4739dbeb17d8fa1eb2570b7d70e5596)
但是当 DirectionalLayout的对齐方式与通过 ohos:layout_alignment属性配置的组件的排列方式一致时,对齐方式不会生效。我们看一下下面的例子。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_97_3.jpg?sign=1739543644-Aug99wgNlyjCr47pdb1OEd5ZaW9OGkjw-0-1d558f389bbbc5ea0c01de14f01ba8bc)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_98_1.jpg?sign=1739543644-aHBWnSHQ3RMD5w9I5UGwGdZBTwvEYtGk-0-71069fa5d56a5a8dfac257836ba1a5ad)
可以看到,当DirectionalLayout的方向设置为水平时,“按钮1”的位置可以通过 layout_alignment 属性设置为垂直居中,“按钮 2”的位置为“top”,在屏幕顶部,“按钮 3”的位置为“bottom”,在屏幕底部,页面的预览效果如图2-16所示。
但 如 果 设 置 ohos:layout_alignment 为 “horizontal_center”,由 于ohos:orientation的属性值为horizontal,而ohos:layout_alignment的对齐方式也指定的是水平方向,那么这个属性不会起作用,因为下一个组件要水平排列,水平方向就不再允许组件通过layout_alignment调整位置。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_1.jpg?sign=1739543644-JowjOfbmRl2c13tsF5GJU7TYVkFP7SlB-0-8152193d2d92b42f8bdfa252200943d2)
图2-17为页面的预览效果图。从图2-17中可以看到,“按钮1”回到了左上角的位置。ohos:layout_alignment的值并未起作用。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_2.jpg?sign=1739543644-Hv083YmInfh2YqYGLJJq21YsQpBrrfnk-0-eebc2ece30b61cf7daed23ff7cd932c8)
图2-16 垂直居中
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_3.jpg?sign=1739543644-13UrVGDwSxeWz8es3naXb5Kd1UtripMS-0-9de92ffb67183c7aaf225c5bb7ddd22f)
图2-17 垂直居中不起作用
除了用XML文件的方式声明DirectionalLayout,还可以通过Java代码创建 DirectionalLayout。下面这段代码的效果和在<DirectionalLayout>中用 XML属性声明的效果是一样的。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_100_1.jpg?sign=1739543644-P2eY44Rn9greM0GemThncZeVB7ssNx0H-0-387566889c187433b5c91fd0deb4ce3f)