關於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值一直爲空,希望大家有好的解決方式!