Android-自定义View实现二维码网格扫描+纵向雷达的扫描效果
最终效果如图:
1.可以看到整体是一个网格+纵向雷达扫描效果,因此首先我们先画出如下的静态效果,如下图
2.新建个View命名为ScanView 继承自View,并且在onLayout中初始化扫描区域为该组件中间的一块正方形
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int measuredHeight = this.getMeasuredHeight();
int measuredWidth = this.getMeasuredWidth();
int rectHeight = 5 * measuredHeight / 8;
int rectWidth = 5 * measuredWidth / 8;
int rectLen = rectHeight>rectWidth?rectWidth:rectHeight;
int rectLeft = (measuredWidth - rectLen) / 2;
int rectTop = (measuredHeight - rectLen) / 2;
mFrame = new Rect(rectLeft,rectTop,rectLeft+rectLen,rectTop+rectLen);//初始化扫描区域所在的Rect
initBoundaryAndAnimator();//初始化动画效果及边框样式
}
3.根据扫描区域的Reat绘制四个顶点的角线,此处我们使用path绘制先构建出定点角线的路径如下,初始化动画的处理可先不管
private void initBoundaryAndAnimator() {
if (mBoundaryLinePath == null) {
mCornerLineLen = mFrame.width() * mCornerLineLenRatio;//mCornerLineLenRatio 是定点处线的长度站边长的比例
mBoundaryLinePath = new Path();//初始化Path
mBoundaryLinePath.moveTo(mFrame.left, mFrame.top + mCornerLineLen);//添加要绘制线的path到路径上
mBoundaryLinePath.lineTo(mFrame.left, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.left + mCornerLineLen, mFrame.top);
mBoundaryLinePath.moveTo(mFrame.right - mCornerLineLen, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.top + mCornerLineLen);
mBoundaryLinePath.moveTo(mFrame.right, mFrame.bottom - mCornerLineLen);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.right - mCornerLineLen, mFrame.bottom);
mBoundaryLinePath.moveTo(mFrame.left + mCornerLineLen, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom - mCornerLineLen);
}
if (mValueAnimator == null) {
initScanValueAnim(mFrame.height());//初始化动画效果
}
}
4.然后初始化网格的路径如下,要想使绘制出来的效果是渐变的则需要在初始化画笔时添加一个Shader(着色器),此处我们需要的是一个线性渐变的效果所以我们初始化一个LinearGradient的着色器。
ps:LinearGradient 的使用比较简单,但此处我们需要注意一下我们构建时使用的模式是 LinearGradient.TileMode.CLAMP,即当着色器的不能填满所要绘制的区域时的模式为拉伸最后一个像素。而此处我们最后的0.99f-1f区域设置的是Color.TRANSPARENT,所以当填不满时会拉伸透明像素,相当于图像截取到此处,这是后面动画效果实现的关键
mScanPaint_Gridding = new Paint(Paint.ANTI_ALIAS_FLAG);
mScanPaint_Gridding.setStyle(Paint.Style.STROKE);//设置Style为STROKE
mScanPaint_Gridding.setStrokeWidth(mGriddingLineWidth);//设置线宽
//初始化网格路径,及绘制该忘咯时所需要的画笔
private void initGriddingPathAndStyle() {
if (mGriddingPath == null) {//初始化路径
mGriddingPath = new Path();
float wUnit