700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android验证码输入框支持粘贴

Android验证码输入框支持粘贴

时间:2019-11-28 20:30:23

相关推荐

Android验证码输入框支持粘贴

验证码输入框,满足剪切板内容自动填充,看效果

原本做法是6个EditText,后来发现,这样写最大问题是,无法满足粘贴功能,验证码短信 一般都带“复制”,点击 短信通知栏 的“复制”后,6位验证码会自动显示在软键盘左上角,点击一下即完成填充。

如果牺牲掉了验证码“通知栏短信-复制-点击填充”功能 ,用户必须一次性记住6位,逐个输入;若是用户习惯性点击了复制后,发现app竟然无法填充,自己也没记验证码,再次下拉看通知栏看短信时,发现通知栏短信也没了,就必须要回到短信收件箱里查找,这种用户体验,WTF,狠操蛋!!!一定要规避这种打破用户操作习惯,引起用户不爽的细节。

先聊聊思路:

1.首先想到 写一个EditText,然后setBackground()为6个框,字间距刚好让每个数字处于框中间;然而字间距的方法没找到合适的,全部是按比例分间距的,累觉不爱,适配是个巨坑,前路艰险,性价比太低,放弃之。

2.我打开滴滴,美团,结果大厂的复制粘贴各种花式bug啪啪打脸,就不一一拉出来细评了。

3.功夫不负有心人,终于找到一个支持粘贴的app—建设银行,尽管被我测出了bug,也给我启发,让我看出了端倪。

看到上图我猜想,蓝色水滴中间才是全部编辑框字体,于是我剪切,结果正如我所料,框内字体被清除了,并且无论我如何点击,双击,长按最后一个框,光标始终在第二个框里跳动。

于是,我有思路了,所有的框就是TextView,而真正的编辑框内容是透明的。为了点击最后一个框也能唤起软键盘,需要让EditText的宽度与六个框一样宽;

建行app 有个缺点就是 光标可以随着手势左右滑动游走,怎么避免呢,

第一道防线:EditText.setTextSize(0.01f),即便不小心弹出选中操作框,字体足够小,小到可以避免光标随手势左右游走,精度层避免该现象,当然这只是补救措施,根本杜绝的话,需要避免选中操作框弹出;第二道防线:屏蔽长按事件避免出现“剪切,复制,粘贴”的那个系统选项框;第三道防线:屏蔽双击事件,经测小米、华为等手机,双击和长按都会弹出“剪切,复制,粘贴”系统选项框,宜将剩勇追穷寇,务必赶尽杀绝。

实现功能:

1.点短信复制后,支持剪切板自动填充,即粘贴;

2.屏蔽长按粘贴,和双击选中;

3.输入完成回调;

4.根据屏幕宽度和左右间距 自动适配 输入方框大小

明显缺点

此种情况下,无法显示光标,暂时没有想到简单易行的解决办法,如有思路,求评论区赐教。

上代码吧:

/*** Created by @author iblade.Wang on /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.selector_bg_edit);inputType = ta.getInt(R.styleable.VerCodeInputView_inputType, InputType.TYPE_CLASS_NUMBER);ta.recycle();textViewList = new ArrayList<>(inputNum);initViews();}private List<TextView> textViewList;private EditText editText;private void initViews() {textViewList.clear();//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 不设置marginparams.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);if (i == 0) textView.setSelected(true);//默认首个方框选中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.01f);//设置透明光标,如果直接不显示光标的话,长按粘贴会没效果try {Field f = TextView.class.getDeclaredField("mCursorDrawableRes");f.setAccessible(true);f.set(editText, R.drawable.edit_cursor_bg_transparent);} catch (Exception e) {e.printStackTrace();}editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputNum)});editText.setInputType(inputType);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() {@Overridepublic boolean onDoubleTap(MotionEvent e) {return true;}});}private TextWatcher textWatcher = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable editable) {String inputContent = (null == editText.getText()) ? "" : editText.getText().toString();//已经有输入时,屏蔽长按和光标if (inputContent.length() > 0) {editText.setLongClickable(false);editText.setCursorVisible(false);} else {editText.setLongClickable(true);editText.setCursorVisible(true);}if (listener != null && inputContent.length() >= inputNum) {listener.onComplete(inputContent);}for (int i = 0, len = textViewList.size(); i < len; i++) {TextView textView = textViewList.get(i);textView.setSelected(false);if (i < inputContent.length()) {textView.setText(String.valueOf(inputContent.charAt(i)));} else {textView.setText("");//选中待输入的textViewif (i == inputContent.length()) {textView.setSelected(true);}}}}};private boolean isAuto = false;/*** 设置宽高自适应,单个框的宽度平分父布局总宽度*/public void setAutoWidth() {isAuto = true;requestLayout();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = getMeasuredWidth();if (isAuto && width > 0) {isAuto = false;//resetWH(width);resetMargin(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;}*/private void resetMargin(int width) {if (width > 0) {int remainWidth = width - (inputNum * inputWidth);if (remainWidth > 0 && inputNum > 1) {childPadding = remainWidth / (inputNum - 1);for (int i = 0, len = textViewList.size(); i < len; i++) {View child = textViewList.get(i);LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();if (i != inputNum - 1) {//最后一个textView 不设置marginparams.rightMargin = childPadding;}params.gravity = Gravity.CENTER;child.setLayoutParams(params);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);}}

res/values/attrs.xml中添加如下代码:

<declare-styleable name="VerCodeInputView"><attr name="inputNum" format="integer" /><attr name="inputWidth" format="dimension" /><attr name="inputHeight" format="dimension" /><attr name="inputPadding" format="dimension" /><attr name="inputTxtColor" format="color|reference" /><attr name="errorTxtColor" format="color|reference" /><attr name="inputTxtSize" format="integer" /><attr name="inputBg" format="reference" /><attr name="inputType"><enum name="number" value="0x00000002" /><enum name="text" value="0x00000001" /><enum name="phone" value="0x00000003" /><enum name="password" value="0x00000080" /></attr></declare-styleable>

如何调用:

/*** @author YlWang*/public class MainActivity extends AppCompatActivity {private VerCodeInputView codeInputCard;@Overrideprotected 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() {@Overridepublic void onComplete(String content) {Toast.makeText(MainActivity.this, "您输入了:" + content, Toast.LENGTH_LONG).show();}});}}

