鸿蒙开发之相对布局、倒计时TextTimer示例代码

好的,鸿蒙(HarmonyOS)开发中,相对布局和倒计时组件是非常常用的功能。下面我将为你提供详细的讲解和示例代码。

图片[1]_鸿蒙开发之相对布局、倒计时TextTimer示例代码_知途无界

1. 相对布局 (DependentLayout)

相对布局是一种通过指定子组件之间的相对位置关系来排列组件的布局方式。它非常灵活,可以实现复杂的界面结构。

核心概念

  • 锚点​:你可以将子组件的边缘(左、右、上、下、水平居中、垂直居中)锚定到父容器或其他子组件的相应边缘上。
  • 对齐方式​:可以设置组件相对于其父容器或其他组件的对齐方式。
  • 权重​:类似于线性布局的 weight,在相对布局中,可以通过设置宽度/高度为 0 并配合 layoutWeight 来实现按比例分配剩余空间。

常用 XML 属性

  • ​**alignRules**: 这是相对布局最核心的属性,它是一个数组,用于定义组件的所有相对规则。在 XML 中,我们通过一系列以 ohos:id 为键的子属性来设置。
    • left_of: 位于某个组件的左边。
    • right_of: 位于某个组件的右边。
    • top_of: 位于某个组件的上边。
    • bottom_of: 位于某个组件的下边。
    • left_of_id: 与 left_of 类似,但指定的是 id。
    • right_of_id: 同上。
    • top_of_id: 同上。
    • bottom_of_id: 同上。
    • align_left: 左边缘与某个组件的左边缘对齐。
    • align_right: 右边缘对齐。
    • align_top: 上边缘对齐。
    • align_bottom: 下边缘对齐。
    • align_center: 水平居中对齐。
    • align_parent_left: 左边缘与父容器左边缘对齐。
    • align_parent_right: 右边缘与父容器右边缘对齐。
    • align_parent_top: 上边缘与父容器上边缘对齐。
    • align_parent_bottom: 下边缘与父容器下边缘对齐。
    • center_in_parent: 在父容器中居中。
    • horizontal_center: 在父容器中水平居中。
    • vertical_center: 在父容器中垂直居中。

示例代码 (XML)

下面是一个使用相对布局实现的用户信息卡片示例,包含一个头像、姓名、简介和一个关注按钮。

1. 首先在 src/main/resources/base/layout/ability_main.xml 中定义布局:​

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_content"
    ohos:background_element="#FFFFFF"
    ohos:padding="16vp">

    <!-- 1. 定义各个组件的ID -->
    <Image
        ohos:id="$+id:img_avatar"
        ohos:width="80vp"
        ohos:height="80vp"
        ohos:scale_mode="zoom_center"
        ohos:background_element="#E0E0E0"
        ohos:margin="8vp"
        ohos:align_parent_top="true"
        ohos:align_parent_left="true"
        ohos:image_src="$media:icon_avatar"/> <!-- 假设你有一张名为 icon_avatar.png 的图片 -->

    <Text
        ohos:id="$+id:tv_name"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="鸿蒙开发者"
        ohos:text_size="20fp"
        ohos:text_color="#000000"
        ohos:text_weight="700"
        ohos:left_of="$id:btn_follow"
        ohos:right_margin="16vp"
        ohos:align_top_to_align_top_of="$id:img_avatar"
        ohos:bottom_of="$id:img_avatar"
        ohos:align_parent_right="false"
        ohos:align_parent_end="false"
        />

    <Text
        ohos:id="$+id:tv_description"
        ohos:width="match_parent"
        ohos:height="match_content"
        ohos:text="致力于分享 HarmonyOS 开发知识和实践经验。"
        ohos:text_size="14fp"
        ohos:text_color="#666666"
        ohos:top_margin="8vp"
        ohos:left_of="$id:btn_follow"
        ohos:right_margin="16vp"
        ohos:align_left_to_left_of="$id:tv_name"
        ohos:top_to_bottom_of="$id:tv_name"
        ohos:multiple_lines="true"
        ohos:max_text_lines="2"/>

    <Button
        ohos:id="$+id:btn_follow"
        ohos:width="80vp"
        ohos:height="40vp"
        ohos:text="关注"
        ohos:text_size="14fp"
        ohos:background_element="$graphic:button_background" <!-- 假设有一个 button_background.xml 的图形资源 -->
        ohos:text_color="#FFFFFF"
        ohos:right_margin="8vp"
        ohos:align_parent_right="true"
        ohos:align_parent_top="true"
        ohos:align_parent_bottom="false"
        ohos:center_vertical="true"/>

    <!-- 分割线 -->
    <Component
        ohos:id="$+id:component_divider"
        ohos:width="match_parent"
        ohos:height="1vp"
        ohos:background_element="#EEEEEE"
        ohos:top_margin="16vp"
        ohos:align_left_parent="true"
        ohos:align_right_parent="true"
        ohos:top_to_bottom_of="$id:tv_description"/>

