关于Android自定义View实现验证码输入框

简介: 在做校验验证的时候,经常需要手机接收短信,获取验证码,输入验证码,实现起来其实也不难,今天对输入框简单做了一个封装,通过自定义View来实现。

在做校验验证的时候,经常需要手机接收短信,获取验证码,输入验证码,实现起来其实也不难,今天对输入框简单做了一个封装,通过自定义View来实现。

先看效果图:
image.png

采用组合自定义view来实现,引入布局文件,这种方式实现起来虽然简单,但是不够智能通用,需求变动的话就需要改代码,但是也不难改,代码很简单,下面是完整代码,请自行阅读。

public class VerificationCodeView extends RelativeLayout {
    private Context context;
    private OnCodeFinishListener onCodeFinishListener;
    private TextView tvCode1;
    private TextView tvCode2;
    private TextView tvCode3;
    private TextView tvCode4;
    private TextView tvCode5;
    private TextView tvCode6;
    private View v1;
    private View v2;
    private View v3;
    private View v4;
    private View v5;
    private View v6;
    private EditText etCode;
    private List<String> codes = new ArrayList<>();
    private InputMethodManager imm;
 
 
    public OnCodeFinishListener getOnCodeFinishListener() {
        return onCodeFinishListener;
    }
 
    public void setOnCodeFinishListener(OnCodeFinishListener onCodeFinishListener) {
        this.onCodeFinishListener = onCodeFinishListener;
    }
 
    public VerificationCodeView(Context context) {
        super(context);
        this.context = context;
        loadView();
    }
 
    public VerificationCodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        loadView();
    }
 
    private void loadView() {
        imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        View view = LayoutInflater.from(context).inflate(R.layout.verification_code, this);
        initView(view);
        initEvent();
    }
 
    ArrayList<View> views = new ArrayList<>();
    ArrayList<TextView> tvList = new ArrayList<>();
 
    private void initView(View view) {
        tvCode1 = view.findViewById(R.id.tv_code1);
        tvCode2 = view.findViewById(R.id.tv_code2);
        tvCode3 = view.findViewById(R.id.tv_code3);
        tvCode4 = view.findViewById(R.id.tv_code4);
        tvCode5 = view.findViewById(R.id.tv_code5);
        tvCode6 = view.findViewById(R.id.tv_code6);
        etCode = view.findViewById(R.id.et_code);
        etCode.requestFocus();
        etCode.setFocusable(true);
        v1 = view.findViewById(R.id.v1);
        v2 = view.findViewById(R.id.v2);
        v3 = view.findViewById(R.id.v3);
        v4 = view.findViewById(R.id.v4);
        v5 = view.findViewById(R.id.v5);
        v6 = view.findViewById(R.id.v6);
        views.add(v1);
        views.add(v2);
        views.add(v3);
        views.add(v4);
        views.add(v5);
        views.add(v6);
        tvList.add(tvCode1);
        tvList.add(tvCode2);
        tvList.add(tvCode3);
        tvList.add(tvCode4);
        tvList.add(tvCode5);
        tvList.add(tvCode6);
    }
 
    private void initEvent() {
        //验证码输入
        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() < 8) {
                        etCode.setCursorVisible(false);
                        codes.add(editable.toString());
                        showCode();
                    }
                    onCodeFinishListener.onTextChange(getPhoneCode());
                }
            }
        });
        // 监听验证码删除按键
        etCode.setOnKeyListener(new 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();
                    onCodeFinishListener.onTextDel();
                    return true;
                }
                return false;
            }
        });
    }
 
    /**
     * 显示输入的验证码
     */
    private void showCode() {
        String code1 = "";
        String code2 = "";
        String code3 = "";
        String code4 = "";
        String code5 = "";
        String code6 = "";
        if (codes.size() >= 1) {
            code1 = codes.get(0);
        }
        if (codes.size() >= 2) {
            code2 = codes.get(1);
        }
        if (codes.size() >= 3) {
            code3 = codes.get(2);
        }
        if (codes.size() >= 4) {
            code4 = codes.get(3);
        }
        if (codes.size() >= 5) {
            code5 = codes.get(4);
        }
        if (codes.size() >= 6) {
            code6 = codes.get(5);
        }
 
        tvCode1.setText(code1);
        tvCode2.setText(code2);
        tvCode3.setText(code3);
        tvCode4.setText(code4);
        tvCode5.setText(code5);
        tvCode6.setText(code6);
    }
 
    /**
     * 设置下划线高亮颜色
     */
    private void setColor(int defaultColor, int focusColor) {
        int color_default = context.getResources().getColor(defaultColor);
        int color_focus = context.getResources().getColor(focusColor);
        for (View v : views) {
            //默认颜色
            v.setBackgroundColor(color_default);
        }
        int length = getPhoneCode().length();
        for (int i = 0; i < length; i++) {
            views.get(i).setBackgroundColor(color_focus);
        }
    }
 
    /**
     * 显示键盘
     */
    public void showSoftInput() {
        //显示软键盘
        if (imm != null && etCode != null) {
            etCode.postDelayed(new Runnable() {
                @Override
                public void run() {
                    imm.showSoftInput(etCode, 0);
                }
            }, 200);
        }
    }
 
    /**
     * 获得手机号验证码
     *
     * @return 验证码
     */
    public String getPhoneCode() {
        StringBuilder sb = new StringBuilder();
        for (String code : codes) {
            sb.append(code);
        }
        return sb.toString();
    }
 
    public void errorText(int color) {
        for (View v : views) {
            v.setBackgroundColor(color);
        }
    }
 
    public void textBgColor(int color) {
        for (View v : views) {
            v.setBackgroundColor(color);
        }
    }
 
    public interface OnCodeFinishListener {
        /**
         * 文本改变
         */
        void onTextChange(String content);
 
        void onTextDel();
    }
 
 
    public void setEditTextCursorDrawable(EditText editText) {
        //修改光标的颜色(反射)
        try {
            @SuppressLint("SoonBlockedPrivateApi") Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
            f.setAccessible(true);
//            f.set(editText, R.drawable.et_otp_cursor);
        } catch (Exception ignored) {
        }
    }
}

在看看布局文件

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
    <LinearLayout
        android:id="@+id/ll_code"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp">
            <TextView
                android:id="@+id/tv_code1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:background="@null"
                android:gravity="center"/>
            <View
                android:id="@+id/v1"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
 
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp"
            >
            <TextView
                android:id="@+id/tv_code2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:background="@null"
                android:gravity="center"/>
            <View
                android:id="@+id/v2"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp"
            >
            <TextView
                android:id="@+id/tv_code3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:background="@null"
                android:gravity="center"/>
            <View
                android:id="@+id/v3"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp">
            <TextView
                android:id="@+id/tv_code4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:background="@null"
                android:gravity="center"/>
            <View
                android:id="@+id/v4"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp">
            <TextView
                android:id="@+id/tv_code5"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@null"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:gravity="center"/>
            <View
                android:id="@+id/v5"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:layout_marginRight="10dp"
            >
            <TextView
                android:id="@+id/tv_code6"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:textSize="24dp"
                android:textStyle="bold"
                android:background="@null"
                android:gravity="center"/>
            <View
                android:id="@+id/v6"
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#4c000000" />
        </LinearLayout>
    </LinearLayout>
 
    <EditText
        android:id="@+id/et_code"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/ll_code"
        android:layout_alignBottom="@+id/ll_code"
        android:background="@android:color/transparent"
        android:textColor="@android:color/transparent"
        android:cursorVisible="false"
        android:layout_marginLeft="20dp"
        android:inputType="number"/>
</RelativeLayout>
相关文章
|
4天前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
5天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
18 5
|
13天前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
13天前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
20 2
|
14天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
17天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
19 2
|
Android开发
Android Studio 自定义设置注释模板
Android Studio 自定义设置注释模板
478 0
Android Studio 自定义设置注释模板
|
6天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
3天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
5天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
16 3