专栏首页C++核心准则原文翻译自学HarmonyOS应用开发(48)- Tablist组件进阶

自学HarmonyOS应用开发(48)- Tablist组件进阶

在应用开发中经常会用到Tablist组件,连载中也介绍了该组件的基本用法:

自学鸿蒙应用开发(17)- TabList和Tab

但是有一个问题是这篇文章,包括HarmonyOS应用开发的官方文档都只是实现了Tab切换的基本功能,对于每个Tab页内组件的处理没有详细说明。本文就来补上这个短板。

定义状态基类

对于包含Tablist的AbilitySlice来讲,需要根据Tablist的选择结果切换画面组件和相应的动作处理,我们为此定义了一个SliceState基类。

public abstract class SliceState {
    AbilitySlice owner_slice = null;
    ComponentContainer component_container = null;
    //构造函数
    public SliceState(AbilitySlice slice, ComponentContainer container) {
        owner_slice = slice;
        component_container = container;
    }
    public abstract int getLayoutId();
    public void onStart(Intent intent)
    {
        Component state_layout = LayoutScatter.getInstance(owner_slice).parse(getLayoutId(), 
                                                                        null,
                                                                        false);
        component_container.addComponent(state_layout);
    }
    public void onStop(){
    }
    public void onForeground(Intent intent){
    }
    public void onBackground(){
        component_container.removeAllComponents();
    }
}

这个类主要的意义除了负责装载布局资源以外,就是定义了一些抽象接口。

实现StopWatchState类

这个类就是之前StopWatchSlice类的小改款,将基类调整为SliceState类并进行相应适配,代码的主干没有任何变化。

public class StopWatchState extends SliceState {
    static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00102, "StopWatchState");
    AnalogStopWatch stopwatch = null;
    Text lap_time = null;
    int record_count = 0;
    Button start_stop = null;
    Button reset_lap = null;

    public StopWatchState(AbilitySlice slice, ComponentContainer container) {
        super(slice, container);
    }

    @Override
    public int getLayoutId(){ return ResourceTable.Layout_stopwatch;};

    @Override
    public void onStart(Intent intent) {
        //HiLog.warn(LABEL, "Failed to visit %{private}s, reason:%{public}d.", url, errno);
        HiLog.info(LABEL, "onStart");
        super.onStart(intent);
        //秒表组件
        stopwatch = (AnalogStopWatch)owner_slice.findComponentById(ResourceTable.Id_analog_stop_watch);
        //计时结果Text组件
        lap_time = (Text)owner_slice.findComponentById(ResourceTable.Id_lap_times);
        //开始或停止按钮
        start_stop = (Button)owner_slice.findComponentById(ResourceTable.Id_start_stop);
        //清零或保存结果按钮
        reset_lap = (Button)owner_slice.findComponentById(ResourceTable.Id_reset_lap);
        start_stop.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if(stopwatch.isRunning()){
                    recordTime();
                }
                stopwatch.start_stop();
                updateButton();
            }
        });

        reset_lap.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (stopwatch.isRunning()){
                    recordTime();
                }
                else{
                    stopwatch.reset();
                    clearTime();
                    start_stop.setTextColor(Color.BLACK);
                }
            }
        });
        loadStatus();
    }

    @Override
    public void onStop(){
        HiLog.info(LABEL, "onStop");
        super.onStop();
    }

    @Override
    public void onForeground(Intent intent){
        HiLog.info(LABEL, "MainAbilitySlice.onForeground");
        super.onForeground(intent);
        stopwatch.onForeground(intent);
    }

    @Override
    public void onBackground(){
        HiLog.info(LABEL, "MainAbilitySlice.onBackground");
        super.onBackground();
        saveStatus();
        stopwatch.onBackground();
    }

    //清除计时结果
    private void clearTime(){
        lap_time.setText("");
        record_count = 0;
    }

    //记录当前时间
    private void recordTime(){
        String lap_string = lap_time.getText();
        long milliseconds = stopwatch.getMilliseconds();
        String current_time = String.format("Lap%02d %02dh:%02dm%02ds.%03dms\n",
                record_count,
                milliseconds / 1000 / 60 / 60 % 60,  //hour
                milliseconds / 1000 / 60 % 60,       //minute
                milliseconds / 1000 % 60,            //second
                milliseconds % 1000);                //milisecond
        lap_time.setText(lap_string + current_time);
        record_count++;
    }

    private void updateButton(){
        if(stopwatch.isRunning()){
            start_stop.setText(ResourceTable.String_Stop);
            start_stop.setTextColor(Color.BLACK);
            reset_lap.setText(ResourceTable.String_Lap);
        }
        else{
            start_stop.setText(ResourceTable.String_Start);
            if(stopwatch.getMilliseconds() == 0) {
                start_stop.setTextColor(Color.BLACK);
            }
            else {
                start_stop.setTextColor(Color.LTGRAY);
            }
            reset_lap.setText(ResourceTable.String_Reset);
        }
    }

    private void loadStatus(){
        HiLog.info(LABEL, "MainAbilitySlice.loadStatus");
        DatabaseHelper databaseHelper = new DatabaseHelper(owner_slice); // context入参类型为ohos.app.Context。
        Preferences preferences = databaseHelper.getPreferences("StopWatch");
        stopwatch.setStartTime(preferences.getLong("start_time", 0));
        stopwatch.setMilliseconds(preferences.getLong("milliseconds", 0));
        lap_time.setText(preferences.getString("lap_times", ""));
        record_count = preferences.getInt("record_count", 0);
        if(preferences.getBoolean("running",false)){
            stopwatch.start();
        }
        updateButton();
    }
    
    private void saveStatus(){
        HiLog.info(LABEL, "MainAbilitySlice.saveStatus");
        DatabaseHelper databaseHelper = new DatabaseHelper(owner_slice); // context入参类型为ohos.app.Context。
        Preferences preferences = databaseHelper.getPreferences("StopWatch");
        preferences.putBoolean("running", stopwatch.isRunning());
        preferences.putLong("start_time", stopwatch.getStartTime());
        preferences.putLong("milliseconds", stopwatch.getMilliseconds());
        preferences.putString("lap_times", lap_time.getText());
        preferences.putInt("record_count", record_count);
    }
}