</DependentLayout>

2. 图形资源文件 (可选,用于美化按钮)​

src/main/resources/base/graphic/button_background.xml 创建按钮背景:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:shape="rectangle">
    <corners
        ohos:radius="20vp"/>
    <solid
        ohos:color="#007DFF"/>
</shape>

3. Java/Kotlin 代码中加载布局 (通常在 AbilitySlice 的 onStart 方法中)​

// Java
@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);
    // 如果需要,可以在这里通过 findComponentById 获取组件并添加事件监听
    Button followBtn = (Button) findComponentById(ResourceTable.Id_btn_follow);
    if (followBtn != null) {
        followBtn.setClickedListener(component -> {
            // 处理关注按钮点击事件
        });
    }
}

2. 倒计时组件 (TextTimer)

TextTimer 是鸿蒙系统提供的专门用于倒计时的组件,它可以自动更新显示的倒计时文本。

核心方法与属性

  • ​**setBaseTime(long baseTime)**: 设置倒计时的基准时间(起始时间)。通常使用 SystemClock.elapsedRealtime() 加上一个偏移量(毫秒)来设置未来的结束时间,或者设置一个过去的时间来实现正计时。
  • ​**setCountDown(boolean isCountDown)**: 设置是否为倒计时模式。true 为倒计时(从 baseTime 减少到 0),false 为正计时(从 0 增加到 baseTime)。
  • ​**setFormat(String format)**: 设置倒计时显示格式。格式字符串中可以包含特定的占位符,系统会自动替换。
    • %1$d: 表示总秒数。
    • %2$d: 表示剩余的小时数。
    • %3$d: 表示剩余的分钟数。
    • %4$d: 表示剩余的秒数。
    • %5$d: 表示剩余的毫秒数(如果格式中包含 S)。
  • ​**start()**: 开始倒计时。
  • ​**stop()**: 停止倒计时。
  • ​**setOnTimerTickListener(TextTimer.OnTimerTickListener listener)**: 设置倒计时监听器,可以监听每一次时间的变化。

示例代码 (XML + Java)

下面是一个简单的验证码倒计时按钮示例。

1. XML 布局 (在之前的布局文件中添加一个 TextTimer)​

在你的布局文件(如 ability_main.xml)的合适位置添加 TextTimer

<!-- 在 Component 下方继续添加 -->
<TextTimer
    ohos:id="$+id:text_timer_countdown"
    ohos:width="match_content"
    ohos:height="match_content"
    ohos:text_size="16fp"
    ohos:text_color="#FF0000"
    ohos:top_margin="20vp"
    ohos:center_horizontal="true"
    ohos:top_to_bottom_of="$id:component_divider"
    ohos:format="重新发送(%2$02d:%3$02d)"/> <!-- 格式:显示 时:分,不足两位补零 -->

2. Java 代码控制倒计时逻辑

在 AbilitySlice 中获取 TextTimer 并设置其逻辑。

// Java
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.miscservices.time.SystemClock;

