![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=1739355508-rSCG3JqQN4a4Fv64AQKmlxPgC4B2zjXP-0-89a38b5c27df30ac825024ac3968ce17)
图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=1739355508-1XMr3CS18qXjwfCOm3fhAtpvdRf6l8DE-0-6a741d8ea5ec749b3f106be7db2273c8)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_89_1.jpg?sign=1739355508-nm0rDGk8fG3RtqjEA28ZKwX8tjmTBuD5-0-8b02d3f1cd418249e3b255b423883491)
在上述代码中,顶部的<?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=1739355508-QWo7X2HsQZ1ayEsPXJEdrWoergxFR4yu-0-da0b248accc6ecb2d881d0bcd61fb42e)
图2-9 垂直排列
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_2.jpg?sign=1739355508-AJ32R4EGIW5dOUfFNAb2o6B6zWyyHUxQ-0-4f94c0b3dc06bbd1958728f064b6d844)
图2-10 水平排列
例如,将“按钮 1”的 ohos:width 属性值设置为 match_parent,其他按钮便没有空间显示。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_3.jpg?sign=1739355508-oirFLdNyEXooGi6otRKgABCPeO12j9zX-0-09ba34f9edd6b379488420a9b96bf6b3)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_91_1.jpg?sign=1739355508-DT9NAO23YmQkLve0QcdZlAqTH471LUEr-0-d043418e694063fe3907707d854a7841)
在上面的代码中,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=1739355508-QPHdm2Wcc5BDd323tqZaOQC1aP4202Vr-0-16ed997ffbf86ac22fce4a240f460fd6)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_1.jpg?sign=1739355508-gHiHtydZbXsaPcDlfwwtTyhtdZYcHK7h-0-d8975855a91a01bef33b8bb07feb05c7)
如图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=1739355508-xNE48Q0MZPZaHUs37ZyVASFHACkQWxax-0-f418a7fa60747adb3cd1a0be91f68835)
图2-11 无剩余空间的显示效果
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_3.jpg?sign=1739355508-itubjfTIBLLj2NzVkCGO0lu3QKScnWy5-0-fdfc97c29620afc3ccf8dda6a4aae98a)
图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=1739355508-1yFqMVlpcqenJxa6IxbQNn5qvQ2atigu-0-03c707c5fe11ac3b75ca36d5472a5d03)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_94_1.jpg?sign=1739355508-jWIA5e41fzn1gO8ESn2V4MnksSixYhtl-0-d1deb64874c30cf8dc06f734fc2818a7)
设置布局的 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=1739355508-Wro6xdWdVHlA1xdM1AMKXc102FG3jSBC-0-6c9ed068449738fc2c77d3bc69b3863f)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_1.jpg?sign=1739355508-NJQ8EOxwcXHEbJvnN22izEso5LllGev4-0-8c68ed33f82d1fa988e74d1483b0d0b5)
图2-14为页面的预览效果图。从图2-14中可以看到,“按钮3”占据了右侧的空间,而“按钮1”和“按钮2”平分了左侧的剩余空间。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_2.jpg?sign=1739355508-NkSCoTswYzy3QAVx04s1CL2su9mYr5XR-0-5ad6075c7b6feb2c9592000aed4baef8)
图2-13 使用weight属性设置宽度
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_3.jpg?sign=1739355508-IAihYcRVqlm6PdkVBn6mCEOmyYVIBKkW-0-0248f40ad6efef8d25a5ce1ed052b9cb)
图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=1739355508-QNrlvd8Ez3LQBiDbGc3FrTBfpGXoA725-0-3d0c2d304b52c2b941605ec6425d708c)
在上述代码中,外层的 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=1739355508-tTrgJdLkvEbYS7R1paCsDKtyH6AhOBnD-0-99e7836e14a8ce3a7000d9c04b137527)
图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=1739355508-OBZsJr350Cyi9OYZF6D83Sg3sFvs0EQe-0-2f0484a4efa0cc688cc0596d37ce3310)
但是当 DirectionalLayout的对齐方式与通过 ohos:layout_alignment属性配置的组件的排列方式一致时,对齐方式不会生效。我们看一下下面的例子。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_97_3.jpg?sign=1739355508-ZGRTc1ZKClM1cfCMtL1MPk7EJ6EdnAZq-0-b741be98ea386c3c5d3a85b29be4ea22)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_98_1.jpg?sign=1739355508-DO6lX6nerBwNGqW7Jn4c5xxnvMJTczdT-0-41a58d6f6cf1b59f882557d9603a834f)
可以看到,当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=1739355508-U7jOxLv2VsWeQaU03JxquYwsQvgggNQr-0-c40d134539bfb00d863f5f3072ffec4b)
图2-17为页面的预览效果图。从图2-17中可以看到,“按钮1”回到了左上角的位置。ohos:layout_alignment的值并未起作用。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_2.jpg?sign=1739355508-WF7mloQCWU4nbDOwGSZpIc1Y6xzy2iu2-0-fd2e7c423301fc04d63c9398cdbf7e79)
图2-16 垂直居中
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_3.jpg?sign=1739355508-KdtCWOzRyTnzkRxPsw2RjI3jA8QoEXjL-0-7fb52c03a34f89f878f6d6cb5c6bbdff)
图2-17 垂直居中不起作用
除了用XML文件的方式声明DirectionalLayout,还可以通过Java代码创建 DirectionalLayout。下面这段代码的效果和在<DirectionalLayout>中用 XML属性声明的效果是一样的。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_100_1.jpg?sign=1739355508-tYfBlpbEaljPGtcrNqIdDOVorfsxJXHE-0-06617ce2a353ba8075d4748859927dbf)