├── .gitignore ├── README-CN.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── jkb │ │ └── vercodeedittext │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── config.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── VercodeEditTex.png └── demo.gif ├── settings.gradle ├── sign ├── JustKiddingBaby.jks └── README.txt └── vcedittext-lib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── com │ └── jkb │ └── vcedittext │ ├── VerificationAction.java │ └── VerificationCodeEditText.java └── res └── values ├── attrs.xml └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README-CN.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 介绍 4 | 一个安卓验证码输入框控件。 5 | [![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html) 6 | 7 | [![SDK](https://img.shields.io/badge/API-12%2B-green.svg?style=flat)](https://android-arsenal.com/api?level=11) 8 | ![VercodeEditText](https://api.bintray.com/packages/jkb/maven/vercodeedittext/images/download.svg) 9 | 10 | ## 演示 11 | 防止输入溢出. 12 | 13 | 14 | ## 特性 15 | - [x] **继承EditText,可以当作EditText使用** 16 | - [x] **防止输入溢出** 17 | - [x] **自定义验证码位数** 18 | - [x] **提供输入内容的监听器** 19 | - [x] **高度自适配** 20 | - [x] **属性自定义配置** 21 | - [x] **光标属性自定义** 22 | 23 | ## 版本 24 | 名称|SlideMenuLayout 25 | ---|--- 26 | 最新|![VercodeEditText](https://api.bintray.com/packages/jkb/maven/vercodeedittext/images/download.svg) 27 | 28 | ## 配置 29 | #### Maven 30 | ```xml 31 | 32 | com.justkiddingbaby 33 | vercodeedittext 34 | 最新版本 35 | pom 36 | 37 | ``` 38 | #### JCenter 39 | 第一步,添加至工程的build.gradle文件中 40 | ```gradle 41 | repositories { 42 | jcenter() 43 | } 44 | ``` 45 | 第二步,添加至module的build.gradle文件中 46 | ```gradle 47 | 'com.justkiddingbaby:vercodeedittext:最新版本' 48 | ``` 49 | 50 | ## 属性说明 51 | 属性|介绍|取值 52 | ---|---|--- 53 | [figures](/vcedittext-lib/src/main/res/values/attrs.xml)|验证码位数|integer 54 | [verCodeMargin](/vcedittext-lib/src/main/res/values/attrs.xml)|每个验证码的间隔|dimension 55 | [bottomLineSelectedColor](/vcedittext-lib/src/main/res/values/attrs.xml)|底线选择状态下的颜色|reference 56 | [bottomLineNormalColor](/vcedittext-lib/src/main/res/values/attrs.xml)|底线未选中状态下的颜色|reference 57 | [bottomLineHeight](/vcedittext-lib/src/main/res/values/attrs.xml)|底线高度|dimension 58 | [selectedBackgroundColor](/vcedittext-lib/src/main/res/values/attrs.xml)|选中的背景颜色|reference 59 | [cursorDuration](/vcedittext-lib/src/main/res/values/attrs.xml)|光标闪烁间隔时间|integer 60 | [cursorColor](/vcedittext-lib/src/main/res/values/attrs.xml)|光标颜色|integer 61 | [cursorWidth](/vcedittext-lib/src/main/res/values/attrs.xml)|光标宽度|integer 62 | 63 | ## 方法说明 64 | 返回值|方法|说明 65 | ---|---|--- 66 | void|[setFigures(int figures)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置验证码位数 67 | void|[setVerCodeMargin(int margin)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置验证码之间的间隔 68 | void|[setBottomSelectedColor(int bottomSelectedColor)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置底线选中状态的颜色 69 | |oid|[setBottomNormalColor(int bottomNormalColor)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置底线未选中状态的颜色 70 | void|[setSelectedBackgroundColor(int selectedBackground)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置验证码选中的背景颜色 71 | void|[setBottomLineHeight(int bottomLineHeight)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置验证码底线的高度 72 | void|[setOnVerificationCodeChangedListener(OnVerificationCodeChangedListener listener)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|设置验证码变化的监听器 73 | 74 | ## 使用 75 | #### 在布局中使用 76 | ```xml 77 | 90 | ``` 91 | 92 | ## 发布历史 93 | #### v1.1.0 (2018/11/1) 94 | 1、添加光标属性的支持. 95 | #### v1.0.5(2017/12/5) 96 | 1、修复在点击控件时候可以遇到的Bug 97 | #### v1.0.4(2017/10/14) 98 | 1、在AndroidManifest.xml中移除label节点. 99 | #### v1.0.3(2017/8/15) 100 | 1、让接口类VerificationAction变为public. 101 | #### v1.0.2(2017/6/29) 102 | 1、修复AndroidMainfest.xml中application标签下allowBackup属性为false的冲突. 103 | #### v1.0.1(2017/6/27) 104 | 1、修复点击后无法获取焦点问题. 105 | #### v1.0.0(2017/6/12) 106 | 1、发布VercodeEditText控件,防止输入溢出. 107 | 2、封装demo. 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Introduction 4 | An android Verification code EditText. 5 | 一个安卓验证码输入框控件。([中文版入口](README-CN.md)) 6 | [![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html) 7 | 8 | [![SDK](https://img.shields.io/badge/API-12%2B-green.svg?style=flat)](https://android-arsenal.com/api?level=11) 9 | ![VercodeEditText](https://api.bintray.com/packages/jkb/maven/vercodeedittext/images/download.svg) 10 | 11 | ## Demo 12 | Prevent input overflow. 13 | 14 | 15 | ## Features 16 | - [x] **Extends EditText,it can be used as EditText** 17 | - [x] **Prevent input overflow** 18 | - [x] **Custom validation code length** 19 | - [x] **Provide input value listener** 20 | - [x] **Layout height is auto adjust** 21 | - [x] **Attributes can be configured for customization** 22 | - [x] **Custom cursor style** 23 | 24 | ## Version 25 | name|VercodeEditText 26 | ---|--- 27 | latest|![VercodeEditText](https://api.bintray.com/packages/jkb/maven/vercodeedittext/images/download.svg) 28 | 29 | ## Configure 30 | #### Maven 31 | ```xml 32 | 33 | com.justkiddingbaby 34 | vercodeedittext 35 | the latest version 36 | pom 37 | 38 | ``` 39 | #### JCenter 40 | First. add to project build.gradle 41 | ```gradle 42 | repositories { 43 | jcenter() 44 | } 45 | ``` 46 | Second. add to module build.gradle 47 | ```gradle 48 | 'com.justkiddingbaby:vercodeedittext:the latest version' 49 | ``` 50 | 51 | ## Attributes instruction 52 | attribute|instruction|value 53 | ---|---|--- 54 | [figures](/vcedittext-lib/src/main/res/values/attrs.xml)|the verification code length|integer 55 | [verCodeMargin](/vcedittext-lib/src/main/res/values/attrs.xml)|the padding for each verification code number|dimension 56 | [bottomLineSelectedColor](/vcedittext-lib/src/main/res/values/attrs.xml)|the color of bottom line is select status|reference 57 | [bottomLineNormalColor](/vcedittext-lib/src/main/res/values/attrs.xml)|the color of bottom line is normal status|reference 58 | [bottomLineHeight](/vcedittext-lib/src/main/res/values/attrs.xml)|the height of bottom line|dimension 59 | [selectedBackgroundColor](/vcedittext-lib/src/main/res/values/attrs.xml)|the background color of verification code is select status|reference 60 | [cursorDuration](/vcedittext-lib/src/main/res/values/attrs.xml)|the duration of cursor blink|integer 61 | [cursorColor](/vcedittext-lib/src/main/res/values/attrs.xml)|the color of cursor|integer 62 | [cursorWidth](/vcedittext-lib/src/main/res/values/attrs.xml)|the width of cursor|integer 63 | 64 | ## Function instruction 65 | return|function name|instruction 66 | ---|---|--- 67 | void|[setFigures(int figures)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the verification code length 68 | void|[setVerCodeMargin(int margin)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the padding for each verification code number 69 | void|[setBottomSelectedColor(int bottomSelectedColor)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the color of bottom line is select status 70 | void|[setBottomNormalColor(int bottomNormalColor)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the color of bottom line is normal status 71 | void|[setSelectedBackgroundColor(int selectedBackground)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the background color of verification code is select status 72 | void|[setBottomLineHeight(int bottomLineHeight)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|set the height of bottom line 73 | void|[setOnVerificationCodeChangedListener(OnVerificationCodeChangedListener listener)](/vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java)|add the listener when verification value is changing| 74 | 75 | ## Usage 76 | #### use in the layout 77 | ```xml 78 | 91 | ``` 92 | 93 | ## Release history 94 | #### v1.1.0 (2018/11/1) 95 | 1、Add cursor support. 96 | #### v1.0.5(2017/12/5) 97 | 1、Fix the bug that could appear when the view is pressed. 98 | #### v1.0.4(2017/10/14) 99 | 1、Remove label element at AndroidManifest.xml. 100 | #### v1.0.3(2017/8/15) 101 | 1、make interface class VerificationAction public. 102 | #### v1.0.2(2017/6/29) 103 | 1、Fix the conflict that allowBackup property is false under the application in AndroidMainfet.xml file. 104 | #### v1.0.1(2017/6/27) 105 | 1、fix bug:can't get focus when the view is touched. 106 | #### v1.0.0(2017/6/12) 107 | 1、release VercodeEditText,Prevent input overflow. 108 | 2、Encapsulation demo. 109 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion rootProject.ext.android.compileSdkVersion 6 | buildToolsVersion rootProject.ext.android.buildToolsVersion 7 | 8 | defaultConfig { 9 | applicationId rootProject.ext.app.applicationId 10 | minSdkVersion rootProject.ext.android.minSdkVersion 11 | targetSdkVersion rootProject.ext.android.targetSdkVersion 12 | versionCode rootProject.ext.app.versionCode 13 | versionName rootProject.ext.app.versionName 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility rootProject.ext.android.sourceCompatibilityVersion 18 | targetCompatibility rootProject.ext.android.targetCompatibilityVersion 19 | } 20 | 21 | signingConfigs { 22 | myConfig { 23 | storeFile file(rootProject.ext.store.storeKey) 24 | storePassword rootProject.ext.store.storePassword 25 | keyAlias rootProject.ext.store.keyAlias 26 | keyPassword rootProject.ext.store.keyPassword 27 | v2SigningEnabled false 28 | } 29 | } 30 | 31 | buildTypes { 32 | release { 33 | minifyEnabled true 34 | //是否清理无用资源 35 | shrinkResources true 36 | //是否启用zipAlign压缩 37 | zipAlignEnabled true 38 | signingConfig signingConfigs.myConfig 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | } 41 | debug { 42 | signingConfig signingConfigs.myConfig 43 | versionNameSuffix "-debug" 44 | } 45 | } 46 | 47 | lintOptions { 48 | abortOnError false 49 | } 50 | } 51 | 52 | dependencies { 53 | compile project(":vcedittext-lib") 54 | } 55 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/yangjing/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/vercodeedittext/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jkb.vercodeedittext; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import com.jkb.vcedittext.VerificationCodeEditText; 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | private VerificationCodeEditText verificationCodeEditText; 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | verificationCodeEditText = (VerificationCodeEditText) findViewById(R.id.am_et); 17 | verificationCodeEditText.setOnVerificationCodeChangedListener(new VerificationCodeEditText 18 | .OnVerificationCodeChangedListener() { 19 | 20 | @Override 21 | public void onVerCodeChanged(CharSequence s, int start, int before, int count) { 22 | 23 | } 24 | 25 | @Override 26 | public void onInputCompleted(CharSequence s) { 27 | 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 26 | 41 | 42 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #bd3e27 4 | #702314 5 | #bd3e27 6 | #64e42604 7 | #999999 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | VercodeEditText 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | apply from: "config.gradle" 4 | 5 | buildscript { 6 | repositories { 7 | jcenter() 8 | mavenCentral() // add repository 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:2.3.2' 12 | classpath 'com.novoda:bintray-release:0.3.4' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | maven { url 'https://jitpack.io' } 23 | } 24 | tasks.withType(Javadoc) { 25 | options.addStringOption('Xdoclint:none', '-quiet') 26 | options.addStringOption('encoding', 'UTF-8') 27 | } 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | app = [ 3 | appVerCode : 1, 4 | appVerName : "0.0.1", 5 | applicationId: "com.jkb.vercodeedittext" 6 | ] 7 | 8 | vercode = [ 9 | publishCode : 7, 10 | publishVersion: "1.1.0", 11 | 12 | userOrg : 'jkb', 13 | groupId : 'com.justkiddingbaby', 14 | artifactId : 'vercodeedittext', 15 | desc : 'An Android vercode EditText.(一个安卓验证码输入框)', 16 | website : 'https://github.com/YangJing96/VercodeEditText' 17 | ] 18 | 19 | android = [ 20 | minSdkVersion : 12, 21 | targetSdkVersion : 23, 22 | compileSdkVersion : 23, 23 | buildToolsVersion : "25.0.0", 24 | sourceCompatibilityVersion: JavaVersion.VERSION_1_7, 25 | targetCompatibilityVersion: JavaVersion.VERSION_1_7 26 | ] 27 | 28 | dependencies = [ 29 | appcompatV7: 'com.android.support:appcompat-v7:23.3.0', 30 | design : 'com.android.support:design:24.0.0' 31 | ] 32 | 33 | store = [ 34 | storeKey : '../sign/JustKiddingBaby.jks', 35 | storePassword: 'mimajiushiwo', 36 | keyAlias : 'JustKiddingBaby', 37 | keyPassword : 'mimajiushiwo' 38 | ] 39 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 12 09:12:32 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /img/VercodeEditTex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/img/VercodeEditTex.png -------------------------------------------------------------------------------- /img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/img/demo.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':vcedittext-lib' 2 | -------------------------------------------------------------------------------- /sign/JustKiddingBaby.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/VercodeEditText/3db397ef2a32390a4d7834f118a11662759a25c2/sign/JustKiddingBaby.jks -------------------------------------------------------------------------------- /sign/README.txt: -------------------------------------------------------------------------------- 1 | Password:mimajiushiwo 2 | Alians:JustKiddingBaby 3 | Password:mimajiushiwo -------------------------------------------------------------------------------- /vcedittext-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /vcedittext-lib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release' 3 | 4 | publish { 5 | userOrg = rootProject.ext.vercode.userOrg 6 | groupId = rootProject.ext.vercode.groupId 7 | artifactId = rootProject.ext.vercode.artifactId 8 | publishVersion = rootProject.ext.vercode.publishVersion 9 | desc = rootProject.ext.vercode.desc 10 | website = rootProject.ext.vercode.website 11 | } 12 | 13 | android { 14 | 15 | compileSdkVersion rootProject.ext.android.compileSdkVersion 16 | buildToolsVersion rootProject.ext.android.buildToolsVersion 17 | 18 | defaultConfig { 19 | minSdkVersion rootProject.ext.android.minSdkVersion 20 | targetSdkVersion rootProject.ext.android.targetSdkVersion 21 | versionCode rootProject.ext.vercode.publishCode 22 | versionName rootProject.ext.vercode.publishVersion 23 | } 24 | 25 | compileOptions { 26 | sourceCompatibility rootProject.ext.android.sourceCompatibilityVersion 27 | targetCompatibility rootProject.ext.android.targetCompatibilityVersion 28 | } 29 | 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | 37 | lintOptions { 38 | abortOnError false 39 | } 40 | } 41 | 42 | dependencies { 43 | compile rootProject.ext.dependencies.appcompatV7 44 | } 45 | -------------------------------------------------------------------------------- /vcedittext-lib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/yangjing/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /vcedittext-lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationAction.java: -------------------------------------------------------------------------------- 1 | package com.jkb.vcedittext; 2 | 3 | import android.support.annotation.ColorRes; 4 | 5 | /** 6 | * 填写验证码支持的Action 7 | * Created by yj on 2017/5/11. 8 | */ 9 | 10 | public interface VerificationAction { 11 | 12 | /** 13 | * 设置位数 14 | */ 15 | void setFigures(int figures); 16 | 17 | /** 18 | * 设置验证码之间的间距 19 | */ 20 | void setVerCodeMargin(int margin); 21 | 22 | /** 23 | * 设置底部选中状态的颜色 24 | */ 25 | void setBottomSelectedColor(@ColorRes int bottomSelectedColor); 26 | 27 | /** 28 | * 设置底部未选中状态的颜色 29 | */ 30 | void setBottomNormalColor(@ColorRes int bottomNormalColor); 31 | 32 | /** 33 | * 设置选择的背景色 34 | */ 35 | void setSelectedBackgroundColor(@ColorRes int selectedBackground); 36 | 37 | /** 38 | * 设置底线的高度 39 | */ 40 | void setBottomLineHeight(int bottomLineHeight); 41 | 42 | /** 43 | * 设置当验证码变化时候的监听器 44 | */ 45 | void setOnVerificationCodeChangedListener(OnVerificationCodeChangedListener listener); 46 | 47 | /** 48 | * 验证码变化时候的监听事件 49 | */ 50 | interface OnVerificationCodeChangedListener { 51 | 52 | /** 53 | * 当验证码变化的时候 54 | */ 55 | void onVerCodeChanged(CharSequence s, int start, int before, int count); 56 | 57 | /** 58 | * 输入完毕后的回调 59 | */ 60 | void onInputCompleted(CharSequence s); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vcedittext-lib/src/main/java/com/jkb/vcedittext/VerificationCodeEditText.java: -------------------------------------------------------------------------------- 1 | package com.jkb.vcedittext; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.os.Build; 8 | import android.support.annotation.ColorRes; 9 | import android.support.v4.content.ContextCompat; 10 | import android.text.Editable; 11 | import android.text.TextPaint; 12 | import android.text.TextWatcher; 13 | import android.util.AttributeSet; 14 | import android.util.DisplayMetrics; 15 | import android.util.TypedValue; 16 | import android.view.MotionEvent; 17 | import android.view.WindowManager; 18 | import android.view.inputmethod.InputMethodManager; 19 | 20 | import java.util.Timer; 21 | import java.util.TimerTask; 22 | 23 | 24 | /** 25 | * 验证码的EditText 26 | * Created by yj on 2017/6/12. 27 | */ 28 | 29 | public class VerificationCodeEditText extends android.support.v7.widget.AppCompatEditText implements 30 | VerificationAction, TextWatcher { 31 | private static final int DEFAULT_CURSOR_DURATION = 400; 32 | 33 | private int mFigures;//需要输入的位数 34 | private int mVerCodeMargin;//验证码之间的间距 35 | private int mBottomSelectedColor;//底部选中的颜色 36 | private int mBottomNormalColor;//未选中的颜色 37 | private float mBottomLineHeight;//底线的高度 38 | private int mSelectedBackgroundColor;//选中的背景颜色 39 | private int mCursorWidth;//光标宽度 40 | private int mCursorColor;//光标颜色 41 | private int mCursorDuration;//光标闪烁间隔 42 | 43 | private OnVerificationCodeChangedListener onCodeChangedListener; 44 | private int mCurrentPosition = 0; 45 | private int mEachRectLength = 0;//每个矩形的边长 46 | private Paint mSelectedBackgroundPaint; 47 | private Paint mNormalBackgroundPaint; 48 | private Paint mBottomSelectedPaint; 49 | private Paint mBottomNormalPaint; 50 | private Paint mCursorPaint; 51 | 52 | // 控制光标闪烁 53 | private boolean isCursorShowing; 54 | private TimerTask mCursorTimerTask; 55 | private Timer mCursorTimer; 56 | 57 | public VerificationCodeEditText(Context context) { 58 | this(context, null); 59 | } 60 | 61 | public VerificationCodeEditText(Context context, AttributeSet attrs) { 62 | this(context, attrs, 0); 63 | } 64 | 65 | public VerificationCodeEditText(Context context, AttributeSet attrs, int defStyleAttr) { 66 | super(context, attrs, defStyleAttr); 67 | initAttrs(attrs); 68 | setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent));//防止出现下划线 69 | initPaint(); 70 | initCursorTimer(); 71 | setFocusableInTouchMode(true); 72 | super.addTextChangedListener(this); 73 | } 74 | 75 | /** 76 | * 初始化paint 77 | */ 78 | private void initPaint() { 79 | mSelectedBackgroundPaint = new Paint(); 80 | mSelectedBackgroundPaint.setColor(mSelectedBackgroundColor); 81 | mNormalBackgroundPaint = new Paint(); 82 | mNormalBackgroundPaint.setColor(getColor(android.R.color.transparent)); 83 | 84 | mBottomSelectedPaint = new Paint(); 85 | mBottomNormalPaint = new Paint(); 86 | mBottomSelectedPaint.setColor(mBottomSelectedColor); 87 | mBottomNormalPaint.setColor(mBottomNormalColor); 88 | mBottomSelectedPaint.setStrokeWidth(mBottomLineHeight); 89 | mBottomNormalPaint.setStrokeWidth(mBottomLineHeight); 90 | 91 | mCursorPaint = new Paint(); 92 | mCursorPaint.setAntiAlias(true); 93 | mCursorPaint.setColor(mCursorColor); 94 | mCursorPaint.setStyle(Paint.Style.FILL_AND_STROKE); 95 | mCursorPaint.setStrokeWidth(mCursorWidth); 96 | } 97 | 98 | /** 99 | * 初始化Attrs 100 | */ 101 | private void initAttrs(AttributeSet attrs) { 102 | TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.VerCodeEditText); 103 | mFigures = ta.getInteger(R.styleable.VerCodeEditText_figures, 4); 104 | mVerCodeMargin = (int) ta.getDimension(R.styleable.VerCodeEditText_verCodeMargin, 0); 105 | mBottomSelectedColor = ta.getColor(R.styleable.VerCodeEditText_bottomLineSelectedColor, 106 | getCurrentTextColor()); 107 | mBottomNormalColor = ta.getColor(R.styleable.VerCodeEditText_bottomLineNormalColor, 108 | getColor(android.R.color.darker_gray)); 109 | mBottomLineHeight = ta.getDimension(R.styleable.VerCodeEditText_bottomLineHeight, 110 | dp2px(5)); 111 | mSelectedBackgroundColor = ta.getColor(R.styleable.VerCodeEditText_selectedBackgroundColor, 112 | getColor(android.R.color.darker_gray)); 113 | mCursorWidth = (int) ta.getDimension(R.styleable.VerCodeEditText_cursorWidth, dp2px(1)); 114 | mCursorColor = ta.getColor(R.styleable.VerCodeEditText_cursorColor, getColor(android.R.color.darker_gray)); 115 | mCursorDuration = ta.getInteger(R.styleable.VerCodeEditText_cursorDuration, DEFAULT_CURSOR_DURATION); 116 | ta.recycle(); 117 | 118 | // force LTR because of bug: https://github.com/JustKiddingBaby/VercodeEditText/issues/4 119 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 120 | setLayoutDirection(LAYOUT_DIRECTION_LTR); 121 | } 122 | } 123 | 124 | private void initCursorTimer() { 125 | mCursorTimerTask = new TimerTask() { 126 | @Override 127 | public void run() { 128 | // 通过光标间歇性显示实现闪烁效果 129 | isCursorShowing = !isCursorShowing; 130 | postInvalidate(); 131 | } 132 | }; 133 | mCursorTimer = new Timer(); 134 | } 135 | 136 | @Override 137 | protected void onAttachedToWindow() { 138 | super.onAttachedToWindow(); 139 | 140 | // 启动定时任务,定时刷新实现光标闪烁 141 | mCursorTimer.scheduleAtFixedRate(mCursorTimerTask, 0, mCursorDuration); 142 | } 143 | 144 | @Override 145 | protected void onDetachedFromWindow() { 146 | super.onDetachedFromWindow(); 147 | mCursorTimer.cancel(); 148 | } 149 | 150 | @Override 151 | final public void setCursorVisible(boolean visible) { 152 | super.setCursorVisible(visible);//隐藏光标的显示 153 | } 154 | 155 | @Override 156 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 157 | int widthResult = 0, heightResult = 0; 158 | //最终的宽度 159 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 160 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 161 | if (widthMode == MeasureSpec.EXACTLY) { 162 | widthResult = widthSize; 163 | } else { 164 | widthResult = getScreenWidth(getContext()); 165 | } 166 | //每个矩形形的宽度 167 | mEachRectLength = (widthResult - (mVerCodeMargin * (mFigures - 1))) / mFigures; 168 | //最终的高度 169 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 170 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 171 | if (heightMode == MeasureSpec.EXACTLY) { 172 | heightResult = heightSize; 173 | } else { 174 | heightResult = mEachRectLength; 175 | } 176 | setMeasuredDimension(widthResult, heightResult); 177 | } 178 | 179 | @Override 180 | public boolean onTouchEvent(MotionEvent event) { 181 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 182 | requestFocus(); 183 | setSelection(getText().length()); 184 | showKeyBoard(getContext()); 185 | return false; 186 | } 187 | return super.onTouchEvent(event); 188 | } 189 | 190 | @Override 191 | protected void onDraw(Canvas canvas) { 192 | mCurrentPosition = getText().length(); 193 | int width = mEachRectLength - getPaddingLeft() - getPaddingRight(); 194 | int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 195 | for (int i = 0; i < mFigures; i++) { 196 | canvas.save(); 197 | int start = width * i + i * mVerCodeMargin; 198 | int end = width + start; 199 | //画一个矩形 200 | if (i == mCurrentPosition) {//选中的下一个状态 201 | canvas.drawRect(start, 0, end, height, mSelectedBackgroundPaint); 202 | } else { 203 | canvas.drawRect(start, 0, end, height, mNormalBackgroundPaint); 204 | } 205 | canvas.restore(); 206 | } 207 | //绘制文字 208 | String value = getText().toString(); 209 | for (int i = 0; i < value.length(); i++) { 210 | canvas.save(); 211 | int start = width * i + i * mVerCodeMargin; 212 | float x = start + width / 2; 213 | TextPaint paint = getPaint(); 214 | paint.setTextAlign(Paint.Align.CENTER); 215 | paint.setColor(getCurrentTextColor()); 216 | Paint.FontMetrics fontMetrics = paint.getFontMetrics(); 217 | float baseline = (height - fontMetrics.bottom + fontMetrics.top) / 2 218 | - fontMetrics.top; 219 | canvas.drawText(String.valueOf(value.charAt(i)), x, baseline, paint); 220 | canvas.restore(); 221 | } 222 | //绘制底线 223 | for (int i = 0; i < mFigures; i++) { 224 | canvas.save(); 225 | float lineY = height - mBottomLineHeight / 2; 226 | int start = width * i + i * mVerCodeMargin; 227 | int end = width + start; 228 | if (i < mCurrentPosition) { 229 | canvas.drawLine(start, lineY, end, lineY, mBottomSelectedPaint); 230 | } else { 231 | canvas.drawLine(start, lineY, end, lineY, mBottomNormalPaint); 232 | } 233 | canvas.restore(); 234 | } 235 | //绘制光标 236 | if (!isCursorShowing && isCursorVisible() && mCurrentPosition < mFigures && hasFocus()) { 237 | canvas.save(); 238 | int startX = mCurrentPosition * (width + mVerCodeMargin) + width / 2; 239 | int startY = height / 4; 240 | int endX = startX; 241 | int endY = height - height / 4; 242 | canvas.drawLine(startX, startY, endX, endY, mCursorPaint); 243 | canvas.restore(); 244 | } 245 | } 246 | 247 | @Override 248 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 249 | mCurrentPosition = getText().length(); 250 | postInvalidate(); 251 | } 252 | 253 | @Override 254 | public void onTextChanged(CharSequence s, int start, int before, int count) { 255 | mCurrentPosition = getText().length(); 256 | postInvalidate(); 257 | if (onCodeChangedListener != null) { 258 | onCodeChangedListener.onVerCodeChanged(getText(), start, before, count); 259 | } 260 | } 261 | 262 | @Override 263 | public void afterTextChanged(Editable s) { 264 | mCurrentPosition = getText().length(); 265 | postInvalidate(); 266 | if (getText().length() == mFigures) { 267 | if (onCodeChangedListener != null) { 268 | onCodeChangedListener.onInputCompleted(getText()); 269 | } 270 | } else if (getText().length() > mFigures) { 271 | getText().delete(mFigures, getText().length()); 272 | } 273 | } 274 | 275 | @Override 276 | public void setFigures(int figures) { 277 | mFigures = figures; 278 | postInvalidate(); 279 | } 280 | 281 | @Override 282 | public void setVerCodeMargin(int margin) { 283 | mVerCodeMargin = margin; 284 | postInvalidate(); 285 | } 286 | 287 | @Override 288 | public void setBottomSelectedColor(@ColorRes int bottomSelectedColor) { 289 | mBottomSelectedColor = getColor(bottomSelectedColor); 290 | postInvalidate(); 291 | } 292 | 293 | @Override 294 | public void setBottomNormalColor(@ColorRes int bottomNormalColor) { 295 | mBottomSelectedColor = getColor(bottomNormalColor); 296 | postInvalidate(); 297 | } 298 | 299 | @Override 300 | public void setSelectedBackgroundColor(@ColorRes int selectedBackground) { 301 | mSelectedBackgroundColor = getColor(selectedBackground); 302 | postInvalidate(); 303 | } 304 | 305 | @Override 306 | public void setBottomLineHeight(int bottomLineHeight) { 307 | this.mBottomLineHeight = bottomLineHeight; 308 | postInvalidate(); 309 | } 310 | 311 | @Override 312 | public void setOnVerificationCodeChangedListener(OnVerificationCodeChangedListener listener) { 313 | this.onCodeChangedListener = listener; 314 | } 315 | 316 | /** 317 | * 返回颜色 318 | */ 319 | private int getColor(@ColorRes int color) { 320 | return ContextCompat.getColor(getContext(), color); 321 | } 322 | 323 | /** 324 | * dp转px 325 | */ 326 | private int dp2px(int dp) { 327 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, 328 | getResources().getDisplayMetrics()); 329 | } 330 | 331 | /** 332 | * 获取手机屏幕的宽度 333 | */ 334 | static int getScreenWidth(Context context) { 335 | DisplayMetrics metrics = new DisplayMetrics(); 336 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 337 | wm.getDefaultDisplay().getMetrics(metrics); 338 | return metrics.widthPixels; 339 | } 340 | 341 | public void showKeyBoard(Context context) { 342 | InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); 343 | imm.showSoftInput(this, InputMethodManager.SHOW_FORCED); 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /vcedittext-lib/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /vcedittext-lib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | VCEditText-Lib 3 | 4 | --------------------------------------------------------------------------------