在AbilitySlice类中使用StopWatchState类

以下代码展示了如何在MainAbilitySlice中使用SliceState和StopWatchState类:

public class MainAbilitySlice extends AbilitySlice {
    static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00101, "MainAbilitySlice");
    TabList.Tab stopwatchTab = null;
    TabList.Tab mapTab = null;
    TabList.Tab settingTab = null;
    private SliceState current_state = null;
    @Override
    public void onStart(Intent intent) {
        //HiLog.warn(LABEL, "Failed to visit %{private}s, reason:%{public}d.", url, errno);
        HiLog.info(LABEL, "onStart");
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        TabList tabList = (TabList) findComponentById(ResourceTable.Id_tab_list);
        stopwatchTab = tabList.new Tab(getContext());
        stopwatchTab.setText("秒表");
        tabList.addTab(stopwatchTab);
        mapTab = tabList.new Tab(getContext());
        mapTab.setText("地图");
        tabList.addTab(mapTab);
        settingTab = tabList.new Tab(getContext());
        settingTab.setText("设定");
        tabList.addTab(settingTab);
        AbilitySlice slice = this;
        tabList.addTabSelectedListener(new TabList.TabSelectedListener() {
            @Override
            public void onSelected(TabList.Tab tab) {
                ComponentContainer container = (ComponentContainer) findComponentById(ResourceTable.Id_tab_container);
                if(tab == stopwatchTab) {
                    current_state = new StopWatchState(slice, container);
                    current_state.onStart(intent);
                }
                else
                {
                    current_state = new SettingState(slice, container);
                    current_state.onStart(intent);
                }
            }

            @Override
            public void onUnselected(TabList.Tab tab) {
                current_state.onBackground();
                current_state = null;
            }

            @Override
            public void onReselected(TabList.Tab tab) {
                onSelected(tab);
            }
        });
        //最开始选选择tab1
        tabList.selectTab(stopwatchTab);
    }
   
    @Override
    public void onForeground(Intent intent) {
        HiLog.info(LABEL, "MainAbilitySlice.onForeground");
        super.onForeground(intent);
        current_state.onBackground();
    }

    @Override
    public void onBackground(){
        HiLog.info(LABEL, "MainAbilitySlice.onBackground");
        super.onBackground();
        current_state.onBackground();
    }

    @Override
    public void onStop() {
        HiLog.info(LABEL, "MainAbilitySlice.onStop!");
        super.onStop();
        current_state.onStop();
    }
}

除了代码29行引入了StopWatchState,34行引入了SettingState之外,所有代码都是面向基类SliceState编程。这样做的好处就是:每种画面的布局,处理代码都独立为一个单独的SliceState类,增加功能变得容易且安全,例如SettingState类。

以下是实际动作的演示视频,画面不连贯是模拟器的原因。

参考资料

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-overview-0000000000500404

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-switch-0000001060806006

作者著作介绍

《实战Python设计模式》是作者去年3月份出版的技术书籍,该书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。

对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。

