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

2021-06-10 10:33:01 浏览数 (1)

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

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

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

定义状态基类

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

代码语言:javascript复制
代码语言:javascript复制
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类并进行相应适配,代码的主干没有任何变化。

代码语言:javascript复制
代码语言:javascript复制
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("Lapd dh:dmds.dmsn",
                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类:

代码语言:javascript复制
代码语言:javascript复制
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 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。

0 人点赞