Android自定义View扫描界面

项目需要做一个动态扫描界面,以此为记

下面是效果图

自定义View扫描界面

下面胃自定义代码,可放入xml布局文件中直接使用,可根据需求灵活画图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public final class ScanView extends View {
/**
* 刷新界面的时间
*/
private static final long ANIMATION_DELAY = 15L;
private static final int OPAQUE = 0xFF;

/**
* 中间那条线每次刷新移动的距离
*/
private static final int SPEEN_DISTANCE = 5;

/**
* 手机的屏幕密度
*/
private static float density;

/**
* 画笔对象的引用
*/
private Paint paint;

/**
* 中间滑动线的最顶端位置
*/
private int slideTop = 0;

/**
* 将扫描的二维码拍下来,这里没有这个功能,暂时不考虑
*/
private Bitmap resultBitmap;
private final int maskColor;
private int mWidth;
private int mHeight;

boolean isFirst;
private Rect frame;

public ScanView(Context context, AttributeSet attrs) {
super(context, attrs);

density = context.getResources().getDisplayMetrics().density;

paint = new Paint();
Resources resources = getResources();
maskColor = resources.getColor(R.color.viewfinder_mask);
}

@Override
public void onDraw(Canvas canvas) {
//获取屏幕的宽和高
mWidth = canvas.getWidth();
mHeight = canvas.getHeight();

int centerX = mWidth / 2;
int centerY = mHeight / 2;
frame = new Rect(centerX - centerX / 5 * 4, centerY - 150, centerX + centerX / 5 * 4, centerY + 150);
paint.setColor(maskColor);

//画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面
//扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边
canvas.drawRect(0, 0, mWidth, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, mWidth, frame.bottom + 1,
paint);
canvas.drawRect(0, frame.bottom + 1, mWidth, mHeight, paint);

paint.setColor(getResources().getColor(R.color.smoke_oranger));
paint.setStrokeWidth(4);
canvas.drawLine(frame.left, frame.top - 2, frame.left, frame.bottom, paint);
canvas.drawLine(frame.left, frame.top, frame.right + 2, frame.top, paint);
canvas.drawLine(frame.right, frame.top, frame.right, frame.bottom + 2, paint);
canvas.drawLine(frame.left - 2, frame.bottom, frame.right, frame.bottom, paint);

Rect rect1 = new Rect(frame.left, frame.top-250, frame.right, frame.bottom-250);
Rect rect2 = new Rect(frame.left, frame.top-250+60, frame.right, frame.bottom-250+60);
Paint textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(50);
textPaint.setStyle(Paint.Style.FILL);
//该方法即为设置基线上那个点究竟是left,center,还是right 这里我设置为center
textPaint.setTextAlign(Paint.Align.CENTER);

Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom

int baseLineY1 = (int) (rect1.centerY() - top/2 - bottom/2);//基线中间点的y轴计算公式
int baseLineY2 = (int) (rect2.centerY() - top/2 - bottom/2);//基线中间点的y轴计算公式

canvas.drawText("请将打码放到识别区域内",rect1.centerX(),baseLineY1,textPaint);
canvas.drawText("拍摄一张清晰的照片",rect1.centerX(),baseLineY2,textPaint);

//绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE
if (slideTop == 0){
slideTop = frame.top;
}
slideTop += SPEEN_DISTANCE;
if(slideTop >= frame.bottom){
slideTop = frame.top;
}
Rect lineRect = new Rect();
lineRect.left = frame.left;
lineRect.right = frame.right;
lineRect.top = slideTop;
lineRect.bottom = slideTop + 18;
canvas.drawBitmap(((BitmapDrawable)(getResources().getDrawable(R.drawable.qrcode_scan_line))).getBitmap(), null, lineRect, paint);

//只刷新扫描框的内容,其他地方不刷新
postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,
frame.right, frame.bottom);
}

public Rect getFrame() {
return frame;
}

public int getmHeight() {
return mHeight;
}

public int getmWidth() {
return mWidth;
}

}