Android自定義View實(shí)現(xiàn)兩種二維碼的掃描效果
背景
最近在開(kāi)發(fā)新項(xiàng)目時(shí),使用了掃描二維碼的功能,一般掃描二維碼的效果是一條橫線從上到下循環(huán)移動(dòng),這次卻換成了網(wǎng)格圖片。網(wǎng)上的大多數(shù)第三方庫(kù)實(shí)現(xiàn)類似效果時(shí) 網(wǎng)格圖片被拉伸變形。為了實(shí)現(xiàn)效果,只能動(dòng)手寫,話不多說(shuō),先看效果。(片尾附有代碼地址)
橫線效果
網(wǎng)格效果
基礎(chǔ)屬性
這里自定義了一些常見(jiàn)屬性:
scan_image | 掃描圖片資源 |
---|---|
scan_duration | 掃描一次時(shí)間 ms |
scan_width | 正方形掃描框?qū)挾?/td> |
scan_bg_color | 除正方形掃描框之外的背景顏色 |
scan_rect_width | 正方形掃描框邊框?qū)挾?/td> |
scan_rect_color | 正方形掃描框邊框顏色 |
scan_border_width | 掃描框四個(gè)邊角線的寬度 |
scan_border_length | 掃描框四個(gè)邊角線的長(zhǎng)度 |
scan_border_color | 掃描框四個(gè)邊角線的顏色 |
繪制背景色
首先定義正方形掃描框矩形的位置,這么默認(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) } } }
通過(guò)上面定義的掃描框矩形,繪制掃描框的邊框線。
繪制四個(gè)邊角線
四個(gè)邊角線為折線,使用自定義view中的path實(shí)現(xiàn)比較簡(jiǎn)單。
/** * 畫四個(gè)角 */ 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!!) }
掃描線繪制及移動(dòng)
繪制掃描線使用了canvas.drawBitmap 方法 ,通過(guò)裁剪顯示位置繪制掃描圖片。
/** * 繪制掃描線 */ 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()) }
這里通過(guò)調(diào)用postInvalidateDelayed 不停延遲繪制圖片來(lái)實(shí)現(xiàn)掃描圖的移動(dòng)效果。
特點(diǎn)
像zxing 等三方庫(kù) 直接使用掃描圖片來(lái)繪制效果,由于掃描框是正方形,如果網(wǎng)格掃描圖是長(zhǎng)方形圖片,則會(huì)導(dǎo)致被拉伸為正方形顯示,圖片變形。為了解決網(wǎng)格圖的變形問(wèn)題,這里對(duì)圖片進(jìn)行縮放處理,避免變形。
val scaleHeight = mScanWidth.toFloat() / mLineBitmap!!.width * mLineBitmap!!.height mLineBitmap = Bitmap.createScaledBitmap(mLineBitmap!!, mScanWidth, scaleHeight.toInt(), true)
代碼簡(jiǎn)潔,不用區(qū)分是線性掃描還是網(wǎng)格掃描,都可以直接使用,使用時(shí),只需傳入需要的掃描圖片即可。
項(xiàng)目地址:github.com/AndroidYou/ScanCodeView
以上就是Android自定義View實(shí)現(xiàn)兩種二維碼的掃描效果的詳細(xì)內(nèi)容,更多關(guān)于Android二維碼掃描的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android中利用xml文件布局修改Helloworld程序
這篇文章主要介紹了Android中利用xml文件布局修改Helloworld程序 的相關(guān)資料,需要的朋友可以參考下2016-07-07Android獲取本機(jī)電話號(hào)碼的簡(jiǎn)單方法
Android獲取本機(jī)電話號(hào)碼的簡(jiǎn)單方法,需要的朋友可以參考一下2013-05-05Android開(kāi)發(fā)之DatePickerDialog、TimePickerDialog時(shí)間日期對(duì)話框用法示例
這篇文章主要介紹了Android開(kāi)發(fā)之DatePickerDialog、TimePickerDialog時(shí)間日期對(duì)話框用法,結(jié)合實(shí)例形式分析了Android使用DatePickerDialog、TimePickerDialog顯示日期時(shí)間相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn)
這篇文章主要介紹了Android跨進(jìn)程傳遞大數(shù)據(jù)的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03僅5步搞定Android開(kāi)發(fā)環(huán)境部署 Android開(kāi)發(fā)環(huán)境搭建教程
僅5步搞定Android開(kāi)發(fā)環(huán)境部署,這篇文章主要為大家詳細(xì)介紹了Android開(kāi)發(fā)環(huán)境搭建教程,感興趣的小伙伴們可以參考一下2016-02-02Android RecyclerView自定義上拉和下拉刷新效果
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView自定義上拉和下拉刷新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02Android如何實(shí)現(xiàn)APP自動(dòng)更新
現(xiàn)在一般的android軟件都是需要不斷更新的,當(dāng)你打開(kāi)某個(gè)app的時(shí)候,如果有新的版本,它會(huì)提示你有新版本需要更新。該小程序?qū)崿F(xiàn)的就是這個(gè)功能。有需要的朋友們可以參考借鑒。2016-08-08