基础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. 后端常用的Linux命令大全,建议收藏

    引言 作为一名后端工程师,使用终端是一种常见的做法,也是你应该学习的技能.许多命令和实用程序可以帮助你在使用 Linux 时更有效地完成任务. 基本 Linux 命令 如果你想使用 Linux 操作系 ...

  2. 斜率优化DP 学习笔记

    斜率优化 DP 适用情况 适用于求解最优解(最大.最小)问题. 上凸壳与下凸壳 求解步骤 对于任意状态转义方程,设 \(A_i\),\(B_i\),使状态转移方程转化为 \(f_i = \min(f_ ...

  3. C/C++基础——引用与指针有什么区别?C++中输入输出加速

    文章目录 1 引用与指针有什么区别? 2 C++中输入输出加速 tie sync_with_stdio 应用 1 引用与指针有什么区别? 指针和引用都是地址的概念,指针指向一块内存,它的内容是所指内存 ...

  4. Python基础——深浅拷贝、python内存泄露、你并不了解的format、decimal

    文章目录 深浅拷贝 先看赋值运算 浅拷贝copy 深拷贝deepcopy 相关面试题 python内存泄露 起因 方案 编写安全的代码 弱引用 你并不了解的format.decimal format格 ...

  5. dms

          产品解决方案文档与社区免费试用定价云市场合作伙伴支持与服务了解阿里云       备案控制台 首页关系型数据库NoSQL数据库数据仓库数据管理工具向量数据库免费试用 个人     打卡 发 ...

  6. 什么是 CSS?

    1.什么是 CSS? CSS 指的是层叠样式表* (Cascading Style Sheets) CSS 描述了如何在屏幕.纸张或其他媒体上显示 HTML 元素 CSS 节省了大量工作.它可以同时控 ...

  7. 炫酷转换:Java实现Excel转换为图片的方法

    摘要:本文由葡萄城技术团队原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 在实际开发过程中,经常会有这样的需求:将Excel表格或特定区域 ...

  8. Linux账号密码安全运维

    前言 随着云计算厂商的兴起,云资源如ECS不再只有企业或者公司才会使用,普通人也可以自己买一台ECS来搭建自己的应用或者网站.虽然云计算厂商帮我们做了很多安全相关的工作,但并不代表我们的机器资源就绝对 ...

  9. Java模块化应用实践之精简JRE(内含开源)

    导语 Java9及以后的版本引入了模块化特性,但是直到今天JDK21都发布了,依然没有被大量使用起来,那么这个特性就真的没啥意义了吗? 别忘了,Java本身可是把模块化做到了极致的,所以可以利用这个特 ...

  10. 解决Maven中90%的依赖(导包)问题

    今天给大家分享一个非常好用的技巧,这个技巧是一个组合技巧 是的,自从我开始接触了以spring为框架的项目学习后,这个maven导包老是出现问题,每次在这个上面花费好多时间,于是乎打算写一个秘籍出来. ...