Android自定義View實現(xiàn)兩種二維碼的掃描效果
背景
最近在開發(fā)新項目時,使用了掃描二維碼的功能,一般掃描二維碼的效果是一條橫線從上到下循環(huán)移動,這次卻換成了網(wǎng)格圖片。網(wǎng)上的大多數(shù)第三方庫實現(xiàn)類似效果時 網(wǎng)格圖片被拉伸變形。為了實現(xiàn)效果,只能動手寫,話不多說,先看效果。(片尾附有代碼地址)
橫線效果

網(wǎng)格效果

基礎(chǔ)屬性
這里自定義了一些常見屬性:
| scan_image | 掃描圖片資源 |
|---|---|
| scan_duration | 掃描一次時間 ms |
| scan_width | 正方形掃描框?qū)挾?/td> |
| scan_bg_color | 除正方形掃描框之外的背景顏色 |
| scan_rect_width | 正方形掃描框邊框?qū)挾?/td> |
| scan_rect_color | 正方形掃描框邊框顏色 |
| scan_border_width | 掃描框四個邊角線的寬度 |
| scan_border_length | 掃描框四個邊角線的長度 |
| scan_border_color | 掃描框四個邊角線的顏色 |
繪制背景色
首先定義正方形掃描框矩形的位置,這么默認(rèn)使用屏幕中心的位置
private fun createRect() {
val leftOffset = (width - mScanWidth) / 2f
val topOffset = (height - mScanWidth) / 2f
mRectFrameRect =
RectF(leftOffset, topOffset, leftOffset + mScanWidth, topOffset + mScanWidth)
val scaleHeight = mScanWidth.toFloat() / mLineBitmap!!.width * mLineBitmap!!.height
mLineBitmap =
Bitmap.createScaledBitmap(mLineBitmap!!, mScanWidth, scaleHeight.toInt(), true)
}
繪制背景色
/**
* 繪制背景色
*/
private fun drawScanBackground(canvas: Canvas?) {
mPaint?.style = Paint.Style.FILL
mPaint?.color = mBackgroundColor
val canvasWidth = canvas?.width
val canvasHeight = canvas?.height
mPaint?.let {
canvas?.drawRect(0f, 0f, canvasWidth!!.toFloat(), mRectFrameRect!!.top, it)
canvas?.drawRect(
0f,
mRectFrameRect!!.top - mBorderWidth / 2,
mRectFrameRect!!.left,
mRectFrameRect!!.bottom + mBorderWidth / 2,
it
)
canvas?.drawRect(
mRectFrameRect!!.right,
mRectFrameRect!!.top - mBorderWidth / 2,
canvasWidth!!.toFloat(),
mRectFrameRect!!.bottom,
it
)
canvas?.drawRect(
0f,
mRectFrameRect!!.bottom - mBorderWidth / 2,
canvasWidth!!.toFloat(),
canvasHeight!!.toFloat(),
it
)
}
}
將陰影部分分為四塊,使用canvas.drawRect分別繪制。

繪制邊框線
/**
* 畫邊框線
*/
private fun drawBorderLine(canvas: Canvas?) {
mPaint?.color = mRectColor
mPaint?.style = Paint.Style.STROKE
mPaint?.strokeWidth = mRectWidth.toFloat()
mRectFrameRect?.let { mPaint?.let { it1 -> canvas?.drawRect(it, it1) } }
}
通過上面定義的掃描框矩形,繪制掃描框的邊框線。
繪制四個邊角線
四個邊角線為折線,使用自定義view中的path實現(xiàn)比較簡單。
/**
* 畫四個角
*/
private fun drawBorderCorner(canvas: Canvas?) {
mPaint?.color = mBorderColor
mPaint?.style = Paint.Style.STROKE
val connerWidth = mBorderWidth / 2
mPaint?.strokeWidth = mBorderWidth.toFloat()
mPath.reset()
//左上
mPath.moveTo(mRectFrameRect!!.left, mRectFrameRect!!.top - connerWidth + mBorderLength)
mPath.lineTo(mRectFrameRect!!.left, mRectFrameRect!!.top)
mPath.lineTo(mRectFrameRect!!.left - connerWidth + mBorderLength, mRectFrameRect!!.top)
//右上
mPath.moveTo(mRectFrameRect!!.right + connerWidth - mBorderLength, mRectFrameRect!!.top)
mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.top)
mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.top - mBorderWidth + mBorderLength)
//左下
mPath.moveTo(mRectFrameRect!!.left, mRectFrameRect!!.bottom + mBorderWidth - mBorderLength)
mPath.lineTo(mRectFrameRect!!.left, mRectFrameRect!!.bottom)
mPath.lineTo(mRectFrameRect!!.left - mBorderWidth + mBorderLength, mRectFrameRect!!.bottom)
//右下
mPath.moveTo(mRectFrameRect!!.right, mRectFrameRect!!.bottom + mBorderWidth - mBorderLength)
mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.bottom)
mPath.lineTo(mRectFrameRect!!.right + mBorderWidth - mBorderLength, mRectFrameRect!!.bottom)
canvas?.drawPath(mPath, mPaint!!)
}
掃描線繪制及移動
繪制掃描線使用了canvas.drawBitmap 方法 ,通過裁剪顯示位置繪制掃描圖片。
/**
* 繪制掃描線
*/
private fun drawScanLine(canvas: Canvas?) {
canvas?.save()
canvas?.restore()
val dstGridRectF = RectF(
mRectFrameRect!!.left,
mRectFrameRect!!.top,
mRectFrameRect!!.right,
mRectFrameRect!!.top + mMoveStep
)
val srcRect = Rect(
0,
(mLineBitmap!!.height - dstGridRectF.height()).toInt(),
mLineBitmap!!.width,
mLineBitmap!!.height
)
mLineBitmap?.let {
canvas?.drawBitmap(it, srcRect, dstGridRectF, mPaint)
}
mMoveStep += dp2px(3F)
if (mMoveStep >= mScanWidth + mLineBitmap!!.height / 2) {
mMoveStep = 0F
}
postInvalidateDelayed(mDelayTimes.toLong())
}
這里通過調(diào)用postInvalidateDelayed 不停延遲繪制圖片來實現(xiàn)掃描圖的移動效果。
特點
像zxing 等三方庫 直接使用掃描圖片來繪制效果,由于掃描框是正方形,如果網(wǎng)格掃描圖是長方形圖片,則會導(dǎo)致被拉伸為正方形顯示,圖片變形。為了解決網(wǎng)格圖的變形問題,這里對圖片進(jìn)行縮放處理,避免變形。
val scaleHeight = mScanWidth.toFloat() / mLineBitmap!!.width * mLineBitmap!!.height
mLineBitmap =
Bitmap.createScaledBitmap(mLineBitmap!!, mScanWidth, scaleHeight.toInt(), true)
代碼簡潔,不用區(qū)分是線性掃描還是網(wǎng)格掃描,都可以直接使用,使用時,只需傳入需要的掃描圖片即可。
項目地址:github.com/AndroidYou/ScanCodeView
以上就是Android自定義View實現(xiàn)兩種二維碼的掃描效果的詳細(xì)內(nèi)容,更多關(guān)于Android二維碼掃描的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android中利用xml文件布局修改Helloworld程序
這篇文章主要介紹了Android中利用xml文件布局修改Helloworld程序 的相關(guān)資料,需要的朋友可以參考下2016-07-07
Android開發(fā)之DatePickerDialog、TimePickerDialog時間日期對話框用法示例
這篇文章主要介紹了Android開發(fā)之DatePickerDialog、TimePickerDialog時間日期對話框用法,結(jié)合實例形式分析了Android使用DatePickerDialog、TimePickerDialog顯示日期時間相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實現(xiàn)
這篇文章主要介紹了Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
僅5步搞定Android開發(fā)環(huán)境部署 Android開發(fā)環(huán)境搭建教程
僅5步搞定Android開發(fā)環(huán)境部署,這篇文章主要為大家詳細(xì)介紹了Android開發(fā)環(huán)境搭建教程,感興趣的小伙伴們可以參考一下2016-02-02
Android RecyclerView自定義上拉和下拉刷新效果
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView自定義上拉和下拉刷新效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02

