Android自定義控件通用驗(yàn)證碼輸入框的實(shí)現(xiàn)
需求
4位驗(yàn)證碼輸入框:
效果圖:
1. 輸入框一行可輸入4位數(shù)字類型的驗(yàn)證碼;
2. 4位數(shù)字之間有間隔(包括底線);
3. 輸入框不允許有光標(biāo);
4. 底線根據(jù)輸入位置顯示高亮(藍(lán)色);
6. 輸入完成,回調(diào)結(jié)果,輸入過程中,也進(jìn)行回調(diào);
分析
這種效果,很難直接在Edittext上處理:
-- 輸入框均分4等份,還要有間隔;
-- 更難處理的是Edittext輸入框禁止光標(biāo),那么,沒有光標(biāo),我們?nèi)绾握{(diào)起虛擬鍵盤輸入數(shù)據(jù)?
-- 等...
與其在一個(gè)控件上折騰,這么難受,不如自定義一個(gè)控件,實(shí)現(xiàn)這種效果。
自定義控件最簡單的方案:使用多個(gè)控件,組合出這種效果。
1、布局如何實(shí)現(xiàn)?
1.禁止光標(biāo),我們直接使用TextView就解決了,而非Edittext;
2.一行顯示4位數(shù)字,比較簡單,可以使用線性布局的權(quán)重,對TextView進(jìn)行控制為4等分;
3.每個(gè)TextView下面跟著一個(gè)底線,將來我們就能對底線設(shè)置高亮顏色了;
這樣,基本的布局展示就可以了?。。?/p>
2、使用了TextView,那么我們?nèi)绾谓邮沼脩舻妮斎肽兀?/strong>
也很簡單,我們在4個(gè)TextView的上方平鋪一個(gè)EditText,設(shè)置透明,
當(dāng)用戶點(diǎn)擊到該控件時(shí),會自動(dòng)調(diào)起軟鍵盤,接收輸入的文本。
EditText接收到用戶輸入的文本,如何顯示在TextView呢?
3、我們監(jiān)聽EditText文本輸入事件,最多僅接收4個(gè)輸入字符,
每接收到一個(gè)字符,我們就賦值給對應(yīng)的TextView;
底線也隨要設(shè)置的文本切換顯示高亮;
4、如何刪除已輸入的數(shù)值?
我們監(jiān)聽EditText按鍵事件,攔截DEL鍵,從后向前挨著刪除字符即可;
底線也隨要?jiǎng)h除的文本切換顯示高亮;
5、是否需要自定義屬性
分析我們自己的項(xiàng)目,雖然是公用的控件,但是該控件比較簡單,沒有特別的要求,所以沒必要自定義屬性了!
如果大家有需要的,可根據(jù)需要自己定義;
如何定義屬性?請自行查找資料;
既然,問題都分析清楚了,那我們就開始快速實(shí)現(xiàn)吧
具體實(shí)現(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è)置了透明和無光標(biāo),僅接收數(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(){ //驗(yàn)證碼輸入 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)聽驗(yà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; } }); } /** * 顯示輸入的驗(yàn)證碼 */ 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); } } /** * 獲得手機(jī)號驗(yàn)證碼 * @return 驗(yàn)證碼 */ 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方法:獲得用戶輸入的驗(yàn)證碼,可被外界調(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(){ //獲得驗(yàn)證碼 String phoneCode = pc_1.getPhoneCode(); } }
總結(jié):
此控件實(shí)現(xiàn)起來,很簡單,代碼量也非常少。
本文章,主要是為了讓大家了解自定義控件的過程,如果想在自己的項(xiàng)目中使用,請根據(jù)需要自行調(diào)整優(yōu)化。
Demo下載地址:CustomView2_jb51.rar
(為了減小Demo大小,我刪除了build下的文件,大家獲取后rebuild一下代碼,就可以了)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android平臺中實(shí)現(xiàn)數(shù)據(jù)存儲的5種方式
這篇文章主要為大家分享了介紹了Android平臺中實(shí)現(xiàn)數(shù)據(jù)存儲技術(shù)的5種方式,供大家學(xué)習(xí),感興趣的小伙伴們可以參考一下2016-06-06Android懸浮窗屏蔽懸浮窗外部所有的點(diǎn)擊事件的實(shí)例代碼
這篇文章主要介紹了Android懸浮窗屏蔽懸浮窗外部所有的點(diǎn)擊事件實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03android基礎(chǔ)總結(jié)篇之二:Activity的四種launchMode
這篇文章主要介紹了android基礎(chǔ)總結(jié)篇之二:Activity的四種launchMode,有需要的可以了解一下。2016-11-11android控件實(shí)現(xiàn)單擊拖動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了android控件實(shí)現(xiàn)單擊拖動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01Android屬性動(dòng)畫實(shí)現(xiàn)布局的下拉展開效果
這篇文章主要為大家詳細(xì)介紹了Android屬性動(dòng)畫實(shí)現(xiàn)布局的下拉展開效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07android實(shí)現(xiàn)ViewPager懶加載的三種方法
這篇文章主要介紹了android實(shí)現(xiàn)ViewPager懶加載的三種方法,懶加載在項(xiàng)目運(yùn)用中很廣泛,可以提高運(yùn)行速度,有興趣的可以了解一下。2017-03-03Android獲取設(shè)備CPU核數(shù)、時(shí)鐘頻率以及內(nèi)存大小的方法
這篇文章主要介紹了Android獲取設(shè)備CPU核數(shù)、時(shí)鐘頻率以及內(nèi)存大小的方法,涉及Android針對系統(tǒng)硬件相關(guān)操作技巧,需要的朋友可以參考下2016-07-07Android開發(fā)之5.0activity跳轉(zhuǎn)時(shí)共享元素的使用方法
下面小編就為大家分享一篇Android開發(fā)之5.0activity跳轉(zhuǎn)時(shí)共享元素的使用方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01