本文分享自微信公众号 - 面向对象思考(OOThinkingDalian),作者:面向对象思考

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-06-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自学HarmonyOS应用开发(47)- 自定义switch组件

    HarmonyOS应用开发都会用到各种各样的UI组件,开发者可以根据需求在布局文件设定UI组件各种属性。但是需求是多种多样

    面向对象思考
  • 自学鸿蒙应用开发(17)- TabList和Tab

    在layout目录下创建TabList布局,将其命名为ability_tablist.xml。

    面向对象思考
  • 自学HarmonyOS应用开发(65)- 为Tab组件使用图像资源

    用图像装饰UI组件可以让应用显得更专业,本文介绍Tab组件使用图像资源的方法。先看动作效果:

    面向对象思考
  • 开发|走进小程序(二)

    之前的博客《走进小程序》介绍了制作小程序的准备步骤和一些技术知识,这次我们从实际制作入手,边做边学。

    算法与编程之美
  • 自学HarmonyOS应用开发(57)- 与Service进行交互

    构建自己的Connection类 StopWatchServiceConnection类的主要功能有两个:一是接受连接成功通知并获取服务端传过来的用于通信的IR...

    面向对象思考
  • 自学HarmonyOS应用开发(59)- 处理拖动事件

    在Harmony应用中通过实现Component.DraggedListener接口处理拖动事件,这个接口的方法一共有6个,这里我们只是用其中的3个:

    面向对象思考
  • 【第22期】HarmonyOS应用开发(基础篇)

    这不就是说,以后华为手机都是鸿蒙系统了嘛?鸿蒙还发出了一条视频,视频中显示2021年6月2号将开启鸿蒙操作系统及华为全场景新品发布会。预计现在支持EMUI11升...

    siberiawolf
  • 自学HarmonyOS应用开发(66)- 自定义布局(1)

    Harmony应用开发文档中为Java开发者提供了6种UI布局,可以满足开发者的大部分需求。但是有一个问题是:这些布局一旦显示,用户便无法进行调整。我们开发一个...

    面向对象思考
  • 自学HarmonyOS应用开发(67)- 自定义布局(2)

    除了这两个限制之外,调整对象组件的类型/个数,分隔的组件的高度都可以任意指定。够灵活了吧。

    面向对象思考
  • 技术分析 | HarmonyOS到底是不是Android套皮?

    最近鸿蒙系统关注度好高,支持与反对、看好和看衰、「自主的全场景分布式系统」和「Android套壳」各执一词,吵的不可开交。

    刘盼
  • HarmonyOS简介

    前两天,华为发布了HarmonyOS 2.0,俺也赶个时髦,给大家简单介绍下HarmonyOS。

    xiangzhihong
  • 自学HarmonyOS应用开发(64)- 处理屏幕旋转

    旋转屏幕是手机用户的一个日常操作,本文介绍如何在屏幕旋转时自动调整屏幕布局的方法。效果如下:

    面向对象思考
  • 自学HarmonyOS应用开发(49)- 引入地图功能

    秒表应用的功能就是计时,其中有一种情况就是计算地图上两点之间移动的时间。但是作者在实际使用这个应用的时候,经常会忘了在预定地点开始和停止计时。解决这个问题的想法...

    面向对象思考
  • 自学HarmonyOS应用开发(53)- 获取当前位置

    在registerLocationEvent方法用来注册一个单次定位事件请求;在定位事件响应对象中我们将获得的位置信息通知给地图对象。

    面向对象思考
  • 自学HarmonyOS应用开发(54)- 校正定位偏差

    经过一番调查,结论是gps信号使用的是WGS-84坐标系,而高德地图使用的是GCJ-02火星坐标系,只有经过坐标变换才能显示正确的位置。这方面的文章网上有很多,...

    面向对象思考
  • 程序员看华为HarmonyOS首发

    HarmonyOS代码正式开源,9月10日下午朋友圈散布着这条消息,科技圈炸锅了。各种声音的都有,我也挺好奇的,目前Android、iOS一统江湖,Harmon...

    马上就说
  • HarmonyOS与Android的全面对比

    第二是我个人非常看好鸿蒙系统的未来,清楚明白华为和一些民族企业担负的责任和国人的期待,虽然带着一些民族感情;鸿蒙刚发布的时候自己是非常激动的,但是后来项目太忙一...

    肉眼品世界
  • 十问华为HarmonyOS:开源一个月,开发者生态建设进度如何?

    基础软件的开源面临着非常大的挑战,除了技术研发困难重重,开源生态和社区的建设更是难上加难。9 月 10 日,在华为开发者大会 2020 上,华为消费者业务 CE...

    深度学习与Python
  • 自学鸿蒙应用开发(9)- TimePicker组件

    如下面代码中21行~49行所示,在获取TimePicker组件后,一方面在button的动作响应中计算所选时刻和当前时刻的秒数差之后用小窗口表示出来;另一方面在...

    面向对象思考

扫码关注云+社区

领取腾讯云代金券