Android控件狀態(tài)依賴框架

在生產(chǎn)型Android客戶端軟件(企業(yè)級(jí)應(yīng)用)開發(fā)中,界面可能存在多個(gè)輸入(EditText)和多個(gè)操作(MotionEventKeyEvent),且操作依賴于輸入的狀態(tài)。如下圖所示的場(chǎng)景:

Demo圖

設(shè)定圖中

  • 確認(rèn)操作依賴于商品編碼和儲(chǔ)位的狀態(tài)
  • 跳過(guò)操作不依賴于輸入狀態(tài)
  • 登記差異操作依賴于儲(chǔ)位和數(shù)量的狀態(tài)

輸入框有三種狀態(tài):

  1. 待輸入;
  2. 待校驗(yàn);
  3. 校驗(yàn)成功。

操作需要當(dāng)其依賴的輸入數(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)依賴框架,其使用方法如下:

使用方法:

  1. 布局文件引用WatchEditTextWatchButton
<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的方式。

  1. Activity中通過(guò)注解申明依賴
@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ò)")/*不依賴輸入*/)
private WatchButton buttonSearch2;
@ViewDependency(name = @ViewName("登記缺貨"), dependency = {"editQuery2", "editQuery3"})
private WatchButton buttonSearch3;

ViewName定義控件名稱,ViewDependencydependency指定其依賴的控件tag

  1. 直接執(zhí)行onClickonEditorAction(修改狀態(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:annotationstateview。

  1. annotation中定義ViewNameViewDependency注解,分別用于WatchEditTextWatchButtonViewName指定WatchEditText控件在業(yè)務(wù)中的名稱,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 {};
}
  1. state中通過(guò)狀態(tài)模式定義EnterVerify、Complete,其基類為抽象類Operator,定義方法operator;
/**
 - 操作抽象接口
 - Created by yanghao1 on 2016/12/15.
 */
public abstract class Operator {

    // 操作對(duì)應(yīng)的上下文
    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;
    }
}
  1. WatchEditTextWatchButton定義控件的依賴關(guān)系。WatchEditText實(shí)現(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();

    /**
     * 待校驗(yàn)狀態(tài)(有輸入(不為空),但未進(jìn)行校驗(yàn),或校驗(yàn)不成功)
     */
    void verify();

    /**
     * 有輸入,并且校驗(yàn)成功
     */
    void complete();
}

以上,Github地址:https://github.com/yhthu/AndroidViewDependency.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,790評(píng)論 25 709
  • 《裕語(yǔ)言》速成開發(fā)手冊(cè)3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 28,704評(píng)論 5 20
  • 《ijs》速成開發(fā)手冊(cè)3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 5,620評(píng)論 0 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • 今天是我的生日,感謝我的父母生育了我,道一句爸媽你們辛苦了,把我養(yǎng)這么大,我在外面還讓你們擔(dān)心,我一定會(huì)好好照...
    風(fēng)追葉子閱讀 246評(píng)論 0 0

友情鏈接更多精彩內(nèi)容