preface

The design of verification is mainly for security consideration, to prevent the machine from directly carrying out some operations, and then many people develop ideas to design a lot of different types of verification code, the following will be through Android custom View to achieve graphic lock function.

rendering

It can be seen from the figure that there is no particularly difficult point. At most, it is how to pick out the verified figure randomly. Here, Xfermode, the image mixing mode, is used for image clipping.

The core idea

First, first of all to have a picture as aLock the child, the following is an example.

First we just get the picture, and then we have to dig out a piece of the lock in a position. In order to look good, our lock core should have a certain interval with the upper and lower.

Second, a picture aslockAnd then pick a random X coordinatelockAnd generatelock

Among them, the green point is the center point of the picture, the white point is the size of the lock core, the black point is the shape of the lock core, and the rest shows the content of the lock because it is transparent.

The Xfermode of Paint is set on the third and second draws to fetch different contentLock the child,The key,lockTo separate.

Xfermode is one of the most important modes in Android graphics, but it can be easily solved by Paint’s Xfermode. Just start with the usual ones. The following will not be repeated, there is a drawing rounded picture case for reference, the content is simple to believe that you will understand after reading! Blog. Lost520. Cn/study/show -…

If you are interested can refer to the great god’s blog: blog.csdn.net/harvic88092…

Core code for drawing locks and keys:

/** * Get the lock or key *@paramThe lock lock *@paramKeyTemp Key template *@paramKeyLocation Location of the key in the lock *@paramMode 1: lock, 2: key *@return* /
private Bitmap getKeyOrLock(Bitmap lock, Bitmap keyTemp, Rect keyLocation, int mode) {
    // Set the Bitmap size according to mode
    int width = lock.getWidth();
    int height = lock.getHeight();
    if (mode == 2) {
        width = keyTemp.getWidth();
        height = keyTemp.getHeight();
    }
    Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);// Draw the result
    Canvas canvas = new Canvas(result);/ / drawing board
    Paint paint = new Paint();/ / brush
    // According to the mode set different PorterDuffXfermode to achieve different mask effect
    if (mode == 1) {// Draw the lock
        canvas.drawBitmap(keyTemp, keyLocation.left, keyLocation.top, paint);/ / draw the DST
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawBitmap(lock, 0.0, paint);/ / draw the SRC
    } else {// Draw the key
        canvas.drawBitmap(keyTemp, 0.0, paint);/ / draw the DST
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(lock, -keyLocation.left, -keyLocation.top, paint);/ / draw the SRC
    }
    return result;
}
Copy the code


The fourth,Lock the child(with a locking core) andThe keyDraw each to a specific location.

The lock can be directly tiled, the lock core can be randomly drawn value, the key is drawn in the left for the user to slide.

Fifth, detect the user drag, verify the key and lock core center point is overlapping.

Rewrite the onTouchEvent function in View to detect the user’s drag. When the user clicks the key and the lock to drag, calculate whether the center point of the key and the lock core is merged (a specific offset can be added), and call back the processing result directly after the user releases it. To this five basic completed the graphic lock function.

The core code

Split lock and key:

/** * get the lock or key **@paramThe lock lock *@paramKeyTemp Key template *@paramKeyLocation Location of the key in the lock *@paramMode 1: lock, 2: key *@return* /
private Bitmap getKeyOrLock(Bitmap lock, Bitmap keyTemp, Rect keyLocation, int mode) {
    // Set the Bitmap size according to mode
    int width = lock.getWidth();
    int height = lock.getHeight();
    if (mode == 2) {
        width = keyTemp.getWidth();
        height = keyTemp.getHeight();
    }
    Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);// Draw the result
    Canvas canvas = new Canvas(result);/ / drawing board
    Paint paint = new Paint();/ / brush
    // According to the mode set different PorterDuffXfermode to achieve different mask effect
    if (mode == 1) {// Draw the lock
        canvas.drawBitmap(keyTemp, keyLocation.left, keyLocation.top, paint);/ / draw the DST
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawBitmap(lock, 0.0, paint);/ / draw the SRC
    } else {// Draw the key
        canvas.drawBitmap(keyTemp, 0.0, paint);/ / draw the DST
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(lock, -keyLocation.left, -keyLocation.top, paint);/ / draw the SRC
    }
    return result;
}
Copy the code

Draw a specific size picture:

/** * Draws the image to a specific size **@paramBitmap images *@paramWidth the width *@param* height height@return* /
private Bitmap resizeBitmap(Bitmap bitmap, int width, int height) {
    Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(result);
    Rect rect = new Rect(0.0, width, height);
    canvas.drawBitmap(bitmap, null, rect, null);
    return result;
}
Copy the code

Layout:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.demo.qylost.puzzleunlockdemo.MainActivity">
    <com.demo.qylost.puzzleunlockdemo.PuzzleUnlockView
        android:id="@+id/puzzleUnlockView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/btnUpdate"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="? selectableItemBackground"
        android:text="Change the picture"
        android:textColor="@color/colorAccent" />
    <Button
        android:id="@+id/btnRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="? selectableItemBackground"
        android:text="Refresh"
        android:textColor="@color/colorAccent" />
    <TextView
        android:id="@+id/txtStatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Status: XXX"
        android:textColor="@color/colorAccent" />
</LinearLayout>
Copy the code

Background:

// Get the relevant controls
Button btnUpdate = findViewById(R.id.btnUpdate);
Button btnRefresh = findViewById(R.id.btnRefresh);
// Custom lock View
final PuzzleUnlockView puzzleUnlockView = findViewById(R.id.puzzleUnlockView);
// Display the status
final TextView txtStatus = findViewById(R.id.txtStatus);

// Change the image
btnUpdate.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) { puzzleUnlockView .setLockBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.lock2)); }});/ / refresh
btnRefresh.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) { puzzleUnlockView.refreshLock(); }});// Validate the callback
puzzleUnlockView.setOnLockResultListener(new PuzzleUnlockView.OnLockResultListener() {
    @Override
    public void onResult(boolean result) {
        if (result) {
            txtStatus.setText("Status: Success");
        } else {
            txtStatus.setText("Status: Failed");
            puzzleUnlockView.refreshLock();/ / refresh}}});Copy the code

Source code + material

Source code + material. Zip