自學HarmonyOS應用開發(fā)(48)- Tablist組件進階

在應用開發(fā)中經(jīng)常會用到Tablist組件,連載中也介紹了該組件的基本用法:
但是有一個問題是這篇文章,包括HarmonyOS應用開發(fā)的官方文檔都只是實現(xiàn)了Tab切換的基本功能,對于每個Tab頁內組件的處理沒有詳細說明。本文就來補上這個短板。
定義狀態(tài)基類
對于包含Tablist的AbilitySlice來講,需要根據(jù)Tablist的選擇結果切換畫面組件和相應的動作處理,我們?yōu)榇硕x了一個SliceState基類。
public abstract class SliceState {AbilitySlice owner_slice = null;ComponentContainer component_container = null;//構造函數(shù)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();}}
這個類主要的意義除了負責裝載布局資源以外,就是定義了一些抽象接口。
實現(xiàn)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);}public int getLayoutId(){ return ResourceTable.Layout_stopwatch;};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() {public void onClick(Component component) {if(stopwatch.isRunning()){recordTime();}stopwatch.start_stop();updateButton();}});reset_lap.setClickedListener(new Component.ClickedListener() {public void onClick(Component component) {if (stopwatch.isRunning()){recordTime();}else{stopwatch.reset();clearTime();start_stop.setTextColor(Color.BLACK);}}});loadStatus();}public void onStop(){HiLog.info(LABEL, "onStop");super.onStop();}public void onForeground(Intent intent){HiLog.info(LABEL, "MainAbilitySlice.onForeground");super.onForeground(intent);stopwatch.onForeground(intent);}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, //hourmilliseconds / 1000 / 60 % 60, //minutemilliseconds / 1000 % 60, //secondmilliseconds % 1000); //milisecondlap_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入?yún)㈩愋蜑閛hos.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入?yún)㈩愋蜑閛hos.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;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() {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);}}public void onUnselected(TabList.Tab tab) {current_state.onBackground();current_state = null;}public void onReselected(TabList.Tab tab) {onSelected(tab);}});//最開始選選擇tab1tabList.selectTab(stopwatchTab);}public void onForeground(Intent intent) {HiLog.info(LABEL, "MainAbilitySlice.onForeground");super.onForeground(intent);current_state.onBackground();}public void onBackground(){HiLog.info(LABEL, "MainAbilitySlice.onBackground");super.onBackground();current_state.onBackground();}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
作者著作介紹
《實戰(zhàn)Python設計模式》是作者去年3月份出版的技術書籍,該書利用Python 的標準GUI 工具包tkinter,通過可執(zhí)行的示例對23 個設計模式逐個進行說明。這樣一方面可以使讀者了解真實的軟件開發(fā)工作中每個設計模式的運用場景和想要解決的問題;另一方面通過對這些問題的解決過程進行說明,讓讀者明白在編寫代碼時如何判斷使用設計模式的利弊,并合理運用設計模式。

對設計模式感興趣而且希望隨學隨用的讀者通過本書可以快速跨越從理解到運用的門檻;希望學習Python GUI 編程的讀者可以將本書中的示例作為設計和開發(fā)的參考;使用Python 語言進行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎,迅速構建自己的系統(tǒng)架構。
覺得本文有幫助?請分享給更多人。
關注微信公眾號【面向對象思考】輕松學習每一天!
面向對象開發(fā),面向對象思考!
