編輯:關於Android編程
接著第一篇內容,來完成一下中間部分,中文驗證碼的部分,先看一下要實現的效果:
分析一下,我們要實現一個驗證碼功能,隨機生成4個中文組合,文字隨機,文字顏色隨機,文字會出現不同程度的旋轉,並且文字周圍會出現一些干擾項,點擊看不清時驗證碼內容會進行刷新重置.要解決的問題基本就這麼多,下面分步來解決一下.
(1)文字和文字顏色隨機,這個實現起來不難,只需要隨機產生一個中文,並且畫筆定義隨機的顏色即可.
(2)文字旋轉的話,可以通過旋轉畫布來完成該功能.
(3)對於干擾項,可以定義一個干擾項的數組,然後隨機取出裡邊的內容,在畫布上的隨機位置進行繪制即可.
(4)刷新重置這個做過很多遍,只需要重置一些變量,再去調用view的重繪方法即可.
通過上邊的分析,我們自定義一個CodeView來完成該功能.
先來定義一些自定義屬性,成員變量.代碼如下:
自定義屬性:
<code class="language-java hljs "><!--?xml version="1.0" encoding="utf-8"?--> <resources> <!--CodeView相關--> <!--擾亂項的個數--> <attr format="integer" name="disturbSize"> <!--干擾項文字的大小--> <attr format="dimension" name="disturbTextSize"> <!--干擾項文字顏色--> <attr format="color" name="disturbTextColor"> <!--驗證碼文字大小--> <attr format="dimension" name="codeTextSize"> <!--驗證碼文字顏色--> <attr format="color" name="codeTextColor"> <!--畫布旋轉的度數--> <attr format="integer" name="rotate"> <declare-styleable name="CodeView"> <attr name="disturbSize"> <attr name="disturbTextSize"> <attr name="disturbTextColor"> <attr name="codeTextSize"> <attr name="codeTextColor"> <attr name="rotate"> </code>
變量:
/**
* 干擾項
*/
private final char[] CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
/**
* 漢字畫筆
*/
private Paint hzPaint;
/**
* 干擾項畫筆
*/
private Paint dbPaint;
/**
* 漢字畫筆顏色
*/
private int hzColor;
/**
* 干擾項畫筆顏色
*/
private int dbColor;
/**
* 干擾項的個數,默認30個
*/
private int DEFAULT_DBSIZE;
/**
* 默認畫筆顏色
*/
private int DEFAULT_DBCOLOR, DEFAULT_HZCOLOR;
/**
* 干擾項隨機生成的位置
*/
private float dbRandomX, dbRandomY;
/**
* 驗證碼文字
*/
private List codeList;
/**
* 隨機
*/
private Random random = new Random();
/**
* 矩形區域
*/
private Rect mBounds;
/**
* 干擾文字大小
*/
private int dbTextSize;
/**
* 驗證碼文字大小
*/
private int hzTextSize;
/**
* 畫布旋轉度數,默認為6
*/
private int rotate;
public CodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取自定義屬性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CodeView);
DEFAULT_DBSIZE = ta.getInteger(R.styleable.CodeView_disturbSize, 30);
dbTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_disturbTextSize, 10));
hzTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_codeTextSize, 20));
DEFAULT_DBCOLOR = ta.getColor(R.styleable.CodeView_disturbTextColor, 0);
DEFAULT_HZCOLOR = ta.getColor(R.styleable.CodeView_codeTextColor, 0);
rotate = ta.getInteger(R.styleable.CodeView_rotate, 6);
init();
}
通過分析我們知道,我們需要隨機生成一個中文,然後還要隨機生成文字的顏色,所以先來寫一個工具類Util,方便之後的使用.
工具類:
package com.example.junweiliu.hanzicode;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.ListAdapter;
import java.io.UnsupportedEncodingException;
import java.util.Random;
/**
* Created by junweiliu on 16/5/9.
*/
public class Util {
/**
* 獲取隨機的顏色
*
* @return
*/
public static int randomColor() {
int red = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
return Color.argb(255, red, green, blue);
}
/**
* 獲取隨機的暗色
*
* @return
*/
public static int randomDarkColor() {
int red = (int) (Math.random() * 100 + 56);
int green = (int) (Math.random() * 100 + 56);
int blue = (int) (Math.random() * 100 + 56);
return Color.argb(255, red, green, blue);
}
/**
* 獲取指定長度隨機簡體中文
*
* @param len int
* @return String
*/
public static String getRandomJianHan(int len) {
String ret = "";
for (int i = 0; i < len; i++) {
String str = null;
int hightPos, lowPos; // 定義高低位
Random random = new Random();
hightPos = (176 + Math.abs(random.nextInt(39))); //獲取高位值
lowPos = (161 + Math.abs(random.nextInt(93))); //獲取低位值
byte[] b = new byte[2];
b[0] = (new Integer(hightPos).byteValue());
b[1] = (new Integer(lowPos).byteValue());
try {
str = new String(b, "GBk"); //轉成中文
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
ret += str;
}
return ret;
}
}
代碼不是很復雜,這裡定義了兩種顏色的獲取,使用的時候可以根據自己的需要來使用或者修改.
先來搞定干擾項的問題,干擾項已經定義過了,是一些數字和字母,隨機顏色的方法也寫在工具類了,之後就是去生成這些干擾項,生成之前,還需要隨機生成位置,然後去繪制在畫布上就可以了.
干擾項:
/**
* 創建干擾項
*
* @return
*/
private String createDBCode() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < DEFAULT_DBSIZE; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
/**
* 隨機生成干擾項畫筆樣式
*/
private void randomDBStyele() {
if (0 == DEFAULT_DBCOLOR) {
dbColor = Util.randomDarkColor();
} else {
dbColor = DEFAULT_DBCOLOR;
}
dbPaint = new Paint();
dbPaint.setColor(dbColor);
dbPaint.setTextSize(dbTextSize);
}
/**
* 隨機生成干擾項的顯示位置
*/
private void randomDBPosition() {
dbRandomX = (float) Math.random() * getWidth();
dbRandomY = (float) Math.random() * getHeight();
}
/**
* 繪制
*/
@Override
protected void onDraw(Canvas canvas) {
Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bp);
String dbCode = createDBCode();
// 繪制干擾項
for (int i = 0; i < dbCode.length(); i++) {
randomDBStyele();
randomDBPosition();
c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
}
canvas.drawBitmap(bp, 0, 0, dbPaint);
}
然後來看一下驗證文字,我們對外提供一個設置驗證文字的方法,因為這些需要驗證的文字肯定不是固定的,所以需要提供一個方法,來隨時改變這些驗證文字,獲取到這些驗證文字之後,就可以去繪制了.
驗證文字:
/**
* 設置驗證碼文字
*
* @param codes
*/
public void setCode(List codes) {
this.codeList = codes;
invalidate();
}
/**
* 隨機生成漢字畫筆樣式
*/
private void randomHZStyle() {
hzPaint = new Paint();
hzPaint.setColor(hzColor);
hzPaint.setFakeBoldText(random.nextBoolean());
hzPaint.setTextSize(hzTextSize);
hzPaint.getTextBounds("一", 0, "一".length(), mBounds);
}
/**
* 繪制
*/
@Override
protected void onDraw(Canvas canvas) {
Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bp);
String dbCode = createDBCode();
// 繪制干擾項
for (int i = 0; i < dbCode.length(); i++) {
randomDBStyele();
randomDBPosition();
c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
}
canvas.drawBitmap(bp, 0, 0, dbPaint);
// 繪制驗證文字
if (null != codeList && codeList.size() > 0) {
for (int i = 0; i < codeList.size(); i++) {
randomHZStyle();
canvas.save();
canvas.rotate((int) (Math.floor(Math.random() * rotate + 1)
- Math.floor(Math.random() * rotate * 2 + 1)));
canvas.drawText(codeList.get(i), mBounds.width() * (i + 1), getHeight() / 2 + mBounds.height() / 2, hzPaint);
canvas.restore();
}
}
}
繪制驗證文字的時候需要注意一下,這裡只是對畫布進行了一個旋轉操作,如果需要設計不同的效果,可以去添加修改這部分,如果需要特殊字體,也可以在初始化的時候去加載一些特殊字體,這裡就不去做這些內容了.
最後就是對外提供一個重置的方法,很簡單
/**
* 重置
*/
public void reSet(List codes) {
// 重置漢字畫筆顏色
if (0 == DEFAULT_HZCOLOR) {
hzColor = Util.randomDarkColor();
} else {
hzColor = DEFAULT_HZCOLOR;
}
this.codeList.clear();
this.codeList = codes;
invalidate();
}
CodeView:
package com.example.junweiliu.hanzicode;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by junweiliu on 16/5/9.
*/
public class CodeView extends ImageView {
/**
* 干擾項
*/
private final char[] CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
/**
* 漢字畫筆
*/
private Paint hzPaint;
/**
* 干擾項畫筆
*/
private Paint dbPaint;
/**
* 漢字畫筆顏色
*/
private int hzColor;
/**
* 干擾項畫筆顏色
*/
private int dbColor;
/**
* 干擾項的個數,默認30個
*/
private int DEFAULT_DBSIZE;
/**
* 默認畫筆顏色
*/
private int DEFAULT_DBCOLOR, DEFAULT_HZCOLOR;
/**
* 干擾項隨機生成的位置
*/
private float dbRandomX, dbRandomY;
/**
* 驗證碼文字
*/
private List codeList;
/**
* 隨機
*/
private Random random = new Random();
/**
* 矩形區域
*/
private Rect mBounds;
/**
* 干擾文字大小
*/
private int dbTextSize;
/**
* 驗證碼文字大小
*/
private int hzTextSize;
/**
* 畫布旋轉度數,默認為6
*/
private int rotate;
public CodeView(Context context) {
this(context, null);
}
public CodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
;
public CodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取自定義屬性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CodeView);
DEFAULT_DBSIZE = ta.getInteger(R.styleable.CodeView_disturbSize, 30);
dbTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_disturbTextSize, 10));
hzTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_codeTextSize, 20));
DEFAULT_DBCOLOR = ta.getColor(R.styleable.CodeView_disturbTextColor, 0);
DEFAULT_HZCOLOR = ta.getColor(R.styleable.CodeView_codeTextColor, 0);
rotate = ta.getInteger(R.styleable.CodeView_rotate, 6);
init();
}
/**
* 初始化
*/
private void init() {
// 驗證的文字顏色一致,只需要生成一次
if (0 == DEFAULT_HZCOLOR) {
hzColor = Util.randomDarkColor();
} else {
hzColor = DEFAULT_HZCOLOR;
}
mBounds = new Rect();
codeList = new ArrayList();
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bp);
String dbCode = createDBCode();
// 繪制干擾項
for (int i = 0; i < dbCode.length(); i++) {
randomDBStyele();
randomDBPosition();
c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
}
canvas.drawBitmap(bp, 0, 0, dbPaint);
// 繪制驗證文字
if (null != codeList && codeList.size() > 0) {
for (int i = 0; i < codeList.size(); i++) {
randomHZStyle();
canvas.save();
canvas.rotate((int) (Math.floor(Math.random() * rotate + 1)
- Math.floor(Math.random() * rotate * 2 + 1)));
canvas.drawText(codeList.get(i), mBounds.width() * (i + 1), getHeight() / 2 + mBounds.height() / 2, hzPaint);
canvas.restore();
}
}
// super.onDraw(canvas);
}
/**
* 重置
*/
public void reSet(List codes) {
// 重置漢字畫筆顏色
if (0 == DEFAULT_HZCOLOR) {
hzColor = Util.randomDarkColor();
} else {
hzColor = DEFAULT_HZCOLOR;
}
this.codeList.clear();
this.codeList = codes;
invalidate();
}
/**
* 設置驗證碼文字
*
* @param codes
*/
public void setCode(List codes) {
this.codeList = codes;
invalidate();
}
/**
* 隨機生成漢字畫筆樣式
*/
private void randomHZStyle() {
hzPaint = new Paint();
// hzPaint.setAntiAlias(true);
hzPaint.setColor(hzColor);
hzPaint.setFakeBoldText(random.nextBoolean());
hzPaint.setTextSize(hzTextSize);
hzPaint.getTextBounds("一", 0, "一".length(), mBounds);
}
/**
* 隨機生成干擾項畫筆樣式
*/
private void randomDBStyele() {
if (0 == DEFAULT_DBCOLOR) {
dbColor = Util.randomDarkColor();
} else {
dbColor = DEFAULT_DBCOLOR;
}
dbPaint = new Paint();
// dbPaint.setAntiAlias(true);
dbPaint.setColor(dbColor);
dbPaint.setTextSize(dbTextSize);
}
/**
* 隨機生成干擾項的顯示位置
*/
private void randomDBPosition() {
dbRandomX = (float) Math.random() * getWidth();
dbRandomY = (float) Math.random() * getHeight();
}
/**
* 創建干擾項
*
* @return
*/
private String createDBCode() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < DEFAULT_DBSIZE; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
}
xml:
<code class="language-java hljs "> <linearlayout android:gravity="center" android:id="@+id/ll_all" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" tools:context="com.example.junweiliu.hanzicode.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:hz="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <linearlayout android:background="@mipmap/hz_nor_ng" android:layout_height="wrap_content" android:layout_width="280dp" android:orientation="vertical" android:padding="20dp"> <linearlayout android:gravity="center" android:layout_height="wrap_content" android:layout_margintop="10dp" android:layout_width="match_parent" android:orientation="horizontal" android:visibility="visible"> <com.example.junweiliu.hanzicode.codeview android:id="@+id/cv_hz" android:layout_height="40dp" android:layout_width="120dp"> </com.example.junweiliu.hanzicode.codeview></linearlayout></linearlayout></linearlayout></code><button android:background="@null" android:id="@+id/btn_reset" android:layout_height="wrap_content" android:layout_marginleft="10dp" android:layout_width="wrap_content" android:text="看不清?" android:textcolor="#4791FF" android:textsize="14sp"><code class="language-java hljs "> </code></button>
MainActivity:
package com.example.junweiliu.hanzicode;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.Toast;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends Activity {
/**
* 驗證碼
*/
private CodeView mCodeView;
/**
* 重置按鈕
*/
private Button mResetBtn;
/**
* 正確答案
*/
private List mCorrectList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
/**
* 初始化數據
*/
private void initData() {
mCorrectList = new ArrayList();
// 添加文字
for (int i = 0; i < 4; i++) {
mCorrectList.add(Util.getRandomJianHan(1));
}
}
/**
* 初始化控件
*/
private void initView() {
mCodeView = (CodeView) findViewById(R.id.cv_hz);
mCodeView.setCode(mCorrectList);
mResetBtn = (Button) findViewById(R.id.btn_reset);
mResetBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 重置文字
initData();
// 刷新驗證碼
mCodeView.reSet(mCorrectList);
}
});
}
}
一、Android中的事件處理方法事件處理:響應用戶UI動作,提高應用程序交互性1、基於監聽的事件處理機制2、基於回調的事件處理機制3、Handler消息處理前面我們已經
WeTest導讀安卓開發者都知道,RecyclerView比ListView要靈活的多,但不可否認的裡面的坑也同樣埋了不少人。下面讓我們看看騰訊開發工程師用實例講解自己踩
先看效果圖 這個是我們自己的apk點擊之後的效果 下邊是布局文件vcD4KPHA+YWN0aXZpdHlfbWFpbi54bWzW97K8vtbOxLz+PG
上一篇文章中我們介紹了android社區中比較火的熱修復功能,並介紹了目前的幾個比較流行的熱修復框架,以及各自的優缺點,同時也介紹了一下自身項目中對熱修復功能的實踐。目前