需求
效果圖:
	
	1. 輸入框一行可輸入4位數(shù)字類型的驗證碼;
	2. 4位數(shù)字之間有間隔(包括底線);
	3. 輸入框不允許有光標;
	4. 底線根據(jù)輸入位置顯示高亮(藍色);
	6. 輸入完成,回調(diào)結(jié)果,輸入過程中,也進行回調(diào);
分析
	這種效果,很難直接在Edittext上處理:
	-- 輸入框均分4等份,還要有間隔;
	-- 更難處理的是Edittext輸入框禁止光標,那么,沒有光標,我們?nèi)绾握{(diào)起虛擬鍵盤輸入數(shù)據(jù)?
	-- 等...
	與其在一個控件上折騰,這么難受,不如自定義一個控件,實現(xiàn)這種效果。
	自定義控件最簡單的方案:使用多個控件,組合出這種效果。
1、布局如何實現(xiàn)?
	1.禁止光標,我們直接使用TextView就解決了,而非Edittext;
	2.一行顯示4位數(shù)字,比較簡單,可以使用線性布局的權(quán)重,對TextView進行控制為4等分;
	3.每個TextView下面跟著一個底線,將來我們就能對底線設(shè)置高亮顏色了;
	這樣,基本的布局展示就可以了!??!
	2、使用了TextView,那么我們?nèi)绾谓邮沼脩舻妮斎肽兀?/strong>
	也很簡單,我們在4個TextView的上方平鋪一個EditText,設(shè)置透明,
	當用戶點擊到該控件時,會自動調(diào)起軟鍵盤,接收輸入的文本。
	EditText接收到用戶輸入的文本,如何顯示在TextView呢?
	3、我們監(jiān)聽EditText文本輸入事件,最多僅接收4個輸入字符,
	每接收到一個字符,我們就賦值給對應(yīng)的TextView;
	底線也隨要設(shè)置的文本切換顯示高亮;
	4、如何刪除已輸入的數(shù)值?
	我們監(jiān)聽EditText按鍵事件,攔截DEL鍵,從后向前挨著刪除字符即可;
	底線也隨要刪除的文本切換顯示高亮;
	5、是否需要自定義屬性
	分析我們自己的項目,雖然是公用的控件,但是該控件比較簡單,沒有特別的要求,所以沒必要自定義屬性了!
	如果大家有需要的,可根據(jù)需要自己定義;
	如何定義屬性?請自行查找資料;
既然,問題都分析清楚了,那我們就開始快速實現(xiàn)吧
具體實現(xiàn)
布局文件 phone_code.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/ll_code" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginRight="7dp"> <TextView android:id="@+id/tv_code1" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#2D2D2D" android:textSize="40sp" android:background="@null" android:gravity="center"/> <View android:id="@+id/v1" android:layout_width="match_parent" android:layout_height="1dp" android:background="#3F8EED" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginRight="7dp" android:layout_marginLeft="7dp"> <TextView android:id="@+id/tv_code2" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#2D2D2D" android:textSize="40sp" android:background="@null" android:gravity="center"/> <View android:id="@+id/v2" android:layout_width="match_parent" android:layout_height="1dp" android:background="#999999" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginRight="7dp" android:layout_marginLeft="7dp"> <TextView android:id="@+id/tv_code3" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#2D2D2D" android:textSize="40sp" android:background="@null" android:gravity="center"/> <View android:id="@+id/v3" android:layout_width="match_parent" android:layout_height="1dp" android:background="#999999" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:layout_marginLeft="7dp"> <TextView android:id="@+id/tv_code4" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#2D2D2D" android:background="@null" android:textSize="40sp" android:gravity="center"/> <View android:id="@+id/v4" android:layout_width="match_parent" android:layout_height="1dp" android:background="#999999" /> </LinearLayout> </LinearLayout> <EditText android:id="@+id/et_code" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignTop="@+id/ll_code" android:layout_alignBottom="@+id/ll_code" android:background="@android:color/transparent" android:textColor="@android:color/transparent" android:cursorVisible="false" android:inputType="number"/></RelativeLayout>
	et_code 輸入框,設(shè)置了透明和無光標,僅接收數(shù)字;
	tv_code1~4 為顯示數(shù)字的控件;
	v1~4 為數(shù)字文本的底線,用于設(shè)置高亮;
