2.2.1 DirectionalLayout
DirectionalLayout 是一种可以声明子组件排列方向的布局,既是最基础,也是最重要的一种布局,应用场景很广泛,用于将组件按照水平[如图2-8(a)所示]或垂直[如图2-8(b)所示]两种方向排列。
图2-8 DirectionalLayout示意图
DirectionalLayout 通过 ohos:orientation 属性控制组件的排列方向。ohos:orientation有两个属性值,分别是horizontal和vertical。其中,horizontal表示水平显示,vertical表示垂直显示,而且DirectionalLayout默认采用垂直的方式进行排列。接下来,通过配置ohos:orientation属性来实现三个按钮的垂直排列。
在上述代码中,顶部的<?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”的宽度就将整个屏幕占满,由于屏幕已经没有剩余空间,其余按钮就会从屏幕右侧被挤出。
图2-9 垂直排列
图2-10 水平排列
例如,将“按钮 1”的 ohos:width 属性值设置为 match_parent,其他按钮便没有空间显示。
在上面的代码中,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,代码如下。
如图2-12所示,屏幕上只显示了“按钮1”和“按钮2”,且“按钮2”的宽度为match_parent,它占据了除去“按钮1”以外的所有右侧的水平空间,“按钮3”就没有多余的位置可以摆放,被挤出屏幕。在本例中,DirectionalLayout被设置为水平方向,那么,match_parent 属性计算的是水平方向剩余可用空间的大小,而非使用水平方向的所有空间来计算组件尺寸。
图2-11 无剩余空间的显示效果
图2-12 “按钮2”挤占剩余空间
如果都使用match_content来指定组件的宽度,那么在排列完三个按钮后,屏幕右侧还有大片的空白位置,UI显得不美观。DirectionalLayout除了可以规定组件的排列方向,还可以通过 ohos:weight 空间权重属性来设置组件所占据的空间大小。这个属性是按比例计算组件在布局中所占空间的,可以用作对不同分辨率屏幕的适配。下面通过给 Button 设置 weight 值来设置三个按钮的大小,以水平排列布局为例编写代码。
设置布局的 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来设置宽度又会如何呢?我们看一下下面的例子。
图2-14为页面的预览效果图。从图2-14中可以看到,“按钮3”占据了右侧的空间,而“按钮1”和“按钮2”平分了左侧的剩余空间。
图2-13 使用weight属性设置宽度
图2-14 weight与指定宽度混用
DirectionalLayout还有一个特有属性,叫ohos:total_weight。它可以指定布局的总权重值totalWeight。这时,用于计算DirectionalLayout中组件尺寸的权重值不再由所有子组件的 weight 加和得到。每个组件所占用的空间都由计算得到。其中,式子的分子中使用的是屏幕可用宽(高)度,也就是说,在使用weight按比例来计算组件宽(高)度时,使用的不是屏幕在宽或高方向的总尺寸,而是使用减去已被其他组件占用后的屏幕剩余空间。我们看一下下面的例子。
在上述代码中,外层的 DirectionalLayout增加了 ohos:total_weight属性,取值为5。布局中包含“按钮1”“按钮2”“按钮3”三个按钮,其中“按钮1”“按钮 2”的 ohos:weight 设置为2,“按钮 3”指定具体的宽度为150vp。页面的预览效果如图2-15所示。
图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属性值
但是当 DirectionalLayout的对齐方式与通过 ohos:layout_alignment属性配置的组件的排列方式一致时,对齐方式不会生效。我们看一下下面的例子。
可以看到,当DirectionalLayout的方向设置为水平时,“按钮1”的位置可以通过 layout_alignment 属性设置为垂直居中,“按钮 2”的位置为“top”,在屏幕顶部,“按钮 3”的位置为“bottom”,在屏幕底部,页面的预览效果如图2-16所示。
但 如 果 设 置 ohos:layout_alignment 为 “horizontal_center”,由 于ohos:orientation的属性值为horizontal,而ohos:layout_alignment的对齐方式也指定的是水平方向,那么这个属性不会起作用,因为下一个组件要水平排列,水平方向就不再允许组件通过layout_alignment调整位置。
图2-17为页面的预览效果图。从图2-17中可以看到,“按钮1”回到了左上角的位置。ohos:layout_alignment的值并未起作用。
图2-16 垂直居中
图2-17 垂直居中不起作用
除了用XML文件的方式声明DirectionalLayout,还可以通过Java代码创建 DirectionalLayout。下面这段代码的效果和在<DirectionalLayout>中用 XML属性声明的效果是一样的。