public class MainAbilitySlice extends AbilitySlice {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MyTag");
    private static final long COUNT_DOWN_TIME_MS = 60 * 1000; // 60秒倒计时
    private TextTimer textTimer;
    private boolean isCounting = false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        initComponents();
    }

    private void initComponents() {
        // 获取 TextTimer 组件
        textTimer = (TextTimer) findComponentById(ResourceTable.Id_text_timer_countdown);
        Button followBtn = (Button) findComponentById(ResourceTable.Id_btn_follow);

        if (textTimer != null) {
            // 设置倒计时格式,例如:"剩余 01:30"
            textTimer.setFormat("重新发送(%2$02d:%3$02d)");
            // 设置计时器监听器(可选)
            textTimer.setOnTimerTickListener(new TextTimer.OnTimerTickListener() {
                @Override
                public void onTickEvent(long l) {
                    // l 是自启动以来的累计时间(如果是正计时)或剩余时间(如果是倒计时)
                    // 这里我们不需要用它来更新UI,因为 setFormat 已经帮我们做了
                    HiLog.info(LABEL, "Tick event, time: %{public}d ms", l);
                }
            });
        }

        if (followBtn != null) {
            followBtn.setClickedListener(component -> {
                if (!isCounting) {
                    startCountdown();
                }
            });
        }
    }

    private void startCountdown() {
        if (textTimer == null) {
            return;
        }

        // 设置为倒计时模式
        textTimer.setCountDown(true);

        // 计算基准时间:当前时间 + 倒计时时长
        long baseTime = SystemClock.elapsedRealtime() + COUNT_DOWN_TIME_MS;
        textTimer.setBaseTime(baseTime);

        // 开始计时
        textTimer.start();
        isCounting = true;

        // 可以在这里禁用发送按钮,防止重复点击
        Button followBtn = (Button) findComponentById(ResourceTable.Id_btn_follow);
        if (followBtn != null) {
            followBtn.setText("发送中...");
            followBtn.setClickable(false);
        }

        // 使用一个 Handler 在倒计时结束后重置按钮状态
        // 注意:TextTimer 本身没有提供结束监听器,所以需要自己计算时间或用其他方式
        // 这里我们用一个简单的方法:在最后一次 onTickEvent 时判断
        // 更优雅的方式是使用 Timer 或 Handler 自己实现倒计时逻辑,以获得更好的控制。

        // 简单实现:假设我们监听最后一次 tick
        // 当剩余时间为 0 时,TextTimer 会自动停止并显示 00:00。
        // 我们可以轮询检查,但最好的方式是使用自己的逻辑。
        // 下面是一个使用 Handler 的示例:

        getUITaskDispatcher().delayDispatch(() -> {
            // 60秒后执行
            isCounting = false;
            if (followBtn != null) {
                followBtn.setText("获取验证码");
                followBtn.setClickable(true);
            }
        }, COUNT_DOWN_TIME_MS);
    }

    @Override
    protected void onActive() {
        super.onActive();
    }

    @Override
    protected void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}

重要提示​:TextTimersetOnTimerTickListener 并不能直接告诉你倒计时何时结束。上面的示例中使用了 getUITaskDispatcher().delayDispatch 来在指定时间后重置按钮,这是一种变通方法。​在生产环境中,更推荐的做法是:​

  1. 使用 HandlerTimer 自己实现倒计时逻辑,这样可以精确控制开始和结束事件。
  2. 或者,在 OnTimerTickListener 中检查 l 参数(剩余时间),当它等于 0 时,执行结束操作。但由于系统调度,l 可能不会精确地变为 0,所以需要在接近 0 时(如小于 1000ms)就触发结束逻辑。

总结

  • 相对布局 (DependentLayout)​​ 通过 alignRules 提供了强大的灵活性,适合构建复杂和非线性的 UI 结构。理解各种锚点和对齐属性的含义是关键。
  • 倒计时 (TextTimer)​​ 是一个便捷的组件,适合快速实现标准的倒计时功能。但要注意其对结束事件的支持有限,复杂场景需自行扩展。

希望这些详细的示例和解释能帮助你更好地理解和使用鸿蒙开发中的这两个重要功能!

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞82 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容