一大早起床就看到推送一篇文章,關於仿鬥魚web端的滑動驗證碼,看了一下實現,挺有趣的,便自己順著思路擼一遍,改了一點實現和動畫什麼的,順帶鞏固一下繪製的程式碼。
這裡也貼一下原作者文章連結:http://qingmang.me/articles/-4771769944547152798
本文程式碼連結:程式碼。看得喜歡關係點個star。
先看一下效果圖
效果還是不錯的。用法,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);
}
}
}
複製程式碼
第二步:繪製陰影(設定畫筆的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) | 設定監聽器 |
詳細請去看程式碼,程式碼裡面註釋應該很全了。程式碼連結:程式碼。看得喜歡關係點個star。