Android自定义短信验证码组件
作者:Unknown world 发布时间:2022-10-06 00:30:13
标签:Android,短信,验证码
Android自定义短信验证码组件,供大家参考,具体内容如下
效果图
1.布局实现
因为要禁用光标,所以我用TextView代替了EditText,每一行显示的验证码个数由用户决定,所以我这里用线性布局的权重,对TextView进行控制宽度等分,然后设置选中和未选中当前TextView的底部边框,设置高亮颜色背景
2.接受用户输入
我这里使用了TextView,但是怎么接受用户输入的值呢。这里我直接继承了RelativeLayout,然后添加了一个透明的EditText,覆盖在这几个TextView上面,用户就可以点击唤起键盘输入
3.TextView如何显示值和删除值
我这里设置EditText的TextColor和BackgroundColor为Color.TRANSPARENT 透明,然后监听EditText的addTextChangedListener事件和setOnKeyListener按键删除事件,然后把值添加到TextView上,就能实现了,然后在写一个对外的接口。获取到输入的验证码。
4.添加闪烁的动画
我这里使用了ObjectAnimator,初始化给每个TextView添加动画,然后在输入的时候给当前的TextView启动动画,取消其他TextView动画
具体源码如下:
/**
* @author wu_ming_zhi_bei
* @date 2021/1/27 15:00
* @Notes
*/
public class VerificationCodeView extends RelativeLayout {
private Context mContext;
private RelativeLayout.LayoutParams layoutParams;
private int num = 4;//验证码数量
private int codeSize;//字体大小
private int codeColor;//字体颜色
private List<TextView> tvs = new ArrayList<>();
private List<String> codes = new ArrayList<>();
private EditText etCode;
private InputMethodManager imm;
List<ObjectAnimator> animators = new ArrayList<>();
public VerificationCodeView(Context context) {
this(context,null);
}
public VerificationCodeView(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public VerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context, AttributeSet attrs) {
this.mContext = context;
imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView);
num = a.getInteger(R.styleable.VerificationCodeView_num,4);
codeSize = a.getDimensionPixelSize(R.styleable.VerificationCodeView_codeSize,18);
codeColor = a.getColor(R.styleable.VerificationCodeView_codeColor,getResources().getColor(R.color.theme_color));
//初始化一个大的LinearLayout来存放验证码
LinearLayout codeBox = new LinearLayout(mContext);
codeBox.setOrientation(LinearLayout.HORIZONTAL);
codeBox.setGravity(Gravity.CENTER);
//添加方块
for(int i=0;i<num;i++){
TextView tv = new TextView(mContext);
tv.setTextSize(codeSize);
tv.setTextColor(codeColor);
tv.setGravity(Gravity.CENTER);
tv.setPadding(0,0,0,10);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, 1);
param.gravity = Gravity.CENTER;
param.rightMargin = 20;
param.leftMargin = 20;
param.topMargin = 20;
param.bottomMargin = 20;
tv.setLayoutParams(param);
//默认第一个选中
if(i==0){
tv.setText("|");
tv.setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom));
}else{
tv.setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom));
}
codeBox.addView(tv);
tvs.add(tv);//添加到数组
}
layoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//添加codebox的位置在组件的最上面
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,TRUE);
layoutParams.setMargins(60,0,60,0);
codeBox.setLayoutParams(layoutParams);
//添加Edit
etCode = new EditText(mContext);
etCode.setLayoutParams(layoutParams);
etCode.setLines(1);
etCode.setMaxLines(1);
etCode.setTextColor(Color.TRANSPARENT);
etCode.setBackgroundColor(Color.TRANSPARENT);
etCode.setCursorVisible(false);
//添加edit监听
etCode.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if(editable != null && editable.length()>0) {
etCode.setText("");//清空数据
if(codes.size() < num){
codes.add(editable.toString());
showCode();
}
}
}
});
// 监听验证码删除按键
etCode.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyCode == KeyEvent.KEYCODE_DEL && keyEvent.getAction() == KeyEvent.ACTION_DOWN && codes.size()>0) {
codes.remove(codes.size()-1);
showCode();
return true;
}
return false;
}
});
addView(codeBox);
addView(etCode);
addAnimation();//添加东安湖
setTwinkle();//开启动画
}
//显示验证码
private void showCode(){
int size = codes.size();//1 6
for(int i=0;i<num;i++){
if(size>i){
tvs.get(i).setText(codes.get(i));//添加到textview
}else if(size==i){
tvs.get(i).setText("|");
}else{
tvs.get(i).setText("");
}
}
etCode.setFocusable(true);
etCode.requestFocus();
etCode.setFocusableInTouchMode(true);
etCode.requestFocusFromTouch();
setTwinkle();//动画
callBack();//回调
}
private void showColor(){
int size = codes.size();
if(size==0){
tvs.get(0).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom));
}else{
for(int i=0;i<tvs.size();i++){
if(i==size-1){
tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom));
}else{
tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom));
}
}
}
}
/**
* 回调
*/
private void callBack(){
if(onInputListener==null){
return;
}
if(codes.size()==num){
onInputListener.onSucess(getPhoneCode());
}else{
onInputListener.onInput();
}
}
//定义回调
public interface OnInputListener{
void onSucess(String code);
void onInput();
}
private OnInputListener onInputListener;
public void setOnInputListener(OnInputListener onInputListener){
this.onInputListener = onInputListener;
}
/**
* 获得手机号验证码
* @return 验证码
*/
public String getPhoneCode(){
StringBuilder sb = new StringBuilder();
for (String code : codes) {
sb.append(code);
}
return sb.toString();
}
/**
* 显示键盘
*/
public void showSoftInput(){
//显示软键盘
if(imm!=null && etCode!=null) {
etCode.postDelayed(new Runnable() {
@Override
public void run() {
imm.showSoftInput(etCode, 0);
}
},200);
}
}
/**
* 隐藏键盘
*/
public void hideSoftInput(){
//显示软键盘
if(imm!=null && etCode!=null) {
etCode.postDelayed(new Runnable() {
@Override
public void run() {
imm.hideSoftInputFromWindow(etCode.getWindowToken(), 0);
}
},200);
}
}
/**
* 添加动画
*/
private void addAnimation(){
for(int i=0;i<tvs.size();i++){
ObjectAnimator animator = ObjectAnimator.ofInt(tvs.get(i), "TextColor", 0x00000000, 0xfff00000);
animator.setDuration(10000);
final int index = i;
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
tvs.get(index).setTextColor(codeColor);
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(Animation.INFINITE);
animators.add(animator);
}
}
/**
* 开启动画
*/
private void setTwinkle(){
int size = codes.size();
for(int i=0;i<tvs.size();i++){
if(i==size){
animators.get(i).start();
tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_current_bottom));
}else{
animators.get(i).cancel();
tvs.get(i).setBackground(mContext.getResources().getDrawable(R.drawable.code_border_bottom));
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
for(int i=0;i<tvs.size();i++){
animators.get(i).cancel();
}
}
}
来源:https://blog.csdn.net/qq_36573702/article/details/113260144


猜你喜欢
- 一、内部类的概念在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。p
- 1.下载JDK查看最新:http://www.oracle.com/technetwork/java/javase/downloads/in
- 什么是Pub-Sub发布订阅是一种设计模式,它允许应用程序组件之间进行松散耦合。其实订阅发布设计中主要是发布者生成事件通道,用于在不了解任何
- 验证用户是否已经登录package cn.hongxin.filter;import java.io.IOException;import
- 前言前不久遇到一个问题,是公司早期的基础库遇到的,其实很低级,但是还是记录下来。出错点是一个 IO 流的写入bug,我们项目会有一种专有的数
- 在查询时经常出现一对多”的关系,所有会出现嵌套对象的情况,Mybatis在resultMap提供了collection标
- 说明:基于atguigu学习笔记。简介Webflux是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似
- 1. 在原有工程目录右键-> new ->Module->:2. 选择library:3. 一路next,最后finish
- 本文实例为大家分享了Java实现简易俄罗斯方块的具体代码,供大家参考,具体内容如下一、将对象抽象为类首先考虑俄罗斯方块游戏中含有哪些具体的对
- import java.io.BufferedReader;import java.io.File;import java.io.FileI
- 在java项目开发中。最开始换行符大家一般是在idea中设置新文件为LF,并且对旧文件通过IDEA下方的点击来更换换行符。很显然,对于几千文
- 最常用的序列化是把某个类序列化成二进制文件.但有时我们也会把类序列化成xml文件. 假如有如下一个类 class Arwen { priva
- 之前写了一个WPF的圆形环绕的Loading动画,现在写一个Winform的圆形环绕的Loading动画。1.新建Winform项目,添加一
- 1、Android内存管理机制1.1 Java内存分配模型先上一张JVM将内存划分区域的图程序计数器:存储当前线程执行目标方法执行到第几行。
- 目录断言对象、数组、集合ObjectUtilsStringUtilsCollectionUtils文件、资源、IO 流FileCopyUti
- 文件创建:File.Create(Application.StartupPath + "\\AlarmSet.txt")
- SurfaceView和TextureView均继承于android.view.View与其它View不同的是,两者都能在独立的线程中绘制和
- 一、ToolBar1、在build.gradle中添加依赖,例如:compile 'com.android.support:appc
- Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一。如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都
- 服务端注册功能实现通过web层完成客户端和服务端的数据交互(接受数据,发送数据),service层完成业务逻辑(注册,登录),dao层操作数