Preface
This article continues with the previous one. Google ZXing Series Explanations (4) - ZXing Solves the Problem of Vertical Screen Scanning . In the previous article, through issue reply in the official github of zxing, the problem that both horizontal and vertical screens of zxing can scan barcode and two-dimensional code is solved.
Only this is not cool enough, if the scanning interface can be as good as Wechat, yes, teenager!
The objectives of this paper are:
- Explore how ViewfinderView draws the default UI
- Customizing ZXing UI by Imitating Wechat
Less nonsense, code, stamp here
Default Scan UI
Look at the zxing source code and customize this block in the class ViewfinderView. It is mainly processed in onDraw method.
Next, we analyze ZXing's Default scan line, and then modify it to Wechat's UI.
Calculation of Default Rectangular Size
For the time being, the menu and other options in the figure are not considered.
The coordinate image is abstracted as:
Here, the horizontal axis demonstrates that the top left corner is the origin of the whole mobile phone screen, extending to the right as the X axis, and downward as the Y axis.
In ViewfinderView - > onDraw, the size of the intermediate frame is obtained first.
Rect frame = cameraManager.getFramingRect();
The analysis code found that ZXing's default scanning frame has a range of 240 x 240, 1200 x 675 and 5/8 of 1920 x 1080.
private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080
Once you get the size, you can draw the size of the frame on the canvas and shadow the surrounding area!
// Draw the exterior (i.e. outside the framing rect) darkened
paint.setColor(resultBitmap != null ? resultColor : maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
Specific ideas come in accordance with the four areas on the map!
Default Laser Line
// Draw a red "laser scanner" line through the middle to show decoding is active
paint.setColor(laserColor);
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
Default pitting
In the process of scanning, there will be dots. This is handled by the following key code segments! __________
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint);
}
}
}
Imitating Wechat Scanning UI
Wechat scans UI and needs to modify ViewfinderView and add some resource files! Let's start with the Wechat Scan UI diagram.
The following aspects need to be clarified in imitating the scanning frame of Wechat:
- Rectangular box size
- Graphics and Colors of Quadrangles of Rectangular Box
- Scanning Animation
Rectangular box size
In horizontal screen, ZXing uses the default size 675 x 1200, while in vertical screen, ZXing uses the default size 240 x 240.
The key code snippet is as follows: @CameraManager
public synchronized Rect getFramingRect() {
int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
int leftOffset = (screenResolution.x - width) / 2;
int topOffset = (screenResolution.y - height) / 2;
... ...
}
private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
int dim = 5 * resolution / 8; // Target 5/8 of each dimension
if (dim < hardMin) {
return hardMin;
}
if (dim > hardMax) {
return hardMax;
}
return dim;
}
Graphics and Colors of Quadrangles of Rectangular Box
There are several ways to choose a picture.
Draw 8 lines.
- Draw eight rectangles
Discovered the article by accident A column on maple leaves The author implements a android-zxingLibrary Looking at the code about drawing borders in the lib, we found that eight of them were drawn in a rectangular way, and they were designed with AttributeSet. We can set the width and height of borders in xml. Details will be given below.
Scan animation
Lines that move up and down are in the form of pictures. The principle of scanning animation is very simple. The onDraw method is constantly called by the system, in which the distance to move up and down is controlled, and the distance can be judged!
private void drawScanLight(Canvas canvas, Rect frame) {
if (scanLineTop == 0) {
scanLineTop = frame.top;
}
if (scanLineTop >= frame.bottom - 30) {
scanLineTop = frame.top;
} else {
scanLineTop += SCAN_VELOCITY;// SCAN_VELOCITY can be set in attributes by default of 5
}
Rect scanRect = new Rect(frame.left, scanLineTop, frame.right, scanLineTop + 30);
canvas.drawBitmap(scanLight, null, scanRect, paint);
}
Implementation steps
1.attrs file
Add attrs file to the values directory for reference android-zxingLibrary
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="innerrect">
<attr name="inner_width" format="dimension"/>
<attr name="inner_height" format="dimension"/>
<attr name="inner_margintop" format="dimension" />
<attr name="inner_corner_color" format="color" />
<attr name="inner_corner_length" format="dimension" />
<attr name="inner_corner_width" format="dimension" />
<attr name="inner_scan_bitmap" format="reference" />
<attr name="inner_scan_speed" format="integer" />
<attr name="inner_scan_iscircle" format="boolean" />
</declare-styleable>
</resources>
This article does not use all the attributes. Where do these attributes work? The answer is layout - > capture. XML in the project directory
<com.google.zxing.client.android.ViewfinderView
android:id="@+id/viewfinder_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:inner_corner_length="30dp" //Length of a rectangle with four green corners
app:inner_corner_width="5dp" //The Width of a Quadrilateral Green Rectangle
app:inner_scan_bitmap="@drawable/scanline" //You need to add scanline images to the drawable directory
app:inner_scan_speed="10" // Scanning line moving distance
app:inner_scan_iscircle="true" /> //Does the spot appear during scanning?
2.ViewfinderView modification
Many of them have been modified, including:
- public ViewfinderView(Context context, AttributeSet attrs)
- private void initInnerRect(Context context, AttributeSet attrs)
- public void onDraw(Canvas canvas)
- private void drawFrameBounds(Canvas canvas, Rect frame)
- private void drawScanLight(Canvas canvas, Rect frame)
Key points are all annotated with //add by tan