在生產(chǎn)型Android客戶端軟件(企業(yè)級應用)開發(fā)中壁榕,界面可能存在多個輸入(EditText
)和多個操作(MotionEvent
和KeyEvent
)灸眼,且操作依賴于輸入的狀態(tài)。如下圖所示的場景:
設(shè)定圖中
- 確認操作依賴于商品編碼和儲位的狀態(tài)
- 跳過操作不依賴于輸入狀態(tài)
- 登記差異操作依賴于儲位和數(shù)量的狀態(tài)
輸入框有三種狀態(tài):
- 待輸入帘瞭;
- 待校驗洋丐;
- 校驗成功苫幢。
操作需要當其依賴的輸入數(shù)據(jù)校驗成功,才能執(zhí)行垫挨。
如果在Activity中去判斷輸入框狀態(tài)韩肝,那么實際需要調(diào)用(3個輸入框)*
(3種狀態(tài))*
(3個按鈕) = 27個 if 判斷,對于狀態(tài)的維護將使得整個程序可維護性極差九榔,并隨著輸入和操作的增加哀峻,維護的狀態(tài)呈指數(shù)增長。
通過對這種場景的抽象哲泊,實現(xiàn)了Android控件狀態(tài)依賴框架剩蟀,其使用方法如下:
使用方法:
- 布局文件引用
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="確認" />
由于
Library Module
中的控件id
不是常量(可參考ButterKnife
對Library Module
的支持采用R2
的原因),這里采用了tag
的方式切威。
- 在
Activity中
通過注解申明依賴
@ViewName("商品編碼")
private WatchEditText editQuery1;
@ViewName("儲位")
private WatchEditText editQuery2;
@ViewName("數(shù)量")
private WatchEditText editQuery3;
@ViewDependency(name = @ViewName("確認"), dependency = {"editQuery1", "editQuery2"})
private WatchButton buttonSearch1;
@ViewDependency(name = @ViewName("跳過")/*不依賴輸入*/)
private WatchButton buttonSearch2;
@ViewDependency(name = @ViewName("登記缺貨"), dependency = {"editQuery2", "editQuery3"})
private WatchButton buttonSearch3;
ViewName
定義控件名稱育特,ViewDependency
中dependency
指定其依賴的控件tag
。
- 直接執(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, "跳下一頁", Toast.LENGTH_SHORT).show();
} else if (v == buttonSearch3) {
Toast.makeText(this, "登記缺貨", Toast.LENGTH_SHORT).show();
}
}
可以看出先朦,這里并沒有通過if
判斷各個輸入控件的狀態(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
進行校驗,這里需要注意通過editQuery1.complete()
修改該EidtText
的狀態(tài)喳魏。
實現(xiàn)原理
整個框架分為三個package:annotation
棉浸、state
和view
。
- 在
annotation
中定義ViewName
和ViewDependency
注解刺彩,分別用于WatchEditText
和WatchButton
迷郑。ViewName
指定WatchEditText
控件在業(yè)務中的名稱,ViewDependency
指定WatchButton
依賴的WatchEditText
控件创倔;
/**
* 控件狀態(tài)依賴
* Created by yanghao1 on 2016/12/19.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ViewDependency {
/**
* 控件名稱(嵌套注解)
*
* @return
*/
ViewName name() default @ViewName;
/**
* 控件狀態(tài)依賴
*
* @return
*/
String[] dependency() default {};
}
- 在
state
中通過狀態(tài)模式定義Enter
嗡害、Verify
、Complete
畦攘,其基類為抽象類Operator
霸妹,定義方法operator
;
/**
- 操作抽象接口
- Created by yanghao1 on 2016/12/15.
*/
public abstract class Operator {
// 操作對應的上下文
protected Context context;
/**
* 操作
*
* @param operatorName 操作名稱
* @param viewName 控件名稱
* @return 是否可以執(zhí)行操作
*/
public abstract boolean operator(String operatorName, String viewName);
}
/**
- 待輸入狀態(tài)(初始狀態(tài))
- Created by yanghao1 on 2016/12/19.
*/
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;
}
}
-
WatchEditText
和WatchButton
定義控件的依賴關(guān)系抑堡。WatchEditText
實現(xiàn)ViewState
接口,其包含三種狀態(tài)的轉(zhuǎn)換方法朗徊。
/**
* 控件狀態(tài)
* Created by yanghao1 on 2016/12/15.
*/
public interface ViewState {
/**
* 待輸入狀態(tài)(初始狀態(tài))
*/
void enter();
/**
* 待校驗狀態(tài)(有輸入(不為空)首妖,但未進行校驗,或校驗不成功)
*/
void verify();
/**
* 有輸入爷恳,并且校驗成功
*/
void complete();
}
以上有缆,Github地址:https://github.com/yhthu/AndroidViewDependency.git