Android - Custom external shadow, internal transparent canvas mask layout

Explain:

A simple requirement, the external shadow, the internal layout is transparent, and the camera is opened at the bottom (here only the layout code, click here with the camera).

Code:

1. Call

Just call in Activity, set the height and width of the middle area.

Activity code

private OcrFaceMaskSurfaceView surfaceview;
surfaceview = (OcrFaceMaskSurfaceView) findViewById(R.id.surface_view);
surfaceview.setMaskSize(900, 600);

Activity layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#EFEFF4"
    android:orientation="vertical"
    tools:context=".WebViewActivity">

    <com.gxjl.pe.gxjlpesdk.view.OcrFaceMaskSurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

    </com.gxjl.pe.gxjlpesdk.view.OcrFaceMaskSurfaceView>

</LinearLayout>

2. OcrFaceMaskSurfaceView.java is a custom canvas

Implementation ideas:

(1) Two layers of canvas in the custom layout. The first layer is just to start and load the camera

(2) The second layer draws the outer shadow and the inner transparency, plus the inner text

The code is as follows: (CameraHelper is a camera tool class, which can be commented out. Click here to see the complete code with camera + demo)

(3) UiUtil utility class- click here

(4) The code notes are very clear

package com.gxjl.pe.gxjlpesdk.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;

import com.gxjl.pe.gxjlpesdk.camrea.CameraHelper;
import com.gxjl.pe.gxjlpesdk.util.UiUtil;

public class OcrFaceMaskSurfaceView extends FrameLayout {

    private Context context;
    private MSurfaceView surfaceView;//Load mask for camera
    private MaskView maskView;//Load mask for layout
    private int width;//Screen width
    private int height;//Screen height
    private int maskWidth;//Middle transparent area width
    private int maskHeight;//Height of transparent area in the middle
    private int screenWidth;//Camera capture width
    private int screenHeight;//Camera capture height

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

        this.context = context;

        surfaceView = new MSurfaceView(context);//The first layer of canvas is used to load the camera
        maskView = new MaskView(context);//The second layer of canvas is used to draw all the layouts
        this.addView(surfaceView, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        this.addView(maskView, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        screenHeight = display.getHeight();
        screenWidth = display.getWidth();
        CameraHelper.getInstance().setMaskSurfaceView(this);
    }

    public void setMaskSize(Integer width, Integer height) {
        maskHeight = height;
        maskWidth = width;
    }

    public int[] getMaskSize() {
        return new MaskSize().size;
    }

    private class MaskSize {
        private int[] size;

        private MaskSize() {
            this.size = new int[]{maskWidth, maskHeight, width, height};
        }
    }

    /**
     * Layout of the carrying camera
     */
    private class MSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
        private SurfaceHolder holder;

        public MSurfaceView(Context context) {
            super(context);
            this.holder = this.getHolder();
            //Transparent transparent
            this.holder.setFormat(PixelFormat.TRANSPARENT);
            this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            this.holder.addCallback(this);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            width = w;
            height = h;
            CameraHelper.getInstance().openCamera(holder, format, width, height, screenWidth, screenHeight);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            CameraHelper.getInstance().releaseCamera();
        }
    }

    /**
     * All layout of mask layer
     */
    private class MaskView extends View {
        private Paint linePaint;
        private Paint rectPaint;
        private Paint topTextPaint;
        private Paint bottomTextPaint;

        public MaskView(Context context) {
            super(context);

            //Paint the rectangle border of the transparent area in the middle
            linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            linePaint.setColor(Color.TRANSPARENT);//Set the middle area color to transparent
            linePaint.setStyle(Style.STROKE);
            linePaint.setStrokeWidth(3f);
            linePaint.setAlpha(0);//The value range is 0-255, the smaller the value, the more transparent

            //Draw rectangular shadow area around
            rectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            rectPaint.setColor(Color.BLACK);
            rectPaint.setStyle(Style.FILL);
            rectPaint.setAlpha(170);//The value range is 0-255, the smaller the value, the more transparent

            //Draw top middle prompt font
            topTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            topTextPaint.setColor(Color.WHITE);
            //topTextPaint.setStyle(Paint.Style.FILL);
            topTextPaint.setTextAlign(Paint.Align.CENTER);//Put the x,y coordinates in the middle of the font (the default x,y coordinates are the font head)
            topTextPaint.setTextSize(UiUtil.sp2px(context, 14));

            //Draw top middle prompt font
            bottomTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            bottomTextPaint.setColor(Color.parseColor("#A0A0A0"));
            //bottomTextPaint.setStyle(Paint.Style.FILL);
            bottomTextPaint.setTextAlign(Paint.Align.CENTER);//Put the x,y coordinates in the middle of the font (the default x,y coordinates are the font head)
            bottomTextPaint.setTextSize(UiUtil.sp2px(context, 12));
        }

        @Override
        protected void onDraw(Canvas canvas) {
            if (maskHeight == 0 && maskWidth == 0) {
                return;
            }
            if (maskHeight == height || maskWidth == width) {
                return;
            }

            if ((height > width && maskHeight < maskWidth) || (height < width && maskHeight > maskWidth)) {
                int temp = maskHeight;
                maskHeight = maskWidth;
                maskWidth = temp;
            }

            //Height: screen height
            //Width: screen width
            //maskHeight: height of transparent area in the middle
            //maskWidth: width of transparent area in the middle
            int h = Math.abs((height - maskHeight) / 2);//Top shadow height
            int w = Math.abs((width - maskWidth) / 2);//Right shadow width

            //Upper shadow
            canvas.drawRect(0, 0, width, h, this.rectPaint);
            //Right shadow
            canvas.drawRect(width - w, h, width, height - h, this.rectPaint);
            //Lower shadow
            canvas.drawRect(0, height - h, width, height, this.rectPaint);
            //Left shadow
            canvas.drawRect(0, h, w, h + maskHeight, this.rectPaint);
            //Medium transparency
            canvas.drawRect(w, h, w + maskWidth, h + maskHeight, this.linePaint);
            canvas.save();//Save the top, bottom, left, right, middle
            //Medium top font
            canvas.rotate(90, width - w / 2, height/2);//Rotate the canvas 90 degrees
            canvas.drawText("Please scan the face of your ID witness", width - w / 2, height/2, topTextPaint);
            canvas.restore();//Restore the canvas to the last saved position to prevent this rotation from affecting the following operations
            //Middle bottom font
            canvas.rotate(90,w / 2, height/2);//Rotate 90 degrees
            canvas.drawText("Please keep the light sufficient, the background clean, and the mobile phone level with the card", w / 2, height/2, bottomTextPaint);

            //Print logo
            Log.e("Height width", "height:" + height + ",width:" + width + ",h:" + h + ",w:" + w + ",mskHeight:" + maskHeight + ",maskWidth:" + maskWidth);

            super.onDraw(canvas);
        }
    }
}

Notes:

When using canvas canvas, pay attention to use save and restore. Because rotation is used to rotate the entire canvas, the layout behind will be affected. Therefore, before restoring the canvas to save, the new layout will not be affected.

Tags: Android SurfaceView xml encoding

Posted on Sun, 05 Jan 2020 11:00:14 -0500 by mpunn