Android自定義短信驗(yàn)證碼組件
Android自定義短信驗(yàn)證碼組件,供大家參考,具體內(nèi)容如下
效果圖
1.布局實(shí)現(xiàn)
因?yàn)橐霉鈽?biāo),所以我用TextView代替了EditText,每一行顯示的驗(yàn)證碼個(gè)數(shù)由用戶決定,所以我這里用線性布局的權(quán)重,對(duì)TextView進(jìn)行控制寬度等分,然后設(shè)置選中和未選中當(dāng)前TextView的底部邊框,設(shè)置高亮顏色背景
2.接受用戶輸入
我這里使用了TextView,但是怎么接受用戶輸入的值呢。這里我直接繼承了RelativeLayout,然后添加了一個(gè)透明的EditText,覆蓋在這幾個(gè)TextView上面,用戶就可以點(diǎn)擊喚起鍵盤輸入
3.TextView如何顯示值和刪除值
我這里設(shè)置EditText的TextColor和BackgroundColor為Color.TRANSPARENT 透明,然后監(jiān)聽EditText的addTextChangedListener事件和setOnKeyListener按鍵刪除事件,然后把值添加到TextView上,就能實(shí)現(xiàn)了,然后在寫一個(gè)對(duì)外的接口。獲取到輸入的驗(yàn)證碼。
4.添加閃爍的動(dòng)畫
我這里使用了ObjectAnimator,初始化給每個(gè)TextView添加動(dòng)畫,然后在輸入的時(shí)候給當(dāng)前的TextView啟動(dòng)動(dòng)畫,取消其他TextView動(dòng)畫
具體源碼如下:
/** * @author wu_ming_zhi_bei * @date 2021/1/27 15:00 * @Notes */ public class VerificationCodeView extends RelativeLayout { private Context mContext; private RelativeLayout.LayoutParams layoutParams; private int num = 4;//驗(yàn)證碼數(shù)量 private int codeSize;//字體大小 private int codeColor;//字體顏色 private List<TextView> tvs = new ArrayList<>(); private List<String> codes = new ArrayList<>(); private EditText etCode; private InputMethodManager imm; List<ObjectAnimator> animators = new ArrayList<>(); public VerificationCodeView(Context context) { this(context,null); } public VerificationCodeView(Context context, AttributeSet attrs) { this(context,attrs,0); } public VerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context,attrs); } private void init(Context context, AttributeSet attrs) { this.mContext = context; imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView); num = a.getInteger(R.styleable.VerificationCodeView_num,4); codeSize = a.getDimensionPixelSize(R.styleable.VerificationCodeView_codeSize,18); codeColor = a.getColor(R.styleable.VerificationCodeView_codeColor,getResources().getColor(R.color.theme_color)); //初始化一個(gè)大的LinearLayout來存放驗(yàn)證碼 LinearLayout codeBox = new LinearLayout(mContext); codeBox.setOrientation(LinearLayout.HORIZONTAL); codeBox.setGravity(Gravity.CENTER); //添加方塊 for(int i=0;i<num;i++){ TextView tv = new TextView(mContext); tv.setTextSize(codeSize); tv.setTextColor(codeColor); tv.setGravity(Gravity.CENTER); tv.setPadding(0,0,0,10); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1); param.gravity = Gravity.CENTER; param.rightMargin = 20; param.leftMargin = 20; param.topMargin = 20; param.bottomMargin = 20; tv.setLayoutParams(param); //默認(rèn)第一個(gè)選中 if(i==0){ tv.setText("|"); tv.setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom)); }else{ tv.setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom)); } codeBox.addView(tv); tvs.add(tv);//添加到數(shù)組 } layoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); //添加codebox的位置在組件的最上面 layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,TRUE); layoutParams.setMargins(60,0,60,0); codeBox.setLayoutParams(layoutParams); //添加Edit etCode = new EditText(mContext); etCode.setLayoutParams(layoutParams); etCode.setLines(1); etCode.setMaxLines(1); etCode.setTextColor(Color.TRANSPARENT); etCode.setBackgroundColor(Color.TRANSPARENT); etCode.setCursorVisible(false); //添加edit監(jiān)聽 etCode.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) { etCode.setText("");//清空數(shù)據(jù) if(codes.size() < num){ codes.add(editable.toString()); showCode(); } } } }); // 監(jiān)聽驗(yàn)證碼刪除按鍵 etCode.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; } }); addView(codeBox); addView(etCode); addAnimation();//添加?xùn)|安湖 setTwinkle();//開啟動(dòng)畫 } //顯示驗(yàn)證碼 private void showCode(){ int size = codes.size();//1 6 for(int i=0;i<num;i++){ if(size>i){ tvs.get(i).setText(codes.get(i));//添加到textview }else if(size==i){ tvs.get(i).setText("|"); }else{ tvs.get(i).setText(""); } } etCode.setFocusable(true); etCode.requestFocus(); etCode.setFocusableInTouchMode(true); etCode.requestFocusFromTouch(); setTwinkle();//動(dòng)畫 callBack();//回調(diào) } private void showColor(){ int size = codes.size(); if(size==0){ tvs.get(0).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom)); }else{ for(int i=0;i<tvs.size();i++){ if(i==size-1){ tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom)); }else{ tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom)); } } } } /** * 回調(diào) */ private void callBack(){ if(onInputListener==null){ return; } if(codes.size()==num){ 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; } /** * 獲得手機(jī)號(hào)驗(yàn)證碼 * @return 驗(yàn)證碼 */ public String getPhoneCode(){ StringBuilder sb = new StringBuilder(); for (String code : codes) { sb.append(code); } return sb.toString(); } /** * 顯示鍵盤 */ public void showSoftInput(){ //顯示軟鍵盤 if(imm!=null && etCode!=null) { etCode.postDelayed(new Runnable() { @Override public void run() { imm.showSoftInput(etCode, 0); } },200); } } /** * 隱藏鍵盤 */ public void hideSoftInput(){ //顯示軟鍵盤 if(imm!=null && etCode!=null) { etCode.postDelayed(new Runnable() { @Override public void run() { imm.hideSoftInputFromWindow(etCode.getWindowToken(), 0); } },200); } } /** * 添加動(dòng)畫 */ private void addAnimation(){ for(int i=0;i<tvs.size();i++){ ObjectAnimator animator = ObjectAnimator.ofInt(tvs.get(i), "TextColor", 0x00000000, 0xfff00000); animator.setDuration(10000); final int index = i; animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { } @Override public void onAnimationCancel(Animator animator) { tvs.get(index).setTextColor(codeColor); } @Override public void onAnimationRepeat(Animator animator) { } }); animator.setInterpolator(new LinearInterpolator()); animator.setRepeatCount(Animation.INFINITE); animators.add(animator); } } /** * 開啟動(dòng)畫 */ private void setTwinkle(){ int size = codes.size(); for(int i=0;i<tvs.size();i++){ if(i==size){ animators.get(i).start(); tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom)); }else{ animators.get(i).cancel(); tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom)); } } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); for(int i=0;i<tvs.size();i++){ animators.get(i).cancel(); } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android開發(fā)中通過手機(jī)號(hào)+短信驗(yàn)證碼登錄的實(shí)例代碼
- Android開發(fā)工程中集成mob短信驗(yàn)證碼功能的方法
- Android實(shí)現(xiàn)短信驗(yàn)證碼獲取自動(dòng)填寫功能(詳細(xì)版)
- Android獲取和讀取短信驗(yàn)證碼的實(shí)現(xiàn)方法
- Android實(shí)現(xiàn)自動(dòng)提取短信驗(yàn)證碼功能
- Android實(shí)現(xiàn)短信驗(yàn)證碼自動(dòng)填寫功能
- Android獲取短信驗(yàn)證碼的實(shí)現(xiàn)方法
- Android用 Mob 實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼實(shí)例
- Android如何通過手機(jī)自動(dòng)獲取短信驗(yàn)證碼
- Android中用Bmob實(shí)現(xiàn)短信驗(yàn)證碼功能的方法詳解
相關(guān)文章
Android電量?jī)?yōu)化提高手機(jī)續(xù)航
這篇文章主要為大家介紹了Android電量?jī)?yōu)化提高你的手機(jī)續(xù)航示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Android編程中ViewPage判斷左右滑動(dòng)方向的方法
這篇文章主要介紹了Android編程中ViewPage判斷左右滑動(dòng)方向的方法,涉及Android中ViewPage針對(duì)滑動(dòng)判定的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-10-10ImageView 實(shí)現(xiàn)Android colorPikcer 選擇器的示例代碼
本篇文章主要介紹了ImageView 實(shí)現(xiàn)Android colorPikcer 選擇器的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-10-10Flutter使用sqflite處理數(shù)據(jù)表變更的方法詳解
了解過數(shù)據(jù)庫(kù)的同學(xué)應(yīng)該會(huì)知道,數(shù)據(jù)表結(jié)構(gòu)是可能發(fā)生改變的。所以本文為大家介紹了Flutter?使用?sqflite?處理數(shù)據(jù)表變更的版本升級(jí)處理方法,感興趣的可以了解一下2023-04-04Kotlin?this關(guān)鍵字的使用實(shí)例詳解
這篇文章主要介紹了Kotlin?this關(guān)鍵字的使用實(shí)例,在Kotlin中,this關(guān)鍵字允許我們引用一個(gè)類的實(shí)例,該類的函數(shù)恰好正在運(yùn)行。此外,還有其他方式可以使this表達(dá)式派上用場(chǎng)2023-02-02使用RecyclerView添加Header和Footer的方法
RecyclerView雖然作為L(zhǎng)istView的替代者有著較好的性能提升,但是ListView的一些常用功能卻沒有提供,比如我們平時(shí)會(huì)經(jīng)常用到的addHeaderView,addFooterView,既然RecyclerView沒有提供這個(gè)方法,我們應(yīng)該如何為列表添加頭部和底部呢,接下來通過本文給大家介紹2016-03-03關(guān)于Android bitmap你不知道的一些事
這篇文章主要為大家詳細(xì)介紹了關(guān)于Android bitmap你不知道的一些事,使用bitmap需要注意的一些細(xì)節(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android仿淘寶view滑動(dòng)至屏幕頂部會(huì)一直停留在頂部的位置
這篇文章主要介紹了Android仿淘寶view滑動(dòng)至屏幕頂部會(huì)一直停留在頂部的位置的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11