自定義控件代碼 PhoneCode
package iwangzhe.customview2.phonecode;import android.content.Context;import android.graphics.Color;import android.text.Editable;import android.text.TextWatcher;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.View;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.RelativeLayout;import android.widget.TextView;import java.util.ArrayList;import java.util.List;import iwangzhe.customview2.R;/** * 類:PhoneCode * 作者: qxc * 日期:2018/3/14. */public class PhoneCode extends RelativeLayout {  private Context context;  private TextView tv_code1;  private TextView tv_code2;  private TextView tv_code3;  private TextView tv_code4;  private View v1;  private View v2;  private View v3;  private View v4;  private EditText et_code;  private List<String> codes = new ArrayList<>();  private InputMethodManager imm;  public PhoneCode(Context context) {    super(context);    this.context = context;    loadView();  }  public PhoneCode(Context context, AttributeSet attrs) {    super(context, attrs);    this.context = context;    loadView();  }  private void loadView(){    imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);    View view = LayoutInflater.from(context).inflate(R.layout.phone_code, this);    initView(view);    initEvent();  }  private void initView(View view){    tv_code1 = (TextView) view.findViewById(R.id.tv_code1);    tv_code2 = (TextView) view.findViewById(R.id.tv_code2);    tv_code3 = (TextView) view.findViewById(R.id.tv_code3);    tv_code4 = (TextView) view.findViewById(R.id.tv_code4);    et_code = (EditText) view.findViewById(R.id.et_code);    v1 = view.findViewById(R.id.v1);    v2 = view.findViewById(R.id.v2);    v3 = view.findViewById(R.id.v3);    v4 = view.findViewById(R.id.v4);  }  private void initEvent(){    //驗證碼輸入    et_code.addTextChangedListener(new TextWatcher() {      @Override      public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {      }      @Override      public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {      }      @Override      public void afterTextChanged(Editable editable) {        if(editable != null && editable.length()>0) {          et_code.setText("");          if(codes.size() < 4){            codes.add(editable.toString());            showCode();          }        }      }    });    // 監(jiān)聽驗證碼刪除按鍵    et_code.setOnKeyListener(new View.OnKeyListener() {      @Override      public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {        if (keyCode == KeyEvent.KEYCODE_DEL && keyEvent.getAction() == KeyEvent.ACTION_DOWN && codes.size()>0) {          codes.remove(codes.size()-1);          showCode();          return true;        }        return false;      }    });  }  /**   * 顯示輸入的驗證碼   */  private void showCode(){    String code1 = "";    String code2 = "";    String code3 = "";    String code4 = "";    if(codes.size()>=1){      code1 = codes.get(0);    }    if(codes.size()>=2){      code2 = codes.get(1);    }    if(codes.size()>=3){      code3 = codes.get(2);    }    if(codes.size()>=4){      code4 = codes.get(3);    }    tv_code1.setText(code1);    tv_code2.setText(code2);    tv_code3.setText(code3);    tv_code4.setText(code4);            setColor();//設(shè)置高亮顏色    callBack();//回調(diào)  }  /**   * 設(shè)置高亮顏色   */  private void setColor(){    int color_default = Color.parseColor("#999999");    int color_focus = Color.parseColor("#3F8EED");    v1.setBackgroundColor(color_default);    v2.setBackgroundColor(color_default);    v3.setBackgroundColor(color_default);    v4.setBackgroundColor(color_default);    if(codes.size()==0){      v1.setBackgroundColor(color_focus);    }    if(codes.size()==1){      v2.setBackgroundColor(color_focus);    }    if(codes.size()==2){      v3.setBackgroundColor(color_focus);    }    if(codes.size()>=3){      v4.setBackgroundColor(color_focus);    }  }  /**   * 回調(diào)   */  private void callBack(){    if(onInputListener==null){      return;    }    if(codes.size()==4){      onInputListener.onSucess(getPhoneCode());    }else{      onInputListener.onInput();    }  }  //定義回調(diào)  public interface OnInputListener{    void onSucess(String code);    void onInput();  }  private OnInputListener onInputListener;  public void setOnInputListener(OnInputListener onInputListener){    this.onInputListener = onInputListener;  }  /**   * 顯示鍵盤   */  public void showSoftInput(){    //顯示軟鍵盤    if(imm!=null && et_code!=null) {      et_code.postDelayed(new Runnable() {        @Override        public void run() {          imm.showSoftInput(et_code, 0);        }      },200);    }  }  /**   * 獲得手機號驗證碼   * @return 驗證碼   */  public String getPhoneCode(){    StringBuilder sb = new StringBuilder();    for (String code : codes) {      sb.append(code);    }    return sb.toString();  }}	codes 集合,用于存放用戶輸入的所有數(shù)字。使用該集合,可簡化輸入框、文本關(guān)聯(lián)邏輯和事件之間處理;
	showSoftInput方法:顯示輸入鍵盤,可被外界調(diào)用;
	getPhoneCode方法:獲得用戶輸入的驗證碼,可被外界調(diào)用;
	OnInputListener接口:定義的數(shù)值輸入回調(diào),用于告訴調(diào)用者是輸入中,還是輸入完成;
調(diào)用者 MainActivity
布局文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="iwangzhe.customview2.MainActivity"> <iwangzhe.customview2.phonecode.PhoneCode android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/pc_1" android:layout_below="@+id/fpc_1" android:layout_marginTop="40dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp"/></RelativeLayout>
代碼
package iwangzhe.customview2;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import iwangzhe.customview2.phonecode.PhoneCode;public class MainActivity extends AppCompatActivity {  PhoneCode pc_1;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    pc_1 = (PhoneCode) findViewById(R.id.pc_1);    //注冊事件回調(diào)(可寫,可不寫)    pc_1.setOnInputListener(new PhoneCode.OnInputListener() {      @Override      public void onSucess(String code) {        //TODO:      }      @Override      public void onInput() {        //TODO:      }    });  }  private void test(){    //獲得驗證碼    String phoneCode = pc_1.getPhoneCode();  }}總結(jié):
此控件實現(xiàn)起來,很簡單,代碼量也非常少。
本文章,主要是為了讓大家了解自定義控件的過程,如果想在自己的項目中使用,請根據(jù)需要自行調(diào)整優(yōu)化。
	Demo下載地址:CustomView2.rar
	(為了減小Demo大小,我刪除了build下的文件,大家獲取后rebuild一下代碼,就可以了)
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網(wǎng)。
新聞熱點
疑難解答
圖片精選