![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=1738860677-IarZzrp3FXc3nbCkQHeMSd6eF1z0bm20-0-ea914058f5af763bb107c6deffa258d8)
图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=1738860677-iLNnTjPtioXoBMU6E6UESWqEvzcImL9w-0-62e5598a50dc72788e03bf94d392e7ba)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_89_1.jpg?sign=1738860677-uven4bDY42OIGbKPU8kchqXUwuRZ7MZW-0-7ffed29928f0bb0e7127816e87ddfcf0)
在上述代码中,顶部的<?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=1738860677-5Z1v2auuhWo8Sjkd1uqeXOrg5FM5qAqn-0-94efd6ccb5de0922dd46f706071fcefa)
图2-9 垂直排列
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_2.jpg?sign=1738860677-q0DdeHfnECwa5ILNSjNj8qG827uNz0yn-0-73c040aba60a84c26d892b15a2e5e145)
图2-10 水平排列
例如,将“按钮 1”的 ohos:width 属性值设置为 match_parent,其他按钮便没有空间显示。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_90_3.jpg?sign=1738860677-7QN4z5YJDxMtOQe4KLJt6NhAweP10Lh0-0-9c32e8e37683f28cfabcddb55f0c6f79)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_91_1.jpg?sign=1738860677-CY0Ocus2u7w5Rl4UYKuNOTZukGbWu6zZ-0-0decd6f06ba6978ae7648f1425d9e7d5)
在上面的代码中,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=1738860677-EHNDO9uDdp5OObf9e2HR48woI8km4ZPD-0-43b7279f6edfb3ed7aa5ea8e1db72eb0)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_1.jpg?sign=1738860677-1zh2L8omzvtRNAtcyNAMzJCGHajVZIwj-0-dac36e5f6b2acce6f4f3fabef0aa5e4b)
如图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=1738860677-ShuDoqykSlz43bloJDy5wl2f2kL7IGIV-0-e30ad71993f3208e941d9257b8b9d438)
图2-11 无剩余空间的显示效果
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_92_3.jpg?sign=1738860677-8z0xs8o2hfwWuCLjp0ogPwr2tXNJGFeF-0-5abb8c200143ddf8cae883ab47fa0462)
图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=1738860677-mmkIauOEG2eSQusc3sgK8bnXaLPXVyNy-0-a288500a14fd8201a9507503690cb266)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_94_1.jpg?sign=1738860677-BhluNX50rn9Y8hT6MO258XTWIXCzi29c-0-a1017d808c5fe64c16edb2e6acf71e8b)
设置布局的 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=1738860677-8mP1az0YBHu3IJUYiIsHs0GbYUwecSiq-0-f994fac9ce6c2585b2b017d360183ddf)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_1.jpg?sign=1738860677-LQf8uJ5zUwhlavnrYya1EcR9aREVH4OV-0-fb05afbdd7a3c2fb54abf168250c8c60)
图2-14为页面的预览效果图。从图2-14中可以看到,“按钮3”占据了右侧的空间,而“按钮1”和“按钮2”平分了左侧的剩余空间。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_2.jpg?sign=1738860677-UliijhlE9qkUoxxUQjKhGGEWChGR4jdz-0-1706f0effdf286e0c2b621ca694a191f)
图2-13 使用weight属性设置宽度
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_95_3.jpg?sign=1738860677-oDlCtLLo604CAfPf0ioSej0SfQtReou3-0-5acac1b75fa6a2587febb495fd8173a9)
图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=1738860677-7XL1XgIPJ5r7AlStzA3bIZi19ql2SdCS-0-0c5abfa00bbcec008dd1dd48458516e2)
在上述代码中,外层的 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=1738860677-Jj6gg3j1Aqcm43lm7HMf64sUUEW2S5zj-0-d1681039bf92c682ed0df7974262ad82)
图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=1738860677-mJoE3AmApbwEasS26kyeQMLmQV9HZeG1-0-9ed1ef732a66fd20783fd972251f41be)
但是当 DirectionalLayout的对齐方式与通过 ohos:layout_alignment属性配置的组件的排列方式一致时,对齐方式不会生效。我们看一下下面的例子。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_97_3.jpg?sign=1738860677-cfpfvn2cHdrxkU6BXXxUZBPBrcW5LH7g-0-d8c9fbb68133f7922f4c833a79c24ec4)
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_98_1.jpg?sign=1738860677-uQ2LLxkpq2U5pDgBw6q43PyMdX42WftQ-0-79c19f00504705107159e9c9ad3632a3)
可以看到,当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=1738860677-GV786nxFb88VcqBRHrWvJYGmVmU56EZT-0-a5c828e8a3fe2b79bc787f2dccaaf20b)
图2-17为页面的预览效果图。从图2-17中可以看到,“按钮1”回到了左上角的位置。ohos:layout_alignment的值并未起作用。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_2.jpg?sign=1738860677-noMUUWR4CUSQfHeiI3BXSkj8GOgrzEp2-0-cbc5563c6ba67514cb94fe6590d05d66)
图2-16 垂直居中
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_99_3.jpg?sign=1738860677-qYL4777AIlMDecxPi3MFPyINoAvLdddh-0-a499d24b51b94c5c283630b8e2802115)
图2-17 垂直居中不起作用
除了用XML文件的方式声明DirectionalLayout,还可以通过Java代码创建 DirectionalLayout。下面这段代码的效果和在<DirectionalLayout>中用 XML属性声明的效果是一样的。
![](https://epubservercos.yuewen.com/0FFABF/23020655009774306/epubprivate/OEBPS/Images/42868_100_1.jpg?sign=1738860677-v2RW7sC4nvDrkoW6G7YQLESpEryZuTaN-0-bc236a4aa1e7a3c3e379fcf31b8b4f8f)