詳解Android控件狀態(tài)依賴(lài)框架
在生產(chǎn)型Android客戶(hù)端軟件(企業(yè)級(jí)應(yīng)用)開(kāi)發(fā)中,界面可能存在多個(gè)輸入(EditText)和多個(gè)操作(MotionEvent和KeyEvent),且操作依賴(lài)于輸入的狀態(tài)。如下圖所示的場(chǎng)景:
設(shè)定圖中
- 確認(rèn)操作依賴(lài)于商品編碼和儲(chǔ)位的狀態(tài)
- 跳過(guò)操作不依賴(lài)于輸入狀態(tài)
- 登記差異操作依賴(lài)于儲(chǔ)位和數(shù)量的狀態(tài)
輸入框有三種狀態(tài):
- 待輸入;
- 待校驗(yàn);
- 校驗(yàn)成功。
操作需要當(dāng)其依賴(lài)的輸入數(shù)據(jù)校驗(yàn)成功,才能執(zhí)行。
如果在Activity中去判斷輸入框狀態(tài),那么實(shí)際需要調(diào)用(3個(gè)輸入框)*(3種狀態(tài))*(3個(gè)按鈕) = 27個(gè) if 判斷,對(duì)于狀態(tài)的維護(hù)將使得整個(gè)程序可維護(hù)性極差,并隨著輸入和操作的增加,維護(hù)的狀態(tài)呈指數(shù)增長(zhǎng)。
通過(guò)對(duì)這種場(chǎng)景的抽象,實(shí)現(xiàn)了Android控件狀態(tài)依賴(lài)框架,其使用方法如下:
使用方法:
1、布局文件引用WatchEditText和WatchButton
<com.android.yhthu.viewdependency.view.WatchEditText android:id="@+id/edit_query_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="editQuery1" android:imeOptions="actionNext" android:hint="商品編碼" android:inputType="number"/> <com.android.yhthu.viewdependency.view.WatchButton android:id="@+id/search_button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:tag="buttonSearch1" android:text="確認(rèn)" />
由于Library Module中的控件id不是常量(可參考ButterKnife對(duì)Library Module的支持采用R2的原因),這里采用了tag的方式。
2、在Activity中通過(guò)注解申明依賴(lài)
@ViewName("商品編碼") private WatchEditText editQuery1; @ViewName("儲(chǔ)位") private WatchEditText editQuery2; @ViewName("數(shù)量") private WatchEditText editQuery3; @ViewDependency(name = @ViewName("確認(rèn)"), dependency = {"editQuery1", "editQuery2"}) private WatchButton buttonSearch1; @ViewDependency(name = @ViewName("跳過(guò)")/*不依賴(lài)輸入*/) private WatchButton buttonSearch2; @ViewDependency(name = @ViewName("登記缺貨"), dependency = {"editQuery2", "editQuery3"}) private WatchButton buttonSearch3;
ViewName定義控件名稱(chēng),ViewDependency中dependency指定其依賴(lài)的控件tag。
3、直接執(zhí)行onClick和onEditorAction(修改狀態(tài))
@Override public void onClick(View v) { if (v == buttonSearch1) { Toast.makeText(this, "調(diào)接口", Toast.LENGTH_SHORT).show(); } else if (v == buttonSearch2) { Toast.makeText(this, "跳下一頁(yè)", Toast.LENGTH_SHORT).show(); } else if (v == buttonSearch3) { Toast.makeText(this, "登記缺貨", Toast.LENGTH_SHORT).show(); } }
可以看出,這里并沒(méi)有通過(guò)if判斷各個(gè)輸入控件的狀態(tài)。
@Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_NEXT && v == editQuery1 && (query1Str = editQuery1.getText().toString()).isEmpty()) { if (query1Str.equals("12345")) { editQuery1.complete(); return true; } } // 省略代碼 return false; }
onEditorAction模擬調(diào)用軟件的Enter進(jìn)行校驗(yàn),這里需要注意通過(guò)editQuery1.complete()修改該EidtText的狀態(tài)。
實(shí)現(xiàn)原理
整個(gè)框架分為三個(gè)package:annotation、state和view。
1、在annotation中定義ViewName和ViewDependency注解,分別用于WatchEditText和WatchButton。ViewName指定WatchEditText控件在業(yè)務(wù)中的名稱(chēng),ViewDependency指定WatchButton依賴(lài)的WatchEditText控件;
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ViewDependency { ViewName name() default @ViewName; String[] dependency() default {}; }
2、在state中通過(guò)狀態(tài)模式定義Enter、Verify、Complete,其基類(lèi)為抽象類(lèi)Operator,定義方法operator;
public abstract class Operator { // 操作對(duì)應(yīng)的上下文 protected Context context; // 操作 public abstract boolean operator(String operatorName, String viewName); }
public class Enter extends Operator { private static Enter enter; private Enter(Context context) { this.context = context; } public static Enter getInstance(Context context) { if (enter == null) { enter = new Enter(context); } return enter; } @Override public boolean operator(String operatorName, String viewName) { Toast.makeText(context, String.format("[%s]為空,不允許執(zhí)行[%s]", viewName, operatorName), Toast.LENGTH_SHORT).show(); return false; } }
3、WatchEditText和WatchButton定義控件的依賴(lài)關(guān)系。WatchEditText實(shí)現(xiàn)ViewState接口,其包含三種狀態(tài)的轉(zhuǎn)換方法。
public interface ViewState { void enter(); void verify(); void complete(); }
以上,博客園對(duì)markdown支持的不太好,無(wú)法添加注釋?zhuān)?* */),如需查看源碼,請(qǐng)移步Github地址:https://github.com/yhthu/AndroidViewDependency.git
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android啟動(dòng)頁(yè)設(shè)置及動(dòng)態(tài)權(quán)限跳轉(zhuǎn)問(wèn)題解決
在我遇到這個(gè)實(shí)際問(wèn)題之前,我一直認(rèn)為啟動(dòng)頁(yè)的作用是美化產(chǎn)品,提升軟件逼格。但實(shí)際上,它更重要的是起到了一個(gè)攔截器的作用,這篇文章主要介紹了Android啟動(dòng)頁(yè)設(shè)置以及動(dòng)態(tài)權(quán)限跳轉(zhuǎn),需要的朋友可以參考下2022-04-04札記:android手勢(shì)識(shí)別功能實(shí)現(xiàn)(利用MotionEvent)
現(xiàn)在手勢(shì)識(shí)別的應(yīng)用已經(jīng)很廣泛了。本篇文章主要介紹了android手勢(shì)識(shí)別功能實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下。2016-11-11Android實(shí)現(xiàn)ListView數(shù)據(jù)動(dòng)態(tài)加載的方法
這篇文章主要介紹了Android實(shí)現(xiàn)ListView數(shù)據(jù)動(dòng)態(tài)加載的方法,通過(guò)ListView控件綁定setOnScrollListener方法簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù)的功能,需要的朋友可以參考下2016-01-01詳解如何使用Android Studio 進(jìn)行NDK開(kāi)發(fā)和調(diào)試
本篇文章主要介紹了詳解如何使用Android Studio 進(jìn)行NDK開(kāi)發(fā)和調(diào)試,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12android 自定義圓角button效果的實(shí)例代碼(自定義view Demo)
這篇文章主要介紹了android 自定義圓角button(自定義View Demo),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12Android開(kāi)發(fā)中MJRefresh自定義刷新動(dòng)畫(huà)效果
本文給大家介紹了MJRefresh自定義刷新動(dòng)畫(huà)效果,包括常見(jiàn)用法等相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-11-11Android簡(jiǎn)單實(shí)現(xiàn)計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了Android簡(jiǎn)單實(shí)現(xiàn)計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android camera2 判斷相機(jī)功能是否可控的實(shí)例
下面小編就為大家?guī)?lái)一篇Android camera2 判斷相機(jī)功能是否可控的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03Android實(shí)現(xiàn)手寫(xiě)板功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)手寫(xiě)板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06