基础view如下:

具体的思路实现:

1:展示textview实现

2: 顶层使用透明的edittext.获取焦点/删除文字等。

public class BaseVerificationCodeView extends RelativeLayout {
private Context mContext;
private OnCodeFinishListener onCodeFinishListener; //TextView的list
private List<TextView> tvList = new ArrayList<>(); private GoogleEditText editText;
/**
* 输入框数量
*/
private int mEtNumber; /**
* 输入框类型
*/
private BaseVerificationCodeView.VCInputType mEtInputType;
/**
* 输入框的宽度
*/
private int mEtWidth;
/**
* 输入框的高度
*/
private int mEtHeight; /**
* 文字颜色
*/
private int mEtTextColor; /**
* 文字大小
*/
private float mEtTextSize; /**
* 输入框背景
*/
private int mEtTextBg; //输入框的间距
private int mEtMargin = 10; public void setOnCodeFinishListener(OnCodeFinishListener onCodeFinishListener) {
this.onCodeFinishListener = onCodeFinishListener;
} public int getmEtNumber() {
return mEtNumber;
} public void setmEtNumber(int mEtNumber) {
this.mEtNumber = mEtNumber;
} public BaseVerificationCodeView.VCInputType getmEtInputType() {
return mEtInputType;
} public void setmEtInputType(BaseVerificationCodeView.VCInputType mEtInputType) {
this.mEtInputType = mEtInputType;
} public int getmEtWidth() {
return mEtWidth;
} public void setmEtWidth(int mEtWidth) {
this.mEtWidth = mEtWidth;
} public int getmEtHeight() {
return mEtHeight;
} public void setmEtHeight(int mEtHeight) {
this.mEtHeight = mEtHeight;
} public int getmEtTextColor() {
return mEtTextColor;
} public void setmEtTextColor(int mEtTextColor) {
this.mEtTextColor = mEtTextColor;
} public float getmEtTextSize() {
return mEtTextSize;
} public void setmEtTextSize(float mEtTextSize) {
this.mEtTextSize = mEtTextSize;
} public int getmEtTextBg() {
return mEtTextBg;
} public void setmEtTextBg(int mEtTextBg) {
this.mEtTextBg = mEtTextBg;
} public enum VCInputType {
NUMBER,
NUMBERPASSWORD,
TEXT,
TEXTPASSWORD,
} public BaseVerificationCodeView(Context context) {
this(context, null);
} public BaseVerificationCodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public BaseVerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
@SuppressLint({"Recycle", "CustomViewStyleable"})
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView);
mEtNumber = typedArray.getInteger(R.styleable.VerificationCodeView_zwidget_vcv_et_number, 4);
int inputType = typedArray.getInt(R.styleable.VerificationCodeView_zwidget_vcv_et_inputType, VerificationCodeView.VCInputType.NUMBER.ordinal());
mEtInputType = BaseVerificationCodeView.VCInputType.values()[inputType];
mEtWidth = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_width, 120);
mEtHeight = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_height, -1);
if (mEtHeight == -1) {
mEtHeight = mEtWidth;
}
mEtTextColor = typedArray.getColor(R.styleable.VerificationCodeView_zwidget_vcv_et_text_color, Color.BLACK);
mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_text_size, 16);
mEtTextBg = typedArray.getResourceId(R.styleable.VerificationCodeView_zwidget_vcv_et_bg, R.drawable.zwidget_vcv_et_code_bg); //释放资源
typedArray.recycle();
initTextView();
initEdit();
} /**
* 设置TextView
*/
private void initTextView() {
LinearLayout linearLayout = new LinearLayout(mContext);
addView(linearLayout);
LayoutParams llLayoutParams = (LayoutParams) linearLayout.getLayoutParams();
llLayoutParams.width = LayoutParams.MATCH_PARENT;
llLayoutParams.height = LayoutParams.WRAP_CONTENT;
//水平排列
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
//内容居中
linearLayout.setGravity(Gravity.CENTER);
int childHPadding = 14;
for (int i = 0; i < mEtNumber; i++) {
TextView textView = new TextView(mContext);
linearLayout.addView(textView); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mEtWidth, mEtHeight);
layoutParams.bottomMargin = childHPadding;
layoutParams.topMargin = childHPadding;
layoutParams.leftMargin = childHPadding;
layoutParams.rightMargin = childHPadding;
layoutParams.gravity = Gravity.CENTER;
textView.setLayoutParams(layoutParams);
textView.setBackgroundResource(mEtTextBg);
textView.setGravity(Gravity.CENTER);
textView.setMaxEms(1);
textView.setMaxLines(1);
textView.setTextSize(mEtTextSize);
textView.setTextColor(mEtTextColor);
switch (mEtInputType) {
case NUMBERPASSWORD:
textView.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
break;
case TEXT:
textView.setInputType(InputType.TYPE_CLASS_TEXT);
break;
case TEXTPASSWORD:
textView.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
break;
default:
textView.setInputType(InputType.TYPE_CLASS_NUMBER);
} tvList.add(textView);
}
tvSetFocus(0);
} private void initEdit() {
editText = new GoogleEditText(mContext);
addView(editText);
LayoutParams layoutParams = (LayoutParams) editText.getLayoutParams();
layoutParams.width = layoutParams.MATCH_PARENT;
layoutParams.height = mEtHeight;
editText.setLayoutParams(layoutParams); //防止横盘小键盘全屏显示
editText.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
//隐藏光标
editText.setCursorVisible(false);
//最大输入长度
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mEtNumber)});
//输入类型为数字
switch (mEtInputType) {
case NUMBERPASSWORD:
editText.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
break;
case TEXT:
editText.setInputType(InputType.TYPE_CLASS_TEXT);
break;
case TEXTPASSWORD:
editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
break;
default:
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
editText.setTextSize(0);
editText.setBackgroundResource(R.drawable.zwidfet_vcv_et_code_transfer_bg);
editText.addTextChangedListener(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) {
if (s != null && !TextUtils.isEmpty(s.toString())) {
//如果是最后一位验证码,焦点在最后一个,否者在下一位
if (s.length() == mEtNumber) {
tvSetFocus(mEtNumber - 1);
} else {
tvSetFocus(s.length());
} //给textView设置数据
for (int i = 0; i < s.length(); i++) {
tvList.get(i).setText(s.toString().substring(i, i + 1));
}
for (int i = s.length(); i < mEtNumber; i++) {
tvList.get(i).setText("");
}
} else {
//一位验证码都没有的情况
tvSetFocus(0);
for (int i = 0; i < mEtNumber; i++) {
tvList.get(i).setText("");
}
}
} @Override
public void afterTextChanged(Editable s) {
int length = s.length();
if (length == mEtNumber) {
onCodeFinishListener.onComplete(s.toString());
}
}
});
showSystemKeyboard(mContext, editText);
} private void tvSetFocus(int index) {
tvList.get(index).setClickable(true);
tvList.get(index).setFocusable(true);
tvList.get(index).setBackgroundResource(mEtTextBg);
} /**
* 显示系统键盘
*
* @param context Context
* @param editText EditText
*/
public static void showSystemKeyboard(Context context, EditText editText) {
editText.requestFocus();
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);
}
} /**
* 隐藏系统键盘
*/
public void hideSystemKeyboard() {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
} /**
* 更新输入框颜色背景及字体大小
*/
public void updateChild() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
if (childAt instanceof LinearLayout) {
int childCount1 = ((LinearLayout) childAt).getChildCount();
for (int i1 = 0; i1 < childCount1; i1++) {
View childAt1 = ((LinearLayout) childAt).getChildAt(i1);
if (childAt1 instanceof TextView){
((TextView) childAt1).setTextSize(mEtTextSize);
((TextView) childAt1).setTextColor(mEtTextColor);
childAt1.setBackgroundResource(mEtTextBg);
}
} }
}
invalidate();
} /**
* 清空所有输入框内容
*/
public void clearAllText() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
editText.setText("");
}
}, 100); } public interface OnCodeFinishListener {
void onComplete(String content);
}
}

