最近撸码忙成狗啊,果然从无到有的独立开发不是一般的累啊。。。。 最近公司项目中有一个类似滴滴出行填写验证码的弹框,下面是我撸出来的效果:
中间的那个输入密码的 6 个框框其实就是用 shape 画的背景,通过监听 EditText 获取焦点来改变背景,废话少说,直接上代码吧。
代码内容比较简单,所以大家可以直接看代码
VerificationCodeInput.java
- /**
- * @author hydCoder
- * @date 2017/9/22 14:39
- * @desc 输入验证码的自定义view
- * @email hyd_coder@163.com
- */
- public class VerificationCodeInput extends LinearLayout implements TextWatcher,
- View.OnKeyListener {
- private final static String TYPE_NUMBER = "number";
- private final static String TYPE_TEXT = "text";
- private final static String TYPE_PASSWORD = "password";
- private final static String TYPE_PHONE = "phone";
- private static final String TAG = "VerificationCodeInput";
- private int box = 4;
- private int boxWidth = 80;
- private int boxHeight = 80;
- private int childHPadding = 14;
- private int childVPadding = 14;
- private String inputType = TYPE_NUMBER;
- private Drawable boxBgFocus = null;
- private Drawable boxBgNormal = null;
- private Listener listener;
- private boolean focus = false;
- private List < EditText > mEditTextList = new ArrayList < >();
- private int currentPosition = 0;
- public VerificationCodeInput(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.vericationCodeInput);
- box = a.getInt(R.styleable.vericationCodeInput_box, 4);
- childHPadding = (int) a.getDimension(R.styleable.vericationCodeInput_child_h_padding, 0);
- childVPadding = (int) a.getDimension(R.styleable.vericationCodeInput_child_v_padding, 0);
- boxBgFocus = a.getDrawable(R.styleable.vericationCodeInput_box_bg_focus);
- boxBgNormal = a.getDrawable(R.styleable.vericationCodeInput_box_bg_normal);
- inputType = a.getString(R.styleable.vericationCodeInput_inputType);
- boxWidth = (int) a.getDimension(R.styleable.vericationCodeInput_child_width, boxWidth);
- boxHeight = (int) a.getDimension(R.styleable.vericationCodeInput_child_height, boxHeight);
- initViews();
- }
- @Override protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- }
- @Override protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- }
- private void initViews() {
- for (int i = 0; i < box; i++) {
- EditText editText = new EditText(getContext());
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(boxWidth, boxHeight);
- layoutParams.bottomMargin = childVPadding;
- layoutParams.topMargin = childVPadding;
- layoutParams.leftMargin = childHPadding;
- layoutParams.rightMargin = childHPadding;
- layoutParams.gravity = Gravity.CENTER;
- editText.setOnKeyListener(this);
- if (i == 0) setBg(editText, true);
- else setBg(editText, false);
- editText.setTextColor(Color.BLACK);
- editText.setLayoutParams(layoutParams);
- editText.setGravity(Gravity.CENTER);
- editText.setInputType(EditorInfo.TYPE_CLASS_PHONE);
- editText.setFilters(new InputFilter[] {
- new InputFilter.LengthFilter(1)
- });
- if (TYPE_NUMBER.equals(inputType)) {
- editText.setInputType(InputType.TYPE_CLASS_NUMBER);
- } else if (TYPE_PASSWORD.equals(inputType)) {
- editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
- } else if (TYPE_TEXT.equals(inputType)) {
- editText.setInputType(InputType.TYPE_CLASS_TEXT);
- } else if (TYPE_PHONE.equals(inputType)) {
- editText.setInputType(InputType.TYPE_CLASS_PHONE);
- }
- editText.setId(i);
- editText.setEms(1);
- editText.addTextChangedListener(this);
- addView(editText, i);
- mEditTextList.add(editText);
- }
- }
- private void backFocus() {
- int count = getChildCount();
- EditText editText;
- for (int i = count - 1; i >= 0; i--) {
- editText = (EditText) getChildAt(i);
- if (editText.getText().length() == 1) {
- editText.requestFocus();
- setBg(mEditTextList.get(i), true);
- //setBg(mEditTextList.get(i-1),true);
- editText.setSelection(1);
- return;
- }
- }
- }
- private void focus() {
- int count = getChildCount();
- EditText editText;
- for (int i = 0; i < count; i++) {
- editText = (EditText) getChildAt(i);
- if (editText.getText().length() < 1) {
- editText.requestFocus();
- return;
- }
- }
- }
- private void setBg(EditText editText, boolean focus) {
- if (boxBgNormal != null && !focus) {
- editText.setBackground(boxBgNormal);
- } else if (boxBgFocus != null && focus) {
- editText.setBackground(boxBgFocus);
- }
- }
- private void setBg() {
- int count = getChildCount();
- EditText editText;
- for (int i = 0; i < count; i++) {
- editText = (EditText) getChildAt(i);
- if (boxBgNormal != null && !focus) {
- editText.setBackground(boxBgNormal);
- } else if (boxBgFocus != null && focus) {
- editText.setBackground(boxBgFocus);
- }
- }
- }
- private void checkAndCommit() {
- StringBuilder stringBuilder = new StringBuilder();
- boolean full = true;
- for (int i = 0; i < box; i++) {
- EditText editText = (EditText) getChildAt(i);
- String content = editText.getText().toString();
- if (content.length() == 0) {
- full = false;
- break;
- } else {
- stringBuilder.append(content);
- }
- }
- if (full) {
- if (listener != null) {
- listener.onComplete(stringBuilder.toString());
- setEnabled(false);
- }
- }
- }
- @Override public void setEnabled(boolean enabled) {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.setEnabled(enabled);
- }
- }
- public void setOnCompleteListener(Listener listener) {
- this.listener = listener;
- }
- @Override
- public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new LinearLayout.LayoutParams(getContext(), attrs);
- }
- @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
- }
- if (count > 0) {
- View child = getChildAt(0);
- int cHeight = child.getMeasuredHeight();
- int cWidth = child.getMeasuredWidth();
- int maxH = cHeight + 2 * childVPadding;
- int maxW = (cWidth + childHPadding) * box + childHPadding;
- setMeasuredDimension(resolveSize(maxW, widthMeasureSpec), resolveSize(maxH, heightMeasureSpec));
- }
- }
- @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.setVisibility(View.VISIBLE);
- int cWidth = child.getMeasuredWidth();
- int cHeight = child.getMeasuredHeight();
- int cl = (i) * (cWidth + childHPadding);
- int cr = cl + cWidth;
- int ct = childVPadding;
- int cb = ct + cHeight;
- child.layout(cl, ct, cr, cb);
- }
- }
- @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
- @Override public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (start == 0 && count >= 1 && currentPosition != mEditTextList.size() - 1) {
- currentPosition++;
- mEditTextList.get(currentPosition).requestFocus();
- setBg(mEditTextList.get(currentPosition), true);
- setBg(mEditTextList.get(currentPosition - 1), false);
- }
- }
- @Override public void afterTextChanged(Editable s) {
- if (s.length() == 0) {} else {
- focus();
- checkAndCommit();
- }
- }
- @Override public boolean onKey(View view, int keyCode, KeyEvent event) {
- EditText editText = (EditText) view;
- if (keyCode == KeyEvent.KEYCODE_DEL && editText.getText().length() == 0) {
- int action = event.getAction();
- if (currentPosition != 0 && action == KeyEvent.ACTION_DOWN) {
- currentPosition--;
- mEditTextList.get(currentPosition).requestFocus();
- setBg(mEditTextList.get(currentPosition), true);
- setBg(mEditTextList.get(currentPosition + 1), false);
- mEditTextList.get(currentPosition).setText("");
- }
- }
- return false;
- }
- public interface Listener {
- void onComplete(String content);
- }
} ··· styles.xml 里添加自定义属性
- <declare-styleable name="vericationCodeInput">
- <attr name="box" format="integer" />
- <attr name="child_h_padding" format="dimension" />
- <attr name="child_v_padding" format="dimension" />
- <attr name="child_width" format="dimension" />
- <attr name="child_height" format="dimension" />
- <attr name="padding" format="dimension" />
- <attr name="box_bg_focus" format="reference" />
- <attr name="box_bg_normal" format="reference" />
- <attr name="inputType" format="string" />
- </declare-styleable>
输入框获取焦点时的背景
verification_edit_bg_focus.xml
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="#FFFFFF" />
- <corners android:radius="8dip" />
- <stroke
- android:width="2dip"
- android:color="@color/auxiliary_color" />
- </shape>
输入框没有获取焦点时的背景
verification_edit_bg_normal.xml
- <?xml version="1.0" encoding="utf-8"?>
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/white" />
- <corners android:radius="8dip" />
- <stroke
- android:width="1dip"
- android:color="@color/divide_color"/>
- </shape>
在界面中使用
- <com.sdalolo.genius.ui.view.VerificationCodeInput
- android:digits="1234567890"
- android:id="@+id/verificationCodeInput"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="25dp"
- android:layout_gravity="center_horizontal"
- ver:box="6"
- ver:box_bg_normal="@drawable/verification_edit_bg_normal"
- ver:box_bg_focus="@drawable/verification_edit_bg_focus"
- ver:child_h_padding="5dp"
- android:layout_centerInParent="true"
- android:layout_marginBottom="16dp"/>
然后对它设置输入完成后的监听
- verificationCodeInput.setOnCompleteListener(new VerificationCodeInput.Listener() {
- @Override
- public void onComplete(String content) {
- btn_confirm.setEnabled(true);
- btn_confirm.setBackgroundResource(R.drawable.btn_bg_shape_enable);
- btn_confirm.setTextColor(Color.parseColor("#e4c16a"));
- codeNum = content;
- }
- });
到这里就可以完成和滴滴出行类似的效果了,是不是很简单,如果你刚好有需要,直接拷过去用吧!
来源: https://juejin.im/post/5a30dca9f265da431c704bd3