4. Page Ability的页面布局:使用XML编写UI布局、DirectionalLayout与DependentLayout详解、常用组件(Text、Button、Image)的使用
好,咱们今天来聊聊Page Ability的页面布局。说白了,就是你的应用长什么样,控件怎么摆。
我记得刚接触鸿蒙开发时,第一反应是——这布局方式跟Android有点像,但又不完全一样。嗯,这里要注意,鸿蒙有自己的布局体系,核心就是DirectionalLayout和DependentLayout。这两个家伙,你搞明白了,页面布局就通了八成。
4.1 用XML写UI布局,其实很简单
我个人习惯,所有UI都用XML来写。为什么?因为清晰、好维护。你想想看,如果把布局代码硬塞到Java或JS里,改个边距都得重新编译,多麻烦。
鸿蒙的XML布局文件放在 resources/base/layout 目录下。根节点通常是一个布局容器,里面再塞各种组件。
来看个最基础的例子:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<Text
ohos:id="$+id:title_text"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="Hello, HarmonyOS!"
ohos:text_size="28fp"
ohos:text_color="#FF0000"
ohos:top_margin="20vp"/>
<Button
ohos:id="$+id:click_btn"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="点我"
ohos:background_element="#007DFF"
ohos:text_color="#FFFFFF"
ohos:padding="12vp"
ohos:top_margin="16vp"/>
</DirectionalLayout>
看到没?每个组件都有 ohos:height 和 ohos:width。这两个属性值有两种:match_parent(填满父容器)和 match_content(根据内容自适应)。
vp(虚拟像素)而不是 px。vp会自动适配不同屏幕密度,我在项目里吃过亏,一开始用px,结果在平板和手机上显示效果差很多。
4.2 DirectionalLayout:线性布局,最常用的容器
DirectionalLayout,顾名思义,就是按方向排列子组件。要么横着排,要么竖着排。由 ohos:orientation 控制。
vertical:垂直排列,从上到下horizontal:水平排列,从左到右
我在项目中遇到过这样一个场景:做一个登录页面,上面是输入框,下面是按钮。用DirectionalLayout垂直排列,几行代码就搞定了。
<DirectionalLayout
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:padding="24vp">
<Text
ohos:height="match_content"
ohos:width="match_content"
ohos:text="用户名"
ohos:text_size="16fp"/>
<TextField
ohos:height="40vp"
ohos:width="match_parent"
ohos:hint="请输入用户名"
ohos:background_element="#F5F5F5"
ohos:top_margin="8vp"/>
<Text
ohos:height="match_content"
ohos:width="match_content"
ohos:text="密码"
ohos:text_size="16fp"
ohos:top_margin="16vp"/>
<TextField
ohos:height="40vp"
ohos:width="match_parent"
ohos:hint="请输入密码"
ohos:background_element="#F5F5F5"
ohos:top_margin="8vp"/>
<Button
ohos:height="44vp"
ohos:width="match_parent"
ohos:text="登录"
ohos:background_element="#007DFF"
ohos:text_color="#FFFFFF"
ohos:top_margin="24vp"/>
</DirectionalLayout>
这里有个坑,我提醒一下:DirectionalLayout里如果子组件太多,超出屏幕了怎么办?默认不会自动滚动。你需要在外层套一个 ScrollView。我曾经因为这个被测试小姐姐骂了一顿,说按钮点不到……
4.3 DependentLayout:相对布局,更灵活
DependentLayout,说白了就是「相对于谁」来定位。你可以让一个组件相对于父容器居中,也可以相对于另一个组件的左边、右边、上边或下边。
我个人觉得,DependentLayout比DirectionalLayout更强大,但也更容易搞晕。你想想看,每个组件都要指定跟谁对齐,布局文件一长,维护起来确实有点头疼。
来看个例子:一个卡片布局,标题在左上角,描述在标题下方,按钮在右下角。
<DependentLayout
ohos:height="160vp"
ohos:width="match_parent"
ohos:background_element="#FFFFFF"
ohos:padding="12vp">
<Text
ohos:id="$+id:card_title"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="鸿蒙开发入门"
ohos:text_size="18fp"
ohos:text_color="#333333"
ohos:align_parent_left="true"
ohos:align_parent_top="true"/>
<Text
ohos:id="$+id:card_desc"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="从零开始学习Ability组件开发"
ohos:text_size="14fp"
ohos:text_color="#666666"
ohos:align_left="$id:card_title"
ohos:below="$id:card_title"
ohos:top_margin="8vp"/>
<Button
ohos:id="$+id:card_btn"
ohos:height="36vp"
ohos:width="80vp"
ohos:text="查看详情"
ohos:text_size="12fp"
ohos:background_element="#007DFF"
ohos:text_color="#FFFFFF"
ohos:align_parent_right="true"
ohos:align_parent_bottom="true"/>
</DependentLayout>
关键属性说明:
| 属性 | 作用 |
|---|---|
align_parent_left |
靠父容器左边 |
align_parent_top |
靠父容器顶部 |
align_parent_right |
靠父容器右边 |
align_parent_bottom |
靠父容器底部 |
align_left |
与指定组件左对齐 |
align_right |
与指定组件右对齐 |
below |
在指定组件下方 |
above |
在指定组件上方 |
4.4 常用组件:Text、Button、Image
这三个组件,你写任何应用都离不开。咱们一个一个说。
4.4.1 Text:显示文字
Text组件就是用来显示文本的。属性不多,但有几个我特别常用:
text:显示的文本内容text_size:字号,单位fptext_color:颜色,支持十六进制或资源引用text_alignment:对齐方式,比如left、center、rightmax_text_lines:最大行数,超出显示省略号
举个例子:
<Text
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="这是一段很长的文本,如果超出两行就会显示省略号..."
ohos:text_size="16fp"
ohos:text_color="#333333"
ohos:max_text_lines="2"
ohos:text_alignment="center"/>
嗯,这里要注意,max_text_lines 配合 text_alignment 使用效果很好。我在做新闻列表时,标题最多显示两行,摘要最多显示三行,超出就加省略号,用户体验很好。
4.4.2 Button:按钮
Button继承自Text,所以Text的属性它都有。额外多了几个:
background_element:背景,可以是颜色或图片clickable:是否可点击,默认true
按钮的点击事件在代码里设置:
Button button = (Button) findComponentById(ResourceTable.Id_click_btn);
button.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
// 处理点击事件
System.out.println("按钮被点击了");
}
});
或者用Lambda表达式更简洁:
button.setClickedListener(component -> {
// 处理点击事件
System.out.println("按钮被点击了");
});
background_element 可以设置成shape资源,实现圆角、渐变等效果。我在项目里经常用,比用图片做背景灵活多了。
4.4.3 Image:显示图片
Image组件用来显示图片。图片资源放在 resources/base/media 目录下。
<Image
ohos:id="$+id:avatar_img"
ohos:height="80vp"
ohos:width="80vp"
ohos:image_src="$media:avatar"
ohos:scale_mode="stretch"/>
scale_mode 控制图片缩放方式:
| 模式 | 说明 |
|---|---|
stretch |
拉伸填满,可能变形 |
fit |
保持比例,完整显示 |
crop |
保持比例,裁剪多余部分 |
center |
居中显示,不缩放 |
我曾经在做一个用户头像时,用了 stretch 模式,结果圆形头像被拉成了椭圆……后来改成 fit 就好了。所以,头像一般用 fit 或 crop,别用 stretch。
4.5 知识体系总览
下面这张图,帮你理清本章的核心逻辑:
好了,这一章的内容就这些。XML布局是基础,DirectionalLayout和DependentLayout是两大核心容器,Text、Button、Image是最常用的三个组件。把这些搞明白,你就能写出大部分页面的布局了。
下一章咱们聊聊Ability的生命周期,那个更有意思。
公众号:蓝海资料掘金营,微信deep3321