resource如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 自定义验证码输入框-->
<declare-styleable name="VerificationCodeView">
<!--输入框的数量-->
<attr name="zwidget_vcv_et_number" format="integer" />
<!--输入类型-->
<attr name="zwidget_vcv_et_inputType">
<enum name="number" value="0" />
<enum name="numberPassword" value="1" />
<enum name="text" value="2" />
<enum name="textPassword" value="3" />
</attr>
<!--输入框的宽度-->
<attr name="zwidget_vcv_et_width" format="dimension|reference" />
<!--输入框的高度-->
<attr name="zwidget_vcv_et_height" format="dimension|reference" />
<!--输入框文字颜色-->
<attr name="zwidget_vcv_et_text_color" format="color|reference" />
<!--输入框文字大小-->
<attr name="zwidget_vcv_et_text_size" format="dimension|reference" />
<!--输入框背景-->
<attr name="zwidget_vcv_et_bg" format="reference" />
</declare-styleable>
</resources>

遗留问题:

1:无法开启光标,根据光标展示。

2:没有替换背景。

Android动态数字输入框的更多相关文章

  1. MUI 里js动态添加数字输入框后,增加、减少按钮无效

    numbox 的自动初化是在 mui.ready 时完成的mui 页面默认会自动初始化页面中的所有数字输入框,动态构造的 DOM 需要进行手动初始化.比如:您动态创建了一个 ID 为 abc 的数字输 ...

  2. 动手写个数字输入框1:input[type=number]的遗憾

    前言  最近在用Polymer封装纯数字的输入框,开发过程中发现不少坑,也有很多值得研究的地方.本系列打算分4篇来叙述这段可歌可泣的踩坑经历: <动手写个数字输入框1:input[type=nu ...

  3. 基于Vue的数字输入框组件开发

    1.概述 Vue组件开发的API:props.events和slots 2.组件代码 github地址:https://github.com/MengFangui/VueInputNumber 效果: ...

  4. Android 动态改变高度以及计算长度的EditText

    前段时间项目需求,需要做一个有限制长度的输入框并动态显示剩余文字,同时也要动态改变EditText的高度来增加用户体验.现整理出来与大家分享. 先来看看效果图 看了效果就分享一下布局 <Rela ...

  5. [转载] Android动态加载Dex机制解析

    本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...

  6. [Mobile] 手机浏览器输入框-数字输入框

    手机浏览器的输入框,一直都是以web的方式进行开发的,没有关注到用户体验,领导提出了输入框要弹出数字输入框,想来应该有这种技术能实现.   搜索之后发现可以使用type="number&qu ...

  7. WPF数字输入框和IP地址输入框

    数字输入框 简介 在业务中,我们经常需要限制用户的输入,比如限制输入长度,限制只能输入数字等等.限制输入长度WPF内置的TextBox已经帮我们解决了,但是限制输入数字却并未在WPF中内置解决方案.使 ...

  8. Android 动态加载 (二) 态加载机制 案例二

    探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...

  9. Android 动态加载 (一) 态加载机制 案例一

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  10. android利用数字证书对程序签名

     签名的必要性 1.  防止你已安装的应用被恶意的第三方覆盖或替换掉. 2.  开发者的身份标识,签名可以防止抵赖等事件的发生. 开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同 ...

随机推荐

  1. mac安装nvm

    系统:macos catalina版本:10.15.7 一.安装nvm 打开终端执行这个命令 安装的版本是 v0.39.1 curl -o- [https://raw.githubuserconten ...

  2. 记录一个令人崩溃的tomcat闪退问题

    tomcat启动时要加载server.xml文件,xml文件中的注释符要一一对应不能多不能少. 比如 这就是错的 只有这样 才是对的 呜呜呜~~~

  3. 文心一言 VS 讯飞星火 VS chatgpt (95)-- 算法导论9.2 4题

    四.用go语言,假设用RANDOMIZED-SELECT 去选择数组 A=(3,2,9,0,7,5,4,8,6,1)的最小元素,给出能够导致 RANDOMIZED-SELECT最坏情况发生的一个划分序 ...

  4. Couchdb-权限绕过--命令执行--(CVE-2017-12635)&&(CVE-2017-12636)--H2database命令执行--(CVE-2022-23221)

    Couchdb-权限绕过--命令执行--(CVE-2017-12635)&&(CVE-2017-12636)--H2database命令执行--(CVE-2022-23221) 环境概 ...

  5. Eclipse 创建OSGI项目并调试

    File->new->Plug-in Project

  6. What is Lambda?

    根据我的观察,Lambda是一种比较灵活的形式,需要多看几个案例才能明白它. Lambda是一种简化代码的技术手段,主要用于简化匿名实现类,允许把函数作为一个方法的参数传递进方法中.它本身并不会创造出 ...

  7. 深入理解 python 虚拟机:原来虚拟机是这么实现闭包的

    深入理解 python 虚拟机:原来虚拟机是这么实现闭包的 在本篇文章当中主要从虚拟机层面讨论函数闭包是如何实现的,当能够从设计者的层面去理解闭包就再也不用死记硬背一些闭包的概念了,因为如果你理解闭包 ...

  8. PostgreSQL学习笔记-4.基础知识:空值NULL、别名AS

    NULL 值代表遗漏的未知数据. 默认地,表的列可以存放 NULL 值. 本章讲解 IS NULL 和 IS NOT NULL 操作符. 语法 当创建表时,NULL 的基本语法如下: CREATE T ...

  9. 轻松掌握组件启动之MongoDB(番外篇):高可用复制集架构环境搭建-mtools

    引言 在前两章节中,我们详细讲解了如何手动配置启动MongoDB.然而,现在有许多不同的工具可以帮助我们更方便地启动和创建MongoDB数据库.因此,今天我将介绍一个名为mtools的开源项目,它可以 ...

  10. 长程 Transformer 模型

    Tay 等人的 Efficient Transformers taxonomy from Efficient Transformers: a Survey 论文 本文由 Teven Le Scao.P ...