Android SDK - camera2 - Draw rectangle over Textur

2019-02-09 01:06发布

问题:

Im new to android development, and I'm finding it hard to find good examples on the camera2 api.

Im working my way slowly through most issues, but on this one I am stuck. In the default camera, when you touch the screen to focus, it shows a rectangle of the focus area for a moment. I want to do something similar (Or in this case, the exact same thing to start off with so i can figure it out).

I read somewhere (I think the TextureView page in the SDK docs) that you cant draw on a textureview while its being used as a camera preview - and calling the lock method will return null rather than a canvas.

I found this online: https://github.com/commonsguy/vidtry/ But i cant get it to work. I either get errors saying my my main view cant be cast to my drawable view, or vice versa - Or my drawable view is on top and makes the screen black - Or its on the bottom and wont respond to touch events (and trying to force the performClick from the view above it casues crashes.)

Im stuck! Can anyone give me an explanation or example of how i can draw my rectangle over the event position for a few sconds?

Thanks!

回答1:

  1. First for example of camera2 api android there is an open source google sample code. https://github.com/googlesamples/android-Camera2Basic
  2. Second for Part where you want to draw a rectangle(touch to focus) follow these steps -
    • Create a custom class extending to SurfaceView.
    • call onTouchListener method in this custom class to detect finger coordinates and draw your rectangle using paint class in android. -add this custom class above your TextureView that is displaying preview from camera2.
    • turn the custom view transparent.
    • finally when you touch at some point on device screen then onTouchListener will be called which will draw on the canvas of custom view you added above you camera preview.
    • finally clear your canvas so you dont keep adding rectangles to customview since you need one rect at one point of time.
    • also if not touched for some time the rectangle should disappear. do this using a handler from custom view.

I am giving you here a tested code to do this. i hope it helps you. BEST OF LUCK.

 private class CustomView extends SurfaceView {

    private final Paint paint;
    private final SurfaceHolder mHolder;
    private final Context context;

    public CustomView(Camera2BasicFragment context) {
        super(context.getActivity().getBaseContext());
        mHolder = getHolder();
        mHolder.setFormat(PixelFormat.TRANSPARENT);
        this.context = context.getActivity().getBaseContext();
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            invalidate();
            if (mHolder.getSurface().isValid()) {
                final Canvas canvas = mHolder.lockCanvas();
                Log.d("touch", "touchRecieved by camera");
                if (canvas != null) {
                    Log.d("touch", "touchRecieved CANVAS STILL Not Null");
                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    canvas.drawColor(Color.TRANSPARENT);
                    canvas.drawCircle(event.getX(), event.getY(), 100, paint);
                    mHolder.unlockCanvasAndPost(canvas);
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Canvas canvas1 = mHolder.lockCanvas();
                            if(canvas1 !=null){
                                canvas1.drawColor(0, PorterDuff.Mode.CLEAR);
                                mHolder.unlockCanvasAndPost(canvas1);
                            }

                        }
                    }, 1000);

                }
                mHolder.unlockCanvasAndPost(canvas);


            }
        }


        return false;
    }
}


回答2:

I solved it -I had to set my surface view to drawColor(Color.TRANSPARENT) with a clear flag and all was fine.



回答3:

For those who are looking for a full code, this sample code draws a small rectangle over the camera preview. Just add the surface view and modify the onViewCreated function in the Camera2BasicFragment project.

public class Camera2BasicFragment extends Fragment
        implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {

    SurfaceView surfaceView;

    @Override
    public void onViewCreated(final View view, Bundle savedInstanceState) {
        view.findViewById(R.id.picture).setOnClickListener(this);
        view.findViewById(R.id.info).setOnClickListener(this);
        mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);

        surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
        surfaceView.setZOrderOnTop(true);
        SurfaceHolder mHolder = surfaceView.getHolder();
        mHolder.setFormat(PixelFormat.TRANSPARENT);
        mHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Canvas canvas = holder.lockCanvas();
                if (canvas == null) {
                    Log.e(TAG, "Cannot draw onto the canvas as it's null");
                } else {
                    Paint myPaint = new Paint();
                    myPaint.setColor(Color.rgb(100, 20, 50));
                    myPaint.setStrokeWidth(10);
                    myPaint.setStyle(Paint.Style.STROKE);
                    canvas.drawRect(100, 100, 200, 200, myPaint);

                    holder.unlockCanvasAndPost(canvas);
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }

And the fragment_camera2_basic.xml file has an additional surface view

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.example.android.camera2basic.AutoFitTextureView
            android:id="@+id/texture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true" />
        <SurfaceView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/surfaceView"/>

        <FrameLayout
            android:id="@+id/control"
            android:layout_width="match_parent"
            android:layout_height="112dp"
            android:layout_alignParentBottom="true"
            android:layout_alignParentStart="true"
            android:background="@color/control_background">



            <Button
                android:id="@+id/picture"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="@string/picture" />

            <ImageButton
                android:id="@+id/info"
                android:contentDescription="@string/description_info"
                style="@android:style/Widget.Material.Light.Button.Borderless"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical|right"
                android:padding="20dp"
                android:src="@drawable/ic_action_info" />

        </FrameLayout>

    </RelativeLayout>