Canvas in Android

 

Useful

https://www.journaldev.com/25182/android-canvas

https://medium.com/over-engineering/getting-started-with-drawing-on-the-android-canvas-621cf512f4c7


A Canvas is a 2D drawing framework that provides us with methods to draw on the underlying Bitmap. A Bitmap acts as the surface over which the canvas is placed. The Paint class is used to provide colors and styles.

Before we dig deep into Canvas, let’s look at the lifecycle of a Custom View.

A Custom View consists of the following commonly used methods :

  • onMeasure()
  • onLayout()
  • onDraw()
InsideonMeasure we determine the size of the view and its children.
Inside onLayout the size is assigned to the view.
The onDraw method is where the canvas is drawn.

A Canvas Object basically comes as a parameter inside the onDraw method.

The invalidate() method is used to redraw the view. It calls the onDraw method again. Typically, this is used when the text or color or view needs to be updated based on certain events.

The Canvas class contains methods to draw certain shapes just as line, arc, circle, over. Moreover, we can draw complex geometry too usingPaths.
We can also draw text or just simply Paint color on the canvas too.

To draw onto a canvas in Android, you will need four things:

  • A bitmap or a view (mostly custom view) — to hold the pixels where the canvas will be drawn.
  • Canvas — to run the drawing commands on.
  • Drawing commands — to indicate to the canvas what to draw.
  • Paint — to describe how to draw the commands.


NOTE : The coordinate system followed by canvas is same as followed in Computer Vision, the top left is the (0,0). All the drawing is done relative to the canvas.


----------------------------------------------------------------------------------------------------------------------------


EXAMPLE 1] DRAW A RECTANGLE 


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">



</androidx.constraintlayout.widget.ConstraintLayout>


package com.deepesh.canvastest;

import static android.content.ContentValues.TAG;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

SquareBox box = new SquareBox(this);
        addContentView(box, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 
ViewGroup.LayoutParams.WRAP_CONTENT));

}


// Customer View on which we'll draw
// Also add this view inside the XML layout
public static class SquareBox extends View {

private Paint paint = new Paint();

public SquareBox(Context context) {
super(context);
}

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

paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(2);

// center coordinates of canvas
int x = getWidth()/2;
int y = getHeight()/2;

// Top left and Bottom right coordinates of rectangle
int x_topLeft = x-(getWidth()/4);
int y_topLeft = y-(getHeight()/4);
int x_bottomRight = x+(getWidth()/4);
int y_bottomRight = y+(getHeight()/10);

canvas.drawRect(x_topLeft,y_topLeft,x_bottomRight,y_bottomRight,paint);

}
}

}




----------------------------------------------------------------------------------------------------------------------------


Drawing a Rectangular frame/shape on camera preview


package com.deepesh.testapp;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;

import com.google.common.util.concurrent.ListenableFuture;

import java.util.concurrent.ExecutionException;

public class MainActivity extends AppCompatActivity {

PreviewView previewView_main;
ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private final int CAMERA_REQUEST_CODE = 101;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

previewView_main = findViewById(R.id.previewView_main);
ask_permissions();

}

private void load_camera_preview() {

cameraProviderFuture = ProcessCameraProvider.getInstance(this);

cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}, ContextCompat.getMainExecutor(this));

draw_preview_rectangle();

}

private void bindPreview(ProcessCameraProvider cameraProvider) {

Preview preview = new Preview.Builder()
.build();

CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();

preview.setSurfaceProvider(previewView_main.getSurfaceProvider());

Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview);

}


private void ask_permissions() {

// asks camera permission to the user.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
String[] permissions = {Manifest.permission.CAMERA};
ActivityCompat.requestPermissions(this, permissions, CAMERA_REQUEST_CODE);
}

// if permission already granted then load camera preview
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
}

}

// Called when a request permission is denied or accepted.
// Load camera preview in both cases
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
} else {
load_camera_preview();
}
}


//=============================================================================

public class Box extends View {
private Paint paint = new Paint();

Box(Context context) {
super(context);
}

@Override
protected void onDraw(Canvas canvas) { // Override the onDraw() Method
super.onDraw(canvas);

paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(4);

//center
            int x0 = previewView_main.getWidth() / 2;
int y0 = previewView_main.getHeight() / 2;
int dx = previewView_main.getHeight() / 6;
int dy = previewView_main.getHeight() / 8;
//draw guide box
canvas.drawRect(x0 - dx, y0 - dy, x0 + dx, y0 + dy, paint);
}
}


private void draw_preview_rectangle() {

Box box = new Box(this);
addContentView(box, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

}


}




NOTE : X0 and Y0 gives us the center coordinates of our canvas,we can then Add or Subtract distances from them to get the Required Cordinates to draw the rectangle of our size.

(Here we are drawing the canvas programmically and then adding it to the mainactivity using addContentView)


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
tools:context=".MainActivity">

<androidx.camera.view.PreviewView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/previewView_main"
/>

</androidx.constraintlayout.widget.ConstraintLayout>


----------------------------------------------------------------------------------------------------------------------------
































Comments

Popular posts from this blog

React Js + React-Redux (part-2)

React Js + CSS Styling + React Router (part-1)

ViteJS (Module Bundlers, Build Tools)