Android之必填項的便捷判定--TypedArray(下)

關於Android的必填項,包括登陸、註冊等,因爲Edittext比較少,所以大多數人選擇gettext然後一一判空,但是如果Edittext比較多的時候,就比較繁瑣了。考慮到優化方案有二:1、重寫Edittext,然後利用註冊,在保存時判定每個Edittext;二、考慮到所有的數據最後都會保存成一個類,所以不管Edittext,保存之前只判斷自定義類。本文主要闡述第一種方式,優點是不需要反射,耗時短。

首先,我們看效果圖:

實現方法:用單例模式建立註冊器,支持動態註冊,註冊方式有xml,view以及自定義的Edittext,考慮到多Activity的操作與複用,Edittext集合採用CopyOnWriterArrayList,全局集合採用ConcurrentHashMap。最後解綁的時候只需要在基類Activity的onDestroy方法中進行UNRegister即可,非常的方便。

最後,前端Activity的代碼:

public class CustomEditActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_edittext);
    }

    public void onCheck(View view){
        EditTextUtil.getInstance().checkEmpty(this);
    }

    @Override
    protected void onDestroy() {
        EditTextUtil.getInstance().unRegister(this);
        super.onDestroy();
    }
}

與其對應的xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">
    <java.wen.com.view.EmptyEditText
        android:id="@+id/username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用戶名"
        app:toast_text="請輸入用戶名"
        app:necessary="true"/>
    <java.wen.com.view.EmptyEditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密碼"
        app:toast_text="請輸入用戶密碼"
        app:necessary="true"/>
    <java.wen.com.view.EmptyEditText
        android:id="@+id/code"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="邀請碼"
        app:toast_text="請輸入用戶邀請碼"/>

    <Button
        android:id="@+id/btn_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="檢查必填項"
        android:onClick="onCheck"/>
</LinearLayout>

自定義的EditText,支持xml中配置必填項與提示:

public class EmptyEditText extends EditText {

    private boolean necessary = false;
    private String toastString = "";

    public EmptyEditText(Context context) {
        super(context);
    }

    public EmptyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public EmptyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.EmptyEditText);
        if(null != ta) {
            toastString = ta.getString(R.styleable.EmptyEditText_toast_text);
            necessary = ta.getBoolean(R.styleable.EmptyEditText_necessary,false);
            ta.recycle();
        }
    }

    public boolean checkEmpty(){
        return checkEmpty(false);
    }

    public boolean checkEmpty(boolean toast){
        if(necessary) {
            Object value = getText();
            if (null == value || TextUtils.isEmpty(value.toString().trim())) {
                if (toast && !TextUtils.isEmpty(toastString)) {
                    Toast.makeText(getContext(), toastString, Toast.LENGTH_SHORT).show();
                }
                return true;
            }
        }
        return false;
    }
}

最後就是單例模式的註冊器,懶加載的模式:

public class EditTextUtil {
    static volatile EditTextUtil defaultInstance;

    private static ConcurrentHashMap<Context,CopyOnWriteArrayList<EmptyEditText>> textMap = new ConcurrentHashMap<>();

    public static EditTextUtil getInstance(){
        if(defaultInstance == null)
            defaultInstance = new EditTextUtil();
        return defaultInstance;
    }

    public void register(Context context,int xml){
        View view = LayoutInflater.from(context).inflate(xml,null);
        register(context,view);
    }

    public void register(Context context, View view){
        List<EmptyEditText> textList = getChildEdit(view);
        register(context,textList);
    }

    public void register(Context context, List<EmptyEditText> textList){
        CopyOnWriteArrayList<EmptyEditText> editList = new CopyOnWriteArrayList<>();
        editList.addAll(textList);
        textMap.put(context, editList);
    }

    public void register(Context context, EmptyEditText textList){
        CopyOnWriteArrayList<EmptyEditText> editList = null;
        if(textMap.containsKey(context)){
            editList= textMap.get(context);
        }
        if(null == editList){
            editList = new CopyOnWriteArrayList<>();
        }
        editList.add(textList);
        textMap.put(context, editList);
    }

    private List<EmptyEditText> getChildEdit(View view){
        List<EmptyEditText> textList = new ArrayList<>();
        getChildEdit(textList,view);
        return textList;
    }

    private List<EmptyEditText> getChildEdit(List<EmptyEditText> textList,View view){
        if(view instanceof ViewGroup) {
            ViewGroup vp = (ViewGroup) view;
            for (int i = 0; i < vp.getChildCount(); i++) {
                View viewchild = vp.getChildAt(i);
                if(viewchild instanceof ViewGroup){
                    getChildEdit(textList,viewchild);
                }else if(viewchild instanceof EmptyEditText){
                    textList.add((EmptyEditText) viewchild);
                }
            }
        }
        return textList;
    }

    public boolean checkEmpty(Context context){
        CopyOnWriteArrayList data = textMap.get(context);
        if(null == data || data.size() ==0){
            if(context instanceof Activity){
                List<EmptyEditText> textList = getAllViews((Activity) context);
                register(context,textList);
                return checkEmpty(textList);
            }
            return checkEmpty(data);
        }
        return checkEmpty(data);
    }

    public boolean checkEmpty(CopyOnWriteArrayList<EmptyEditText> editList){
        boolean result = false;
        if(null == editList || editList.size() ==0){
            return result;
        }
        for (EmptyEditText edittext:editList) {
            if(edittext.checkEmpty(true)){
                result = true;
                break;
            }
        }
        return result;
    }

    private List<EmptyEditText> getAllViews(Activity act) {
        return getAllChildViews(act.getWindow().getDecorView());
    }

    private List<EmptyEditText> getAllChildViews(View view) {
        List<EmptyEditText> allchildren = new ArrayList<>();
        if (view instanceof ViewGroup) {
            ViewGroup vp = (ViewGroup) view;
            for (int i = 0; i < vp.getChildCount(); i++) {
                View viewchild = vp.getChildAt(i);
                if(viewchild instanceof EmptyEditText){
                    allchildren.add((EmptyEditText) viewchild);
                }else if(viewchild instanceof ViewGroup){
                    //再次 調用本身(遞歸)
                    allchildren.addAll(getAllChildViews(viewchild));
                }
            }
        }
        return allchildren;
    }

    public boolean checkEmpty(List<EmptyEditText> data){
        CopyOnWriteArrayList<EmptyEditText> editList = new CopyOnWriteArrayList<>();
        editList.addAll(data);
        return checkEmpty(editList);
    }

    public void unRegister(Context context){
        textMap.remove(context);
    }
}

values中自定義EditText所需要的提示與是否必須:

<declare-styleable name="EmptyEditText">
        <attr name="toast_text" format="string|reference" />
        <attr name="necessary" format="boolean|reference" />
    </declare-styleable>

至此,目前兩種Android必填項判空的方式已完成,如果只是單純的登陸界面無所謂,但是如果是大量添加表單的頁面,這樣精簡還是很有必要的。另外這樣的註冊器還有一個問題,就是當採用xml的註冊方式時,EditText的getText值一直爲空,希望大家有好的解決方式!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章