Android 自定义View之正方形验证码输入框
来源:互联网 发布:大数据和java的关系 编辑:程序博客网 时间:2024/06/07 02:48
友情提示 该项目已在github开源,解决所有bug,也有更新计划,具体请看 README
概述:先描述一下具体需求吧,我们在项目中可能会遇到修改用户名及密码的需求,为保证一定的完全性,服务端一般会接入短信验证码的功能。我们需要将接受到的验证码返回给服务端进行验证。可能会有以下的界面让用户输入验证码:
那么此时我们就需要用自定义控件去实现我们的需求了。源码下载
一 分析
在安卓开发中,实现自定义控件的方式有三种,继承控件,组合控件,自绘控件。现在我们需要通过分析决定使用哪种方式。首先我们需要有输入事件,那么我们肯定是需要有EditText控件的。其次我们用需要显示验证码。我们需要显示文本的控件TextView。那么很明显了,我们需要使用组合控件的方式来实现我们的需求。
二 思路
我们需要通过EditText控件接受我们的输入,界面中明显是不能看到这个控件的,所以我们需要将这个控件给设置透明。然后将接受到的输入内容设置给我们的TextView。为了满足正方形的样式,只需要给TextView设置一个背景即可。在开发过程中,我们发现验证码的个数不是固定的,有4位数的,也有6位数的。为了实现低耦合的复用性。我们需要一个自定义的属性来满足这个要求。其他具体的思路将会在具体实现的时候讲。
三 实现
(1)组合控件的布局实现
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/container_et" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerInParent="true" android:gravity="center_vertical" android:orientation="horizontal" android:showDividers="middle"> </LinearLayout> <EditText android:id="@+id/et" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:inputType="number" /></RelativeLayout>
这的LinearLayout用来存放TextVeiw ,android:showDividers=”middle”来设定我们的间隔的方式。
(2)设计自定义属性
<!-- 自定义验证码输入框--> <declare-styleable name="IdentifyingCodeView"> <!--输入框的数量--> <attr name="icv_et_number" format="integer" /> <!--输入框的宽度--> <attr name="icv_et_width" format="dimension|reference" /> <!--输入框之间的分割线--> <attr name="icv_et_divider_drawable" format="reference" /> <!--输入框文字颜色--> <attr name="icv_et_text_color" format="color|reference" /> <!--输入框文字大小--> <attr name="icv_et_text_size" format="dimension|reference" /> <!--输入框获取焦点时边框--> <attr name="icv_et_bg_focus" format="reference" /> <!--输入框没有焦点时边框--> <attr name="icv_et_bg_normal" format="reference" /> </declare-styleable>
注释已经很清楚了,就不再解释了。
(3)获取自定义属性
public class IdentifyingCodeView extends RelativeLayout public IdentifyingCodeView(Context context) { this(context, null); } public IdentifyingCodeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IdentifyingCodeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); } //初始化 布局和属性 private void init(Context context, AttributeSet attrs, int defStyleAttr) { LayoutInflater.from(context).inflate(R.layout.layout_identifying_code, this); containerEt = (LinearLayout) this.findViewById(R.id.container_et); et = (EditText) this.findViewById(R.id.et); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IdentifyingCodeView, defStyleAttr, 0); mEtNumber = typedArray.getInteger(R.styleable.IdentifyingCodeView_icv_et_number, 1); count = mEtNumber; mEtWidth = typedArray.getDimensionPixelSize(R.styleable.IdentifyingCodeView_icv_et_width, 42); mEtDividerDrawable = typedArray.getDrawable(R.styleable.IdentifyingCodeView_icv_et_divider_drawable); mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.IdentifyingCodeView_icv_et_text_size, 16); mEtTextColor = typedArray.getColor(R.styleable.IdentifyingCodeView_icv_et_text_color, Color.WHITE); mEtBackgroundDrawableFocus = typedArray.getDrawable(R.styleable.IdentifyingCodeView_icv_et_bg_focus); mEtBackgroundDrawableNormal = typedArray.getDrawable(R.styleable.IdentifyingCodeView_icv_et_bg_normal); //释放资源 typedArray.recycle(); }
(4)在 onFinishInflate 方法中进行逻辑实现
① 初始化 TextView
initTextViews(getContext(), mEtNumber, mEtWidth, mEtDividerDrawable, mEtTextSize, mEtTextColor);private void initTextViews(Context context, int etNumber, int etWidth, Drawable etDividerDrawable, float etTextSize, int etTextColor) { // 设置 editText 的输入长度 //将光标隐藏 et.setCursorVisible(false); //最大输入长度 et.setFilters(new InputFilter[]{new InputFilter.LengthFilter(etNumber)}); // 设置分割线的宽度 if (etDividerDrawable != null) { etDividerDrawable.setBounds(0, 0, etDividerDrawable.getMinimumWidth(), etDividerDrawable.getMinimumHeight()); containerEt.setDividerDrawable(etDividerDrawable); } mTextViews = new TextView[etNumber]; for (int i = 0; i < mTextViews.length; i++) { TextView textView = new EditText(context); textView.setTextSize(etTextSize); textView.setTextColor(etTextColor); textView.setWidth(etWidth); textView.setHeight(etWidth); if (i == 0) { textView.setBackgroundDrawable(mEtBackgroundDrawableFocus); } else { textView.setBackgroundDrawable(mEtBackgroundDrawableNormal); } textView.setGravity(Gravity.CENTER); textView.setFocusable(false); mTextViews[i] = textView; } }
这里动态生成TextView 具体实现 注释很清楚,需要注意一点的是 textView.setFocusable(false); 不然在页面中TextView会获取焦点有一个 光标。用一个数组来存放 TextView。
② 填充盛放TextView的 LinerLayout
initEtContainer(mTextViews);//初始化存储TextView 的容器private void initEtContainer(TextView[] mTextViews) { for (int i = 0; i < mTextViews.length; i++) { containerEt.addView(mTextViews[i]); }}
③ 处理我们的输入事件
setListener(); private void setListener() { // 监听输入内容 et.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) { String inputStr = editable.toString(); if (inputStr != null && !inputStr.equals("")) { setText(inputStr); et.setText(""); } } }); // 监听删除按键 et.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { onKeyDelete(); return true; } return false; } }); } // 给TextView 设置文字 public void setText(String inputContent) { for (int i = 0; i < mTextViews.length; i++) { TextView tv = mTextViews[i]; if (tv.getText().toString().trim().equals("")) { tv.setText(inputContent); // 添加输入完成的监听 if (inputCompleteListener != null) { inputCompleteListener.inputComplete(); } tv.setBackgroundDrawable(mEtBackgroundDrawableNormal); if (i < mEtNumber - 1) { mTextViews[i + 1].setBackgroundDrawable(mEtBackgroundDrawableFocus); } break; } } } // 监听删除 public void onKeyDelete() { for (int i = mTextViews.length - 1; i >= 0; i--) { TextView tv = mTextViews[i]; if (!tv.getText().toString().trim().equals("")) { tv.setText(""); // 添加删除完成监听 if (inputCompleteListener != null) { inputCompleteListener.deleteContent(); } tv.setBackgroundDrawable(mEtBackgroundDrawableFocus); if (i < mEtNumber - 1) { mTextViews[i + 1].setBackgroundDrawable(mEtBackgroundDrawableNormal); } break; } } }
代码都很简洁明了 就不一一说明了
④ 提供给外界的方法
/** * 获取输入文本 * * @return */ public String getTextContent() { StringBuffer buffer = new StringBuffer(); for (TextView tv : mTextViews) { buffer.append(tv.getText().toString().trim()); } return buffer.toString(); } /** * 删除所有内容 */ public void clearAllText() { for (int i = 0; i < mTextViews.length; i++) { if (i == 0) { mTextViews[i].setBackgroundDrawable(mEtBackgroundDrawableFocus); } else { mTextViews[i].setBackgroundDrawable(mEtBackgroundDrawableNormal); } mTextViews[i].setText(""); } } /** * 获取输入的位数 * * @return */ public int getTextCount() { return mEtNumber; } // 输入完成 和 删除成功 的监听 private InputCompleteListener inputCompleteListener; public void setInputCompleteListener(InputCompleteListener inputCompleteListener) { this.inputCompleteListener = inputCompleteListener; } public interface InputCompleteListener { void inputComplete(); void deleteContent(); }
四 效果
是不是棒棒哒 ,其中在逻辑实现过程中,代码和思路都非常的简洁明了。源码下载 GitHub地址
阅读全文
3 1
- Android 自定义View之正方形验证码输入框
- Android自定义View实现滴滴验证码输入框效果
- 自定义View-输入验证码
- Android自定义View之密码输入框
- android自定义view之刷新验证码
- Android从零开搞系列:自定义View(16)自定义验证码输入框效果
- Android 自定义View (验证码)
- Android自定义数字验证码输入框
- Android自定义View之金额输入EditText
- Android 自定义View之随机生成图片验证码
- 【Android自定义View实战】之获取验证码倒计时按钮
- Android自定义View入门之简单验证码控件
- Android 自定义View之随机生成图片验证码
- 自定义view之支付密码输入框
- 自定义View初学笔记之验证码
- 自定义View学习之验证码
- Android自定义View--验证码控件
- Android自定义View(一)(验证码)
- 初学Redis(4)——简单实现Redis缓存中的排序功能
- 雇佣问题
- 点击图片弹出页面效果常用代码
- position:absolute后设置left:50%发生的有趣小事
- 搜索-P
- Android 自定义View之正方形验证码输入框
- solr spellcheck 距离选取方案
- Java Maven项目之Nexus私服搭建和版本管理应用
- C#中Struct与Class的区别
- 个人学习java的真实经验!
- 安卓5.0 Transitions动画切换时状态栏不参与动画
- 用a链接实现跳转至本页面或另一个页面的某个部分
- NAT技术与代理服务器
- java学习一定要掌握静态方法和属性