Android验证码输入框支持粘贴 您所在的位置:网站首页 android复制粘贴怎么设置 Android验证码输入框支持粘贴

Android验证码输入框支持粘贴

2024-07-10 19:30| 来源: 网络整理| 查看: 265

验证码输入框,满足剪切板内容自动填充,看效果 在这里插入图片描述 原本做法是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 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.selector_bg_edit); inputType = ta.getInt(R.styleable.VerCodeInputView_inputType, InputType.TYPE_CLASS_NUMBER); ta.recycle(); textViewList = new ArrayList(inputNum); initViews(); } private List 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 //最后一个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); 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() { @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 = (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 textView.setText(String.valueOf(inputContent.charAt(i))); } else { textView.setText(""); //选中待输入的textView if (i == inputContent.length()) { textView.setSelected(true); } } } } }; 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); 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 //最后一个textView 不设置margin params.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中添加如下代码:

如何调用:

/** * @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(); } }); } }

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

------------------------------2019.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 //最后一个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.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(); } @Override public 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 textView.setText(String.valueOf(inputContent.charAt(i))); } else { textView.setText(""); } } }

其中:edit_cursor_bg_transparent.xml

2020.04.26更新,加上了 待输入方框的选中色。效果如下: 在这里插入图片描述

最近发现有同行也做了类似需求:https://www.jianshu.com/p/3238a5afc21c



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有