设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间07 现在时间07 缓存数据 给自己一个目标,给自己一个希望,给自己一份爱、一份温暖,只为今天快乐,不为昨天烦恼,自己照顾好自己,我的朋友。

给自己一个目标,给自己一个希望,给自己一份爱、一份温暖,只为今天快乐,不为昨天烦恼,自己照顾好自己,我的朋友。

查看: 1697|回复: 2

Android自定义View实现两种二维码的扫描效果

[复制链接]

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
30
主题
26
精华
0
金钱
94
积分
60
注册时间
2023-10-2
最后登录
2025-6-1

发表于 2024-5-26 23:55:41 | 显示全部楼层 |阅读模式
目录


  • 背景
  • 横线效果
  • 网格效果
  • 基础属性
  • 绘制背景色
  • 绘制边框线
  • 绘制四个边角线
  • 扫描线绘制及移动
  • 特点

背景

最近在开发新项目时,使用了扫描二维码的功能,一般扫描二维码的效果是一条横线从上到下循环移动,这次却换成了网格图片。网上的大多数第三方库实现类似效果时 网格图片被拉伸变形。为了实现效果,只能动手写,话不多说,先看效果。(片尾附有代码地址)

横线效果

1.webp


网格效果

2.webp


基础属性

这里自定义了一些常见属性:
scan_image扫描图片资源scan_duration扫描一次时间 msscan_width正方形扫描框宽度scan_bg_color除正方形扫描框之外的背景颜色scan_rect_width正方形扫描框边框宽度scan_rect_color正方形扫描框边框颜色scan_border_width扫描框四个边角线的宽度scan_border_length扫描框四个边角线的长度scan_border_color扫描框四个边角线的颜色
绘制背景色

首先定义正方形扫描框矩形的位置,这么默认使用屏幕中心的位置
  1. private fun createRect() {
  2.         val leftOffset = (width - mScanWidth) / 2f
  3.         val topOffset = (height - mScanWidth) / 2f
  4.         mRectFrameRect =
  5.             RectF(leftOffset, topOffset, leftOffset + mScanWidth, topOffset + mScanWidth)

  6.         val scaleHeight = mScanWidth.toFloat() / mLineBitmap!!.width * mLineBitmap!!.height
  7.         mLineBitmap =
  8.             Bitmap.createScaledBitmap(mLineBitmap!!, mScanWidth, scaleHeight.toInt(), true)


  9.     }
复制代码
绘制背景色
  1. /**
  2.      * 绘制背景色
  3.      */
  4.     private fun drawScanBackground(canvas: Canvas?) {
  5.         mPaint?.style = Paint.Style.FILL
  6.         mPaint?.color = mBackgroundColor
  7.         val canvasWidth = canvas?.width
  8.         val canvasHeight = canvas?.height
  9.         mPaint?.let {
  10.             canvas?.drawRect(0f, 0f, canvasWidth!!.toFloat(), mRectFrameRect!!.top, it)
  11.             canvas?.drawRect(
  12.                 0f,
  13.                 mRectFrameRect!!.top - mBorderWidth / 2,
  14.                 mRectFrameRect!!.left,
  15.                 mRectFrameRect!!.bottom + mBorderWidth / 2,
  16.                 it
  17.             )
  18.             canvas?.drawRect(
  19.                 mRectFrameRect!!.right,
  20.                 mRectFrameRect!!.top - mBorderWidth / 2,
  21.                 canvasWidth!!.toFloat(),
  22.                 mRectFrameRect!!.bottom,
  23.                 it
  24.             )
  25.             canvas?.drawRect(
  26.                 0f,
  27.                 mRectFrameRect!!.bottom - mBorderWidth / 2,
  28.                 canvasWidth!!.toFloat(),
  29.                 canvasHeight!!.toFloat(),
  30.                 it
  31.             )
  32.         }

  33.     }
复制代码
将阴影部分分为四块,使用canvas.drawRect分别绘制。
3.jpeg


绘制边框线
  1. /**
  2.      * 画边框线
  3.      */
  4.     private fun drawBorderLine(canvas: Canvas?) {
  5.         mPaint?.color = mRectColor
  6.         mPaint?.style = Paint.Style.STROKE
  7.         mPaint?.strokeWidth = mRectWidth.toFloat()
  8.         mRectFrameRect?.let { mPaint?.let { it1 -> canvas?.drawRect(it, it1) } }
  9.     }
复制代码
通过上面定义的扫描框矩形,绘制扫描框的边框线。

绘制四个边角线

