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:heightohos: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。我曾经因为这个被测试小姐姐骂了一顿,说按钮点不到……

注意: DirectionalLayout不支持子组件重叠。如果你需要让一个按钮浮在图片上面,那就得用DependentLayout或者StackLayout。

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 在指定组件上方
核心区别: DirectionalLayout是「排队」,DependentLayout是「定位」。排队简单但死板,定位灵活但复杂。我的建议是:简单的从上到下布局用DirectionalLayout,复杂的、需要精确对齐的用DependentLayout。

4.4 常用组件:Text、Button、Image

这三个组件,你写任何应用都离不开。咱们一个一个说。

4.4.1 Text:显示文字

Text组件就是用来显示文本的。属性不多,但有几个我特别常用:

  • text:显示的文本内容
  • text_size:字号,单位fp
  • text_color:颜色,支持十六进制或资源引用
  • text_alignment:对齐方式,比如 leftcenterright
  • max_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 就好了。所以,头像一般用 fitcrop,别用 stretch

4.5 知识体系总览

下面这张图,帮你理清本章的核心逻辑:

Page Ability 页面布局知识体系 XML编写UI布局 布局容器详解 常用组件使用 layout目录下创建.xml文件 根节点为布局容器 match_parent / match_content DirectionalLayout(线性布局) vertical / horizontal DependentLayout(相对布局) align_parent / below / above Text(文本显示) Button(按钮交互) Image(图片展示) scale_mode 缩放控制 核心:布局容器决定排列方式,组件负责展示和交互

好了,这一章的内容就这些。XML布局是基础,DirectionalLayout和DependentLayout是两大核心容器,Text、Button、Image是最常用的三个组件。把这些搞明白,你就能写出大部分页面的布局了。

下一章咱们聊聊Ability的生命周期,那个更有意思。


公众号:蓝海资料掘金营,微信deep3321