另外,框框背景drawable目录下 bg_edit_vercode.xml

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="/apk/res/android"><item android:state_selected="true"><shape android:shape="rectangle"><solid android:color="@color/color_ffffff" /><stroke android:width="@dimen/dp_05" android:color="@color/color_00b38a" /></shape></item><item android:state_selected="false"><shape android:shape="rectangle"><solid android:color="@color/color_ffffff" /><stroke android:width="@dimen/dp_05" android:color="@color/color_dfdfdf" /></shape></item></selector>

------------------------------.4.10更新-----------------------

经测试Vivo,华为部分机型 不会把复制短信的内容呈现在软键盘上方,复制完之后,想粘贴有两种办法:①需要资深玩家在软键盘里找到粘贴按键(缺点:操作麻烦),②大家习惯的长按出现粘贴;

然鹅。。。上面代码又把长按屏蔽了。哎~心塞塞!!!

继续优化:

我们期待长按后出现这种:

可是一旦不屏蔽长按,恶魔放出了瓶子;

例如:

有坑警告:为了满足长按出现粘贴,删除editText.setLongClickable(false);,长按了好久了,不出现粘贴;同步代码,Clean,Rebuild,各种大动作,仍然长按无效;

抱着没啥希望的心态 加上editText.setLongClickable(true)再试一把,果然没希望,还是长按无效。

WHY?

经测删除editText.setCursorVisible(false);再试,长按终于出粘贴了。

结论:设置光标不可见时,长按将会无效。

为了满足长按可用,只好设置光标可见,大不了颜色设成透明的(效果上等同于设置不可见)。

上图蓝色圆球和一大串操作栏好丑,坚决不能出现,那就不得不动态设置了:

例如不输入内容时,不屏蔽长按;一旦有了输入内容后,屏蔽长按,设置光标不可见,这样就不会出现了,所以修改后代码是这样的。

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 不设置marginparams.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.01f);//设置透明光标,如果直接不显示光标的话,长按粘贴会没效果try {Field f = TextView.class.getDeclaredField("mCursorDrawableRes");f.setAccessible(true);f.set(editText, R.drawable.edit_cursor_bg_transparent);} catch (Exception e) {e.printStackTrace();}editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputNum)});editText.setInputType(inputType);editText.setTextColor(ContextCompat.getColor(getContext(), R.color.transparent));editText.setBackground(null);editText.addTextChangedListener(textWatcher);addView(editText);initListener();}

@Overridepublic void afterTextChanged(Editable editable) {String inputContent = (null == editText.getText()) ? "" : editText.getText().toString();//已经有输入时,屏蔽长按和光标if (inputContent.length() > 0) {editText.setLongClickable(false);editText.setCursorVisible(false);} else {editText.setLongClickable(true);editText.setCursorVisible(true);}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("");}}}

其中:edit_cursor_bg_transparent.xml

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="/apk/res/android"android:shape="rectangle"><size android:width="0.01dp" /><solid android:color="@android:color/transparent" /></shape>

.04.26更新,加上了 待输入方框的选中色。效果如下:

最近发现有同行也做了类似需求:/p/3238a5afc21c

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。