Android驗證碼輸入框支持粘貼

驗證碼輸入框,滿足剪切板內容自動填充,看效果
在這裏插入圖片描述
原本做法是6個EditText,後來發現,這樣寫最大問題是,無法滿足粘貼功能,驗證碼短信 一般都帶“複製”,如果犧牲掉了驗證碼粘貼功能 確實有點操蛋。

先聊聊思路:
1.首先想到 寫一個EditText,然後setBackground()爲6個框,字間距剛好讓每個數字處於框中間;然而字間距的方法沒找到合適的,此路不通。
2.我打開滴滴,美團,結果大廠的複製粘貼各種花式bug啪啪打臉。
3.功夫不負有心人,終於找到一個支持粘貼的app—建設銀行,儘管被我測出了bug,也給我思路,讓我看出了端倪。
在這裏插入圖片描述

看到上圖我猜想,藍色水滴中間纔是全部編輯框字體,於是我剪切,結果正如我所料,框內字體被清除了,並且無論我點擊最後一個框,光標始終在第二個框裏跳動。
於是,我有思路了,所有的框就是TextView,而真正的編輯框內容是透明的。爲了點擊最後一個框也能喚起軟鍵盤,需要讓EditText的寬度與六個框一樣寬;

建行app 有個缺點就是 光標可以遊走,怎麼避免呢,EditText.setTextSize(0.01f);

上代碼吧:

/**
 * Created by @author iblade.Wang on 2019/4/4.
 * 驗證碼輸入框
 * EditText字號極小,且顏色透明
 */

public class VerCodeInputView extends FrameLayout {
    /**
     * 輸入框個數
     */
    private int inputNum;
    /**
     * 輸入框寬度
     */
    private int inputWidth;
    private int inputHeight;
    /**
     * 輸入框之間的間隔
     */
    private int childPadding;
    /**
     * 輸入框背景
     */
    private int editTextBg;
    /**
     * 文本顏色
     */
    private int textColor;
    /**
     * 文本字體大小
     */
    private int textSize;
    /**
     * 輸入類型
     */
    private int inputType;


    public VerCodeInputView(Context context) {
        this(context, null);
    }

    public VerCodeInputView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerCodeInputView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VerCodeInputView, defStyleAttr, 0);
        inputNum = ta.getInteger(R.styleable.VerCodeInputView_inputNum, 6);
        inputWidth = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputWidth, DensityUtil.dip2px(context, 43));
        inputHeight = inputWidth;
        childPadding = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputPadding, DensityUtil.dip2px(context, 7.5f));
        textColor = ta.getColor(R.styleable.VerCodeInputView_inputTxtColor, Color.parseColor("#333333"));
        textSize = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputTxtSize, 24);
        editTextBg = ta.getResourceId(R.styleable.VerCodeInputView_inputBg, R.drawable.bg_edit_vercode);
        inputType = ta.getInt(R.styleable.VerCodeInputView_inputType, InputType.TYPE_CLASS_NUMBER);
        ta.recycle();
        this.initViews();
    }

    private List<TextView> textViewList;
    private EditText editText;

    private void initViews() {
        textViewList = new ArrayList<>(inputNum);
        LinearLayout llTextViewRoot = new LinearLayout(getContext());
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        llTextViewRoot.setLayoutParams(layoutParams);
        llTextViewRoot.setOrientation(LinearLayout.HORIZONTAL);
        addView(llTextViewRoot);
        for (int i = 0; i < inputNum; i++) {
            TextView textView = new TextView(getContext());
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(inputWidth, inputHeight);
            if (i != inputNum - 1) {//最後一個textView 不設置margin
                params.rightMargin = childPadding;
            }
            params.gravity = Gravity.CENTER;
            textView.setLayoutParams(params);
            textView.setTextColor(textColor);
            textView.setTextSize(textSize);
            textView.setGravity(Gravity.CENTER);
            textView.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
            textView.setInputType(inputType);
            textView.setBackgroundResource(editTextBg);
            textView.setId(i);
            llTextViewRoot.addView(textView);
            textViewList.add(textView);
        }
        editText = new EditText(getContext());
        LayoutParams layoutParam2 = new LayoutParams(LayoutParams.MATCH_PARENT, inputHeight);
        editText.setLayoutParams(layoutParam2);
        editText.setTextSize(0.1f);
        editText.setCursorVisible(false);
        editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputNum)});
        //屏蔽長按
        editText.setLongClickable(false);
        editText.setTextColor(ContextCompat.getColor(getContext(), R.color.transparent));
        editText.setBackground(null);
        editText.addTextChangedListener(textWatcher);
        addView(editText);
        initListener();
    }

    private void initListener() {
        //屏蔽雙擊: 好多手機雙擊會出現 選擇 剪切 粘貼 的選項卡,
        new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                return true;
            }
        });
    }


    private TextWatcher textWatcher = 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) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            String inputContent = editText.getText().toString();
            if (listener != null && inputContent.length() >= inputNum) {
                listener.onComplete(inputContent);
            }
            for (int i = 0, len = textViewList.size(); i < len; i++) {
                TextView textView = textViewList.get(i);
                if (i < inputContent.length()) {
                    textView.setText(String.valueOf(inputContent.charAt(i)));
                } else {
                    textView.setText("");
                }
            }
        }
    };

    private boolean isAuto = false;

    /**
     * 設置寬高自適應,單個框的寬度平分父佈局總寬度
     */
    public void setAutoWidth() {
        isAuto = true;
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        if (isAuto && width != 0) {
            isAuto = false;
            resetWH(width);
        }
    }

    private void resetWH(int w) {
        int paddings = childPadding * (inputNum - 1);
        inputWidth = (w - paddings) / (inputNum);
        inputHeight = inputWidth;
        for (int i = 0, len = textViewList.size(); i < len; i++) {
            View child = textViewList.get(i);
            child.getLayoutParams().height = inputHeight;
            child.getLayoutParams().width = inputWidth;
        }
        editText.getLayoutParams().height = inputHeight;
    }

    /**
     * 獲取編輯框內容
     *
     * @return 編輯框內容
     */
    public String getEditContent() {
        return editText.getText().toString();
    }

    public OnCompleteListener listener;

    public void setOnCompleteListener(OnCompleteListener listener) {
        this.listener = listener;
    }

    public interface OnCompleteListener {
        /**
         * 完成驗證碼的填寫
         *
         * @param content 填寫內容
         */
        void onComplete(String content);
    }

}

如何調用:

/**
 * @author YlWang
 */
public class MainActivity extends AppCompatActivity {
    private VerCodeInputView codeInputCard;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }


    private void initView() {
        codeInputCard = findViewById(R.id.edit);
        codeInputCard.setAutoWidth();
        codeInputCard.setOnCompleteListener(new VerCodeInputView.OnCompleteListener() {
            @Override
            public void onComplete(String content) {
                Toast.makeText(MainActivity.this, "您輸入了:" + content, Toast.LENGTH_LONG).show();
            }
        });

    }
}

最近發現有同行也做了類似需求:https://www.jianshu.com/p/3238a5afc21c

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章