我先贴出图:
这是我从一篇博客里面的demo里面抠出来的,然后使用起来比较方便:
public class SecurityCodeView extends RelativeLayout {
private LinearLayout containerEt;
private EditText et;
// 输入框数量
private int mEtNumber;
// 输入框的宽度
private int mEtWidth;
//输入框分割线
private Drawable mEtDividerDrawable;
//输入框文字颜色
private int mEtTextColor;
//输入框文字大小
private float mEtTextSize;
//输入框获取焦点时背景
private Drawable mEtBackgroundDrawableFocus;
// 输入框没有焦点时背景
private Drawable mEtBackgroundDrawableNormal;
//存储TextView的数据 数量由自定义控件的属性传入
private TextView[] mTextViews;
public SecurityCodeView(Context context) {
this(context, null);
}
public SecurityCodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SecurityCodeView(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.SecurityCodeView, defStyleAttr, 0);
mEtNumber = typedArray.getInteger(R.styleable.SecurityCodeView_icv_et_number, 1);
mEtWidth = typedArray.getDimensionPixelSize(R.styleable.SecurityCodeView_icv_et_width, 42);
mEtDividerDrawable = typedArray.getDrawable(R.styleable.SecurityCodeView_icv_et_divider_drawable);
mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.SecurityCodeView_icv_et_text_size, 16);
mEtTextColor = typedArray.getColor(R.styleable.SecurityCodeView_icv_et_text_color, Color.WHITE);
mEtBackgroundDrawableFocus = typedArray.getDrawable(R.styleable.SecurityCodeView_icv_et_bg_focus);
mEtBackgroundDrawableNormal = typedArray.getDrawable(R.styleable.SecurityCodeView_icv_et_bg_normal);
//释放资源
typedArray.recycle();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
initTextViews(getContext(), mEtNumber, mEtWidth, mEtDividerDrawable, mEtTextSize, mEtTextColor);
initEtContainer(mTextViews);
setListener();
}
//初始化TextView
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.setBackground(mEtBackgroundDrawableFocus);
// textView.setBackgroundDrawable(mEtBackgroundDrawableFocus);
} else {
textView.setBackground(mEtBackgroundDrawableNormal);
// textView.setBackgroundDrawable(mEtBackgroundDrawableNormal);
}
textView.setGravity(Gravity.CENTER);
textView.setFocusable(false);
mTextViews[i] = textView;
}
}
//初始化存储TextView 的容器
private void initEtContainer(TextView[] mTextViews) {
for (int i = 0; i < mTextViews.length; i++) {
containerEt.addView(mTextViews[i]);
}
}
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) {
//这个afterTextChanged只会在新增的时候被调
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) {
Log.i("cy==View", 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.setBackground(mEtBackgroundDrawableNormal);
if (i < mEtNumber - 1) {
mTextViews[i + 1].setBackground(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.setBackground(mEtBackgroundDrawableFocus);
if (i < mEtNumber - 1) {
mTextViews[i + 1].setBackground(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();
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<********SecurityCodeView
android:id="@+id/icv"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="26dp"
app:icv_et_bg_focus="@drawable/shape_icv_et_bg_focus"
app:icv_et_bg_normal="@drawable/shape_icv_et_bg_normal"
app:icv_et_divider_drawable="@drawable/shape_divider_identifying"
app:icv_et_number="4"
app:icv_et_text_color="#000000"
app:icv_et_width="60dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:onClick="onClick"
android:text="清空" />
</LinearLayout>
里面的自定义属性解释如下:
(1)icv_et_with 是单个框的宽度
(2)icv_et_bg_focus是选中的时候框的background
(3)icv_et_bg_normal 是没有被选中的框的bg
(4)icv_et_num 是多少个框
(5)icv_et_text_color 是框里面数字的颜色
(6)icv_et_divider_drawable 是两个框之间的view,你看起来试空白的,其实是一个view,你可以写一个不是透明的shape试试就知道了
我这里贴出几个bg:
被选中的框的bg:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F2F2F2" />
<!-- 大小 -->
<size
android:width="25dp"
android:height="25dp" /><!-- 宽度和高度 -->
<corners android:radius="2dp" />
<stroke
android:width="1dp"
android:color="#A6D8EB" />
</shape>
框正常的bg:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F2F2F2" />
<!-- 大小 -->
<size
android:width="25dp"
android:height="25dp" /><!-- 宽度和高度 -->
<corners android:radius="2dp" />
<stroke
android:width="1dp"
android:color="#C7C7CD" />
</shape>
divider的bg:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size
android:width="6dp"
android:height="6dp" />
<solid android:color="#0000" />
</shape>
自定义属性的xml,在res/values/attrs.xml里面:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 自定义验证码输入框-->
<declare-styleable name="SecurityCodeView">
<!--输入框的数量-->
<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>
</resources>
在acrtivity中的使用:
private SecurityCodeView icv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
icv = (SecurityCodeView) findViewById(R.id.icv);
icv.setInputCompleteListener(new SecurityCodeView.InputCompleteListener() {
@Override
public void inputComplete() {
Log.i("icv_input", icv.getTextContent());
}
@Override
public void deleteContent() {
Log.i("icv_delete", icv.getTextContent());
}
});
}
public void onClick(View view) {
icv.clearAllText();
}