搜索
您的当前位置:首页正文

android文本输入框 输入完成自动跳到下一个输入框

来源:二三娱乐

定义文本框 输入完一个自动跳到下一个且获取焦点,当删除一个自动跳到前一个输入框获取焦点  

老规矩来一波效果图:


新建NumberCodeView 继承FrameLayout

public class NumberCodeView extends FrameLayout {

    private static final int[] STATE_NORMAL = {-android.R.attr.state_selected};

    private static final int[] STATE_SELECTED = {android.R.attr.state_selected};

    private static final int DEFAULT_TEXT_COLOR = 0xFFffffff;

    private static final int DEFAULT_TEXT_SIZE = 30;  //dp

    private static final int DEFAULT_FRAME_SIZE = 50;

    private static final int DEFAULT_FRAME_PADDING = 14;

    private static final int DEFAULT_CODE_LENGTH = 4;

    /**

    * 输入View

    */

    private EditText mEditText;

    private int mLastIndex = 0;

    private int mCurIndex = 0;

    private int mCodeLength = 0;

    private Paint mCodeTextPaint;

    private Rect mTextRect;

    private String mCodeText = "";

    private int mFrameSize = -1;

    private int mFramePadding = -1;

    private int mCodeTextColor = -1;

    private int mCodeTextSize = -1;

    private int mNormalId = R.mipmap.verificate_code_normal;

    private int mSelectId = R.mipmap.verificate_code_selected;

    private boolean mShowSystemKeyboard = true;

    private @DrawableRes

    int mFrameDrawableId = -1;

    private SparseArrayCompat<Drawable> mInputDrawable = new SparseArrayCompat<>();

    private InputMethodManager mInputMethodManager;

    private OnNumberInputListener mOnNumberInputListener;

    private TextWatcher mTextWatcher = new TextWatcher() {

        @Override

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override

        public void onTextChanged(CharSequence s, int start, int before, int count) {

            boolean isBack = mCodeText.length() > s.length();

            mLastIndex = mCurIndex;

            if (!TextUtils.isEmpty(s)) {

                mCodeText = s.toString();

                mCurIndex = isBack ? mCodeText.length() - 1 : mCodeText.length();

                mCurIndex = mCurIndex == mCodeLength ? mCurIndex - 1 : mCurIndex;

            } else {

                mCurIndex = 0;

                mCodeText = "";

            }

            setDrawableState(mLastIndex, STATE_NORMAL);

            if (mCodeText.length() == mCodeLength) {

                if (mOnNumberInputListener != null) {

                    mOnNumberInputListener.onInputFinish();

                }

            } else {

                setDrawableState(mCurIndex, STATE_SELECTED);

                if (mOnNumberInputListener != null) {

                    mOnNumberInputListener.onInputIng();

                }

            }

            invalidate();

        }

        @Override

        public void afterTextChanged(Editable s) {

        }

    };

    public NumberCodeView(Context context) {

        this(context, null);

    }

    public NumberCodeView(Context context, AttributeSet attrs) {

        this(context, attrs, 0);

    }

    public NumberCodeView(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        PixelUtil pixelUtil = new PixelUtil(context);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NumberCodeView);

        int size = typedArray.getIndexCount();

        if (size > 0) {

            for (int i = 0; i < size; i++) {

                int attr = typedArray.getIndex(i);

                switch (attr) {

                    case R.styleable.NumberCodeView_codeTextColor:

                        mCodeTextColor = typedArray.getColor(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_codeTextSize:

                        mCodeTextSize = typedArray.getDimensionPixelSize(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_frameSize:

                        mFrameSize = typedArray.getDimensionPixelSize(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_framePadding:

                        mFramePadding = typedArray.getDimensionPixelOffset(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_codeLength:

                        mCodeLength = typedArray.getInt(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_frameDrawableId:

                        mFrameDrawableId = typedArray.getResourceId(attr, -1);

                        break;

                    case R.styleable.NumberCodeView_normal:

                        mNormalId = typedArray.getResourceId(attr, R.mipmap.verificate_code_normal);

                        break;

                    case R.styleable.NumberCodeView_select:

                        mSelectId = typedArray.getResourceId(attr, R.mipmap.verificate_code_selected);

                        break;

                }

            }

        }

        typedArray.recycle();

        if (mCodeTextColor == -1) {

            mCodeTextColor = DEFAULT_TEXT_COLOR;

        }

        if (mCodeTextSize == -1) {

            mCodeTextSize = pixelUtil.dp2px(DEFAULT_TEXT_SIZE);

        }

        if (mFrameSize == -1) {

            mFrameSize = pixelUtil.dp2px(DEFAULT_FRAME_SIZE);

        }

        if (mFramePadding == -1) {

            mFramePadding = pixelUtil.dp2px(DEFAULT_FRAME_PADDING);

        }

        if (mCodeLength <= 0) {

            mCodeLength = DEFAULT_CODE_LENGTH;

        }

        mTextRect = new Rect();

        mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

        initEditText();

        initTextPaint();

        initStateListDrawable();

        setWillNotDraw(false);

    }

    private void initEditText() {

        mEditText = new EditText(getContext());

        mEditText.addTextChangedListener(mTextWatcher);

        mEditText.setCursorVisible(false);

        ViewCompat.setBackground(mEditText, new ColorDrawable(Color.TRANSPARENT));

        mEditText.setTextColor(Color.TRANSPARENT);

        mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mCodeLength)});

        mEditText.setFocusable(true);

        mEditText.requestFocus();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            mEditText.setShowSoftInputOnFocus(true);

        }

        mEditText.setInputType(TYPE_CLASS_NUMBER);

        mEditText.setSingleLine();

        addView(mEditText, new LayoutParams(MATCH_PARENT, MATCH_PARENT));

    }

    /**

    * 是否显示键盘

    *

    * @param showSystemKeyboard true为显示,false为不显示

    */

    public void setShowKeyboard(boolean showSystemKeyboard) {

        if (mShowSystemKeyboard == showSystemKeyboard) return;

        mShowSystemKeyboard = showSystemKeyboard;

        if (mShowSystemKeyboard) {

            mEditText.setInputType(TYPE_CLASS_NUMBER);

        } else {

            mEditText.setInputType(TYPE_NULL);

        }

    }

    public EditText getInputView() {

        return mEditText;

    }

    public void setText(CharSequence text) {

        if (mEditText != null) {

            mEditText.setText(text);

        }

    }

    private void initTextPaint() {

        mCodeTextPaint = new TextPaint();

        mCodeTextPaint.setColor(mCodeTextColor);

        mCodeTextPaint.setAntiAlias(true);

        mCodeTextPaint.setTextSize(mCodeTextSize);

        mCodeTextPaint.setFakeBoldText(true);

        mCodeTextPaint.setTextAlign(Paint.Align.CENTER);

    }

    private Drawable getFrameDrawable() {

        if (mFrameDrawableId == -1) {

            StateListDrawable drawable = new StateListDrawable();

            drawable.addState(STATE_NORMAL, ContextCompat.getDrawable(getContext(), mNormalId));

            drawable.addState(STATE_SELECTED, ContextCompat.getDrawable(getContext(), mSelectId));

            return drawable;

        } else {

            return ContextCompat.getDrawable(getContext(), mFrameDrawableId);

        }

    }

    private void initStateListDrawable() {

        for (int i = 0; i < mCodeLength; i++) {

            mInputDrawable.put(i, getFrameDrawable());

        }

        mCurIndex = mLastIndex = 0;

        setDrawableState(mCurIndex, STATE_SELECTED);

    }

//    private static boolean isAttrPxType(TypedArray typeArray, int index) {

//        return typeArray.peekValue(index).type ==

//    }

    public void setOnNumberInputListener(OnNumberInputListener listener) {

        this.mOnNumberInputListener = listener;

    }

    /**

    * 设置drawable state

    */

    private void setDrawableState(int index, int[] state) {

        if (index < 0 || index > mInputDrawable.size() - 1) return;

        mInputDrawable.get(index).setState(state);

    }

    @Override

    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {

        super.onVisibilityChanged(changedView, visibility);

        if (getVisibility() != VISIBLE) {

            mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);

        }

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec);

        int height = MeasureSpec.getSize(heightMeasureSpec);

        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);

        if (heightSpecMode == MeasureSpec.AT_MOST) {

            height = mFrameSize;

        }

        if (widthSpecMode != MeasureSpec.EXACTLY) {

            width = (mCodeLength * mFrameSize) + (mFramePadding * (mCodeLength - 1));

        }

        int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);

        int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, height);

        mEditText.measure(childWidthSpec, childHeightSpec);

        setMeasuredDimension(width, height);

    }

    public String getInputCode() {

        return mCodeText;

    }

    private String indexOfCode(int index) {

        if (TextUtils.isEmpty(mCodeText)) {

            return "";

        }

        if (index < 0 || index > mCodeText.length() - 1) {

            return "";

        }

        return String.valueOf(mCodeText.charAt(index));

    }

    @Override

    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        int left = 0;

        int right = mFrameSize;

        int size = mInputDrawable.size();

        for (int i = 0; i < size; i++) {

            Drawable drawable = mInputDrawable.get(i);

            drawable.setBounds(left, 0, right, getMeasuredHeight());

            drawable.draw(canvas);

            //绘制文本

            drawCodeText(canvas, drawable.getBounds(), indexOfCode(i));

            left = right + mFramePadding;

            right = left + mFrameSize;

        }

    }

    private void drawCodeText(Canvas canvas, Rect bound, String text) {

        if (!TextUtils.isEmpty(text)) {

            mCodeTextPaint.getTextBounds(text, 0, text.length(), mTextRect);

            canvas.drawText(text, bound.centerX(), bound.height() / 2 + mTextRect.height() / 2, mCodeTextPaint);

        }

    }

    public interface OnNumberInputListener {

        void onInputFinish();

        void onInputIng();

    }

}


 public interface OnNumberInputListener {

        void onInputFinish();

        void onInputIng();

}

该接口有两个方法用来监听输入完成、正在输入


像素转换工具类:PixelUtil

/**

* 像素转换工具类

*/

public class PixelUtil {

    /**

    * The context.

    */

    private Context context;

    public PixelUtil(Context context) {

        this.context = context;

    }

    public static boolean isPxVal(TypedValue val) {

        if (val != null && val.type == TypedValue.TYPE_DIMENSION &&

                getComplexUnit(val.data) == {

            return true;

        }

        return false;

    }

    private static int getComplexUnit(int data) {

        return & (data >>

    }

    /**

    * dpת px.

    *

    * @param value the value

    * @return the int

    */

    public int dp2px(float value) {

        final float density = context.getResources().getDisplayMetrics().density;

        return (int) (value * density + 0.5f);

    }

    /**

    * pxתdp.

    *

    * @param value the value

    * @return the int

    */

    public int px2dp(float value) {

        final float scale = context.getResources().getDisplayMetrics().densityDpi;

        return (int) ((value * 160) / scale + 0.5f);

    }

    /**

    * spתpx.

    *

    * @param value the value

    * @return the int

    */

    public int sp2px(float value) {

        Resources r;

        if (context == null) {

            r = Resources.getSystem();

        } else {

            r = context.getResources();

        }

        float spvalue = value * r.getDisplayMetrics().scaledDensity;

        return (int) (spvalue + 0.5f);

    }

    /**

    * pxתsp.

    *

    * @param value the value

    * @return the int

    */

    public int px2sp(float value) {

        final float scale = context.getResources().getDisplayMetrics().scaledDensity;

        return (int) (value / scale + 0.5f);

    }

    public int width() {

        return context.getResources().getDisplayMetrics().widthPixels;

    }

    public int height() {

        return context.getResources().getDisplayMetrics().heightPixels;

    }

}


attrs.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <declare-styleable name="NumberCodeView">

        <attr name="codeTextColor" format="color|reference" />

        <attr name="codeTextSize" format="reference|dimension" />

        <attr name="frameSize" format="reference|dimension" />

        <attr name="framePadding" format="reference|dimension" />

        <attr name="codeLength" format="integer|reference" />

        <attr name="frameDrawableId" format="reference" />

        <attr name="normal" format="reference" />

        <attr name="select" format="reference" />

    </declare-styleable>

</resources>


Top