Android 滑動驗證碼實踐
一大早起床就看到推送一篇文章,關于仿斗魚web端的滑動驗證碼,看了一下實現,挺有趣的,便自己順著思路擼一遍,改了一點實現和動畫什么的,順帶鞏固一下繪制的代碼。
先看一下效果圖
效果圖
效果還是不錯的。
用法,SlideValidationView 是繼承自ImageView,所以驗證碼圖片直接set就行。
SeekBar seekBar;
SlideValidationView slideValidationView;
slideValidationView = (SlideValidationView) findViewById(R.id.yzm);
// 設置監聽器,判斷驗證成功失敗時回調
slideValidationView.setListener(new SlideListener() {
@Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "驗證成功", Toast.LENGTH_SHORT).show();
seekBar.setProgress(0);
}
@Override
public void onFail() {
Toast.makeText(MainActivity.this, "驗證失敗", Toast.LENGTH_SHORT).show();
seekBar.setProgress(0);
}
});
seekBar = (SeekBar) findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// 更新驗證滑塊的位置
slideValidationView.setOffsetX(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) { }
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// 進行驗證碼的判斷
slideValidationView.deal();
}
});
下面說一下實現,也可以選擇去看代碼,代碼里面注釋應該很全了。代碼鏈接: 代碼 。看得喜歡關系點個star。
第一步:畫拼圖的path,上下左右四個半圓隨機凹凸
/**
* 創建驗證區域path
*/
private void creatValidationPath() {
validationPath = new Path();
if (validationSize == 0) {
validationSize = width/6;
}
circleSize = validationSize / 3;
startX = new Random().nextInt(width - validationSize * 2 - circleSize * 2 - 10) + circleSize + validationSize + 10;
startY = new Random().nextInt(height - validationSize - circleSize * 2) + circleSize;
// 從左上畫path到右上
validationPath.moveTo(startX, startY);
validationPath.lineTo(startX + circleSize, startY);
creatRandomArc(validationPath, startX + circleSize, startY, false, 0);
validationPath.lineTo(startX + validationSize, startY);
// 從右上畫path到右下
validationPath.lineTo(startX + validationSize, startY + circleSize);
creatRandomArc(validationPath, startX + validationSize, startY + circleSize, true, 0);
validationPath.lineTo(startX + validationSize, startY + validationSize);
// 從右下畫path到左下
validationPath.lineTo(startX + circleSize * 2, startY + validationSize);
creatRandomArc(validationPath, startX + circleSize, startY + validationSize, false, 1);
validationPath.lineTo(startX, startY + validationSize);
// 從左下畫path到左上
validationPath.lineTo(startX, startY + circleSize * 2);
creatRandomArc(validationPath, startX, startY + circleSize, true, 1);
validationPath.lineTo(startX, startY);
}
/**
* 驗證區域path四條邊的半圓弧度
* @param validationPath 要操作的path
* @param beginX 弧度的起始x坐標(取弧度的左邊坐標,即弧度的兩點,位于左邊的那個坐標)
* @param beginY 弧度的起始y坐標(取弧度的上邊坐標,即弧度的兩點,位于上邊的那個坐標)
* @param isleftRight 是否左右邊
* @param type 右上邊為0,左下邊為1
*/
private void creatRandomArc(Path validationPath, int beginX, int beginY, boolean isleftRight, int type) {
RectF rectF;
// 是左右邊還是上下邊
if (isleftRight) {
rectF = new RectF(beginX - circleSize / 2, beginY, beginX + circleSize / 2, beginY + circleSize);
} else {
rectF = new RectF(beginX, beginY - circleSize / 2, beginX + circleSize, beginY + circleSize / 2);
}
// 隨機得到是突出還是凹入半圓,針對角度問題,用type來解決
if (new Random().nextInt(10) > 5) {
// 突出半圓
if (isleftRight) {
validationPath.arcTo(rectF, -90 + type * 180, 180);
} else {
validationPath.arcTo(rectF, -180 + type * 180, 180);
}
} else {
// 凹入半圓
if (isleftRight) {
validationPath.arcTo(rectF, -90 + type * 180, -180);
} else {
validationPath.arcTo(rectF, -180 + type * 180, -180);
}
}
}
繪制拼圖path
第二步:繪制陰影(設置畫筆的setMaskFilter,應該要為這個view關閉硬件加速,否則陰影沒作用)
// 單獨為這個view關閉硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
陰影
// 驗證塊的陰影畫筆
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setColor(0x99000000);
// 設置畫筆遮罩濾鏡mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID));
繪制陰影
第三步:繪制滑塊
因為上面我們得到了拼圖的path,我們就創建一個bitmap,在里面分別繪制驗證碼原圖和這個path,通過setXfermode(不了解的可以去搜搜),取得他們的交集,即為我們的滑塊,由此我們通過一個變量來控制滑塊的繪制x軸就行了
// 以控件寬高 create一塊bitmap
Bitmap tempBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// 把創建的bitmap作為畫板
Canvas mCanvas = new Canvas(tempBitmap);
// 抗鋸齒
mCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
// 繪制用于遮罩的圓形
mCanvas.drawPath(mask, mMaskPaint);
// 設置遮罩模式(圖像混合模式)
mMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// 考慮到scaleType等因素,要用Matrix對Bitmap進行縮放
mCanvas.drawBitmap(mBitmap, getImageMatrix(), mMaskPaint);
第四步
繪制滑塊的陰影,這里面有個api我也是第一次接觸,bitmap.extractAlpha()拿到該bitmap的圖片大小等信息,但只有透明度沒有顏色,返回一張新的bitmap。我們通過設置畫筆的陰影來繪制新的bitmap即可繪制出滑塊的陰影
// extractAlpha拿到原bitmap的區域,只有透明度Bitmap
mMaskShadowBitmap = mMaskBitmap.extractAlpha();
繪制滑塊和陰影
一些方法
方法名 | 用處 |
---|---|
setOffsetX(float howMuch) | 設置滑塊移動距離(@param howMuch 0-100內數字,表示百分比) |
restore() | 重置驗證區域位置(重新生成拼圖path) |
deal() | 判斷是否成功 |
setListener(SlideListener listener) | 設置監聽器 |
本文由用戶 oberober 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!