四个边角线为折线,使用自定义view中的path实现比较简单。
  1.     /**
  2.      * 画四个角
  3.      */
  4.     private fun drawBorderCorner(canvas: Canvas?) {
  5.         mPaint?.color = mBorderColor
  6.         mPaint?.style = Paint.Style.STROKE
  7.         val connerWidth = mBorderWidth / 2
  8.         mPaint?.strokeWidth = mBorderWidth.toFloat()

  9.         mPath.reset()
  10.         //左上     
  11.         mPath.moveTo(mRectFrameRect!!.left, mRectFrameRect!!.top - connerWidth + mBorderLength)
  12.         mPath.lineTo(mRectFrameRect!!.left, mRectFrameRect!!.top)
  13.         mPath.lineTo(mRectFrameRect!!.left - connerWidth + mBorderLength, mRectFrameRect!!.top)
  14.          //右上     
  15.         mPath.moveTo(mRectFrameRect!!.right + connerWidth - mBorderLength, mRectFrameRect!!.top)
  16.         mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.top)
  17.         mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.top - mBorderWidth + mBorderLength)
  18.         //左下   
  19.         mPath.moveTo(mRectFrameRect!!.left, mRectFrameRect!!.bottom + mBorderWidth - mBorderLength)
  20.         mPath.lineTo(mRectFrameRect!!.left, mRectFrameRect!!.bottom)
  21.         mPath.lineTo(mRectFrameRect!!.left - mBorderWidth + mBorderLength, mRectFrameRect!!.bottom)
  22.          //右下
  23.         mPath.moveTo(mRectFrameRect!!.right, mRectFrameRect!!.bottom + mBorderWidth - mBorderLength)
  24.         mPath.lineTo(mRectFrameRect!!.right, mRectFrameRect!!.bottom)
  25.         mPath.lineTo(mRectFrameRect!!.right + mBorderWidth - mBorderLength, mRectFrameRect!!.bottom)

  26.         canvas?.drawPath(mPath, mPaint!!)
  27.     }
复制代码
扫描线绘制及移动

绘制扫描线使用了canvas.drawBitmap 方法 ,通过裁剪显示位置绘制扫描图片。
  1.   /**
  2.      * 绘制扫描线
  3.      */
  4.     private fun drawScanLine(canvas: Canvas?) {
  5.         canvas?.save()
  6.         canvas?.restore()

  7.         val dstGridRectF = RectF(
  8.             mRectFrameRect!!.left,
  9.             mRectFrameRect!!.top,
  10.             mRectFrameRect!!.right,
  11.             mRectFrameRect!!.top + mMoveStep
  12.         )
  13.         val srcRect = Rect(
  14.             0,
  15.             (mLineBitmap!!.height - dstGridRectF.height()).toInt(),
  16.             mLineBitmap!!.width,
  17.             mLineBitmap!!.height
  18.         )
  19.         mLineBitmap?.let {
  20.             canvas?.drawBitmap(it, srcRect, dstGridRectF, mPaint)
  21.         }

  22.         mMoveStep += dp2px(3F)
  23.         if (mMoveStep >= mScanWidth + mLineBitmap!!.height / 2) {
  24.             mMoveStep = 0F
  25.         }
  26.         postInvalidateDelayed(mDelayTimes.toLong())
  27.     }
复制代码
这里通过调用postInvalidateDelayed 不停延迟绘制图片来实现扫描图的移动效果。

特点

像zxing 等三方库 直接使用扫描图片来绘制效果,由于扫描框是正方形,如果网格扫描图是长方形图片,则会导致被拉伸为正方形显示,图片变形。为了解决网格图的变形问题,这里对图片进行缩放处理,避免变形。
  1. val scaleHeight = mScanWidth.toFloat() / mLineBitmap!!.width * mLineBitmap!!.height
  2.         mLineBitmap =
  3.             Bitmap.createScaledBitmap(mLineBitmap!!, mScanWidth, scaleHeight.toInt(), true)
复制代码
代码简洁,不用区分是线性扫描还是网格扫描,都可以直接使用,使用时,只需传入需要的扫描图片即可。
项目地址:github.com/AndroidYou/ScanCodeView
以上就是Android自定义View实现两种二维码的扫描效果的详细内容,更多关于Android二维码扫描的资料请关注晓枫资讯其它相关文章!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
16
积分
12
注册时间
2022-12-26
最后登录
2022-12-26

发表于 2024-11-14 12:20:50 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:1
  • 打卡月天数:0
  • 打卡总奖励:9
  • 最近打卡:2025-04-16 08:17:01
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
22
积分
6
注册时间
2024-2-21
最后登录
2025-4-16

发表于 2025-4-11 02:02:35 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表