fist commit

This commit is contained in:
吃苹果的猫
2017-11-02 10:36:23 +08:00
commit b1a9ef5b83
48 changed files with 1145 additions and 0 deletions

1
verificationcodeview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,34 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

21
verificationcodeview/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,26 @@
package com.jyn.vcview;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.jyn.verificationcodeview.test", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jyn.vcview" />

View File

@@ -0,0 +1,216 @@
package com.jyn.vcview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.lang.reflect.Field;
/**
* @author jiaoyaning
* @package com.b2cf.nonghe.widget
* @filename VerificationCodeView
* @date 2017/10/31
*/
public class VerificationCodeView extends LinearLayout implements TextWatcher, View.OnKeyListener, View.OnFocusChangeListener {
private Context mContext;
private long endTime = 0;
private OnCodeFinishListener onCodeFinishListener;
/**
* 输入框数量
*/
private int mEtNumber;
/**
* 输入框的宽度
*/
private int mEtWidth;
/**
* 文字颜色
*/
private int mEtTextColor;
/**
* 文字大小
*/
private float mEtTextSize;
/**
* 输入框背景
*/
private int mEtTextBg;
private int mCursorDrawable;
public VerificationCodeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
@SuppressLint({"Recycle", "CustomViewStyleable"})
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.vericationCodeView);
mEtNumber = typedArray.getInteger(R.styleable.vericationCodeView_vcv_et_number, 4);
mEtWidth = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_width, 120);
mEtTextColor = typedArray.getColor(R.styleable.vericationCodeView_vcv_et_text_color, Color.BLACK);
mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_text_size, 16);
mEtTextBg = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_bg, R.drawable.et_login_code);
mCursorDrawable = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_cursor, R.drawable.et_cursor);
//释放资源
typedArray.recycle();
initView();
}
@SuppressLint("ResourceAsColor")
private void initView() {
for (int i = 0; i < mEtNumber; i++) {
EditText editText = new EditText(mContext);
int childHPadding = 14;
int childVPadding = 14;
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mEtWidth, mEtWidth);
layoutParams.bottomMargin = childVPadding;
layoutParams.topMargin = childVPadding;
layoutParams.leftMargin = childHPadding;
layoutParams.rightMargin = childHPadding;
layoutParams.gravity = Gravity.CENTER;
editText.setLayoutParams(layoutParams);
editText.setGravity(Gravity.CENTER);
editText.setId(i);
editText.setCursorVisible(true);
editText.setMaxEms(1);
editText.setTextColor(mEtTextColor);
editText.setTextSize(mEtTextSize);
editText.setMaxLines(1);
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setPadding(0, 0, 0, 0);
editText.setOnKeyListener(this);
editText.setBackgroundResource(mEtTextBg);
try {//修改光标的颜色(反射)
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(editText, mCursorDrawable);
} catch (Exception ignored) {
}
editText.addTextChangedListener(this);
editText.setOnFocusChangeListener(this);
editText.setOnKeyListener(this);
addView(editText);
if (i == 0) {
editText.setFocusable(true);
}
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() != 0) {
focus();
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
backFocus();
}
return false;
}
@Override
public void setEnabled(boolean enabled) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
child.setEnabled(enabled);
}
}
/**
* 获取焦点
*/
private void focus() {
int count = getChildCount();
EditText editText;
for (int i = 0; i < count; i++) {
editText = (EditText) getChildAt(i);
if (editText.getText().length() < 1) {
editText.setCursorVisible(true);
editText.requestFocus();
return;
} else {
editText.setCursorVisible(false);
}
}
EditText lastEditText = (EditText) getChildAt(mEtNumber - 1);
if (lastEditText.getText().length() > 0) {
lastEditText.requestFocus();
getResult();
}
}
private void backFocus() {
long startTime = System.currentTimeMillis();
EditText editText;
for (int i = mEtNumber - 1; i >= 0; i--) {
editText = (EditText) getChildAt(i);
if (editText.getText().length() >= 1 && startTime - endTime > 100) {
editText.setText("");
editText.setCursorVisible(true);
editText.requestFocus();
endTime = startTime;
return;
}
}
}
private void getResult() {
StringBuffer stringBuffer = new StringBuffer();
EditText editText;
for (int i = 0; i < mEtNumber; i++) {
editText = (EditText) getChildAt(i);
stringBuffer.append(editText.getText());
}
if (onCodeFinishListener != null) {
onCodeFinishListener.onComplete(stringBuffer.toString());
}
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
focus();
}
}
public interface OnCodeFinishListener {
void onComplete(String content);
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:width="2dp" />
<solid android:color="#0dbc75" />
</shape>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false">
<shape android:shape="rectangle">
<solid android:color="#FFFFFF" />
<stroke android:width="1dp" android:color="#C4C4C4" />
<corners android:radius="5dp" />
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="rectangle">
<solid android:color="#ffffff" />
<stroke android:width="1dp" android:color="#0dbc75" />
<corners android:radius="5dp" />
</shape>
</item>
</selector>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 自定义验证码输入框-->
<declare-styleable name="vericationCodeView">
<!--输入框的数量-->
<attr name="vcv_et_number" format="integer" />
<!--输入框的宽度-->
<attr name="vcv_et_width" format="dimension|reference" />
<!--输入框文字颜色-->
<attr name="vcv_et_text_color" format="color|reference" />
<!--输入框文字大小-->
<attr name="vcv_et_text_size" format="dimension|reference" />
<!--输入框背景-->
<attr name="vcv_et_bg" format="reference" />
<!--光标样式-->
<attr name="vcv_et_cursor" format="reference" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">VerificationCodeView</string>
</resources>

View File

@@ -0,0 +1,17 @@
package com.jyn.vcview;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}