Welcome guys,
I have problem with custom drawing view (Fingerprint)
I'm using
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
The problem is it draws black lines then it removes the drawing.
How to disable this black line and enable it to transparent
My code is:
import android.annotation.SuppressLint;
import android.graphics.PorterDuff;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.view.MotionEvent;
public class DrawingView extends View {
// drawing path
private Path drawPath;
// drawing and canvas paint
private Paint drawPaint, canvasPaint, drawCirclePaint;
// initial color
public int paintColor = Color.BLACK;
// canvas
private Canvas drawCanvas;
// canvas bitmap
private Bitmap canvasBitmap;
private float brushSize;
private boolean startedEditing = false;
private int width, height;
public boolean isLined = false;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public boolean isStartedEditing() {
return startedEditing;
}
public void setBackColor(int color) {
this.setBackgroundColor(color);
}
public int getBackColor() {
int colorID;
try {
ColorDrawable color = (ColorDrawable) this.getBackground();
colorID = color.getColor();
} catch (Exception e) {
colorID = Color.WHITE;
}
return colorID;
}
public void setupDrawing() {
brushSize = 4;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
drawPaint.setStrokeWidth(brushSize);
drawCirclePaint = new Paint();
drawCirclePaint.setColor(paintColor);
drawCirclePaint.setStyle(Paint.Style.FILL);
drawCirclePaint.setStrokeJoin(Paint.Join.ROUND);
drawCirclePaint.setStrokeCap(Paint.Cap.ROUND);
drawCirclePaint.setStrokeWidth(brushSize / 4);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
public void setBrushSize(float newSize) {
float pixelAmount = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, newSize, getResources()
.getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
public void setBrushColor(int newColor) {
drawPaint.setColor(newColor);
drawCirclePaint.setColor(newColor);
}
public int getBrushColor() {
return (drawPaint.getColor() == Color.WHITE) ? Color.BLACK : drawPaint
.getColor();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
width = w;
height = h;
// setLinedBackground();
}
#SuppressLint("NewApi")
public void setLinedBackground(boolean setOrRemove) {
if (setOrRemove) {
isLined = true;
// Lined Background
// Initialize lined background
Bitmap linedBackground = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas linedBackgroundCanvas = new Canvas(linedBackground);
// Set back white color
linedBackgroundCanvas.drawColor(Color.WHITE);
final float scale = DrawingView.this.getResources()
.getDisplayMetrics().density;
int pixels = (int) (50 * scale + 0.5f);
for (int i = 1, j = 0; j < drawCanvas.getHeight() / (pixels); i++, j++) {
Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
myPaint.setStrokeWidth((int) (1 * scale + 0.5f));
myPaint.setColor(Color.argb(60, 168, 168, 168));
linedBackgroundCanvas.drawLine(5, i * pixels,
drawCanvas.getWidth() - 5, i * pixels, myPaint);
}
BitmapDrawable ob = new BitmapDrawable(
DrawingView.this.getResources(), linedBackground);
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
this.setBackgroundDrawable(ob);
} else {
this.setBackground(ob);
}
} else {
isLined = false;
// Lined Background
// Initialize lined background
setBackColor(Color.WHITE);
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
AddDrawingNote.moreLayout.setVisibility(View.GONE);
startedEditing = true;
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawCanvas.drawPoint(touchX, touchY, drawCirclePaint);
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public void setErase() {
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
}
and the xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#drawable/drawingnote_main_layout_bg"
android:orientation="vertical"
android:weightSum="100" >
<ImageView
android:id="#+id/drawingView_back"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_margin="1dp"
android:background="#FFFF00"/>
<ibrahim.radwan.qnotes.DrawingView
android:id="#+id/add_drawing_note_drawing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_margin="1dp"
android:background="#00ffffff" />
</RelativeLayout>
Any ideas :)
Yo, I figured this out. Just set the paint color to the background of your view.
Related
I need to implement a custom signature view inside a scroll view. The structure of my xml file is like this
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
>
<ScrollView>
<androidx.constraintlayout.widget.ConstraintLayout>
//bunch of linear layouts and textviews
<LinearLayout
android:id="#+id/linearLayoutSignature"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="10dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="#+id/imageView3"
tools:ignore="MissingConstraints">
</LinearLayout>
//some buttons and textfields
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Now, when I move right or left inside my signature view canvas, it's all good. But when I move up or down, the scroll moves, and I can't draw. Is there a way to implement this without moving my signature view outside of scroll view? Is there a way to freeze signature layout when it is active, so it wont scroll up or down while I draw a signature?
CaptureSignature.java
package com.example.app_ptt.services;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.io.ByteArrayOutputStream;
public class CaptureSignature extends View {
private Bitmap _Bitmap;
private Canvas _Canvas;
private Path _Path;
private Paint _BitmapPaint;
private Paint _paint;
private float _mX;
private float _mY;
private float TouchTolerance = 4;
private float LineThickness = 4;
public CaptureSignature(Context context, AttributeSet attr) {
super(context, attr);
_Path = new Path();
_BitmapPaint = new Paint(Paint.DITHER_FLAG);
_paint = new Paint();
_paint.setAntiAlias(true);
_paint.setDither(true);
_paint.setColor(Color.argb(255, 0, 0, 0));
_paint.setStyle(Paint.Style.STROKE);
_paint.setStrokeJoin(Paint.Join.ROUND);
_paint.setStrokeCap(Paint.Cap.ROUND);
_paint.setStrokeWidth(LineThickness);
}
public CaptureSignature(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
_Bitmap = Bitmap.createBitmap(w, (h > 0 ? h : ((View) this.getParent()).getHeight()), Bitmap.Config.ARGB_8888);
_Canvas = new Canvas(_Bitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(_Bitmap, 0, 0, _BitmapPaint);
canvas.drawPath(_Path, _paint);
}
private void TouchStart(float x, float y) {
_Path.reset();
_Path.moveTo(x, y);
_mX = x;
_mY = y;
}
private void TouchMove(float x, float y) {
float dx = Math.abs(x - _mX);
float dy = Math.abs(y - _mY);
if (dx >= TouchTolerance || dy >= TouchTolerance) {
_Path.quadTo(_mX, _mY, (x + _mX) / 2, (y + _mY) / 2);
_mX = x;
_mY = y;
}
}
private void TouchUp() {
if (!_Path.isEmpty()) {
_Path.lineTo(_mX, _mY);
_Canvas.drawPath(_Path, _paint);
} else {
_Canvas.drawPoint(_mX, _mY, _paint);
}
_Path.reset();
}
#Override
public boolean onTouchEvent(MotionEvent e) {
super.onTouchEvent(e);
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
TouchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
TouchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
TouchUp();
invalidate();
break;
}
return true;
}
public void ClearCanvas() {
_Canvas.drawColor(Color.WHITE);
invalidate();
}
public byte[] getBytes() {
Bitmap b = getBitmap();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
public Bitmap getBitmap() {
View v = (View) this.getParent();
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return b;
}
}
try this Override method copy in your CaptureSignature class and check
#Override
public boolean onTouchEvent(final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
getParent().getParent().requestDisallowInterceptTouchEvent(false);
break;
default:
break;
}
return super.onTouchEvent(event);
}
How can I extend the drawing area when it reached the end and there is an issue in clear function when the user clears the screen using clearCanvas() and gets pressed undo() button then the paint color and stroke-width behavior changed. how can I fix it? And now I want to support pdf file in drawing area also for draw over it.
Below is my custom view code and screenshot:
package co.ctdworld.sketchapp;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class DrawingView extends View
{
private Path mDrawPath;
private Paint mBackgroundPaint;
private Paint mDrawPaint;
private Canvas mDrawCanvas;
private Bitmap mCanvasBitmap;
private ArrayList<Path> mPaths = new ArrayList<>();
private ArrayList<Paint> mPaints = new ArrayList<>();
private ArrayList<Path> mUndonePaths = new ArrayList<>();
private ArrayList<Paint> mUndonePaints = new ArrayList<>();
private ArrayList<Path> mLastPaths = new ArrayList<>();
private ArrayList<Paint> mLastPaints = new ArrayList<>();
// Set default values
private int mBackgroundColor = 0xFFFFFFFF;
private int mPaintColor = getContext().getResources().getColor(R.color.colorPrimaryDark);
private int mStrokeWidth = 8;
public DrawingView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
mDrawPath = new Path();
mBackgroundPaint = new Paint();
initPaint();
}
private void initPaint()
{
mDrawPaint = new Paint();
mDrawPaint.setColor(mPaintColor);
mDrawPaint.setAntiAlias(true);
mDrawPaint.setStrokeWidth(mStrokeWidth);
mDrawPaint.setStyle(Paint.Style.STROKE);
mDrawPaint.setStrokeJoin(Paint.Join.ROUND);
mDrawPaint.setStrokeCap(Paint.Cap.ROUND);
}
private void drawBackground(Canvas canvas)
{
mBackgroundPaint.setColor(mBackgroundColor);
mBackgroundPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), mBackgroundPaint);
}
private void drawPaths(Canvas canvas)
{
int i = 0;
for (Path p : mPaths)
{
canvas.drawPath(p, mPaints.get(i));
i++;
}
}
#Override
protected void onDraw(Canvas canvas)
{
drawBackground(canvas);
drawPaths(canvas);
canvas.drawPath(mDrawPath, mDrawPaint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mCanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mDrawCanvas = new Canvas(mCanvasBitmap);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mDrawPath.reset();
mDrawPath.moveTo(touchX, touchY);
//mDrawPath.addCircle(touchX, touchY, mStrokeWidth/10, Path.Direction.CW);
break;
case MotionEvent.ACTION_MOVE:
mDrawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
mDrawPath.lineTo(touchX, touchY);
mPaths.add(mDrawPath);
mPaints.add(mDrawPaint);
mDrawPath = new Path();
initPaint();
break;
default:
return false;
}
invalidate();
return true;
}
public void setPaintColor(int color)
{
mPaintColor = color;
mDrawPaint.setColor(mPaintColor);
}
public void setPaintStrokeWidth(int strokeWidth)
{
mStrokeWidth = strokeWidth;
mDrawPaint.setStrokeWidth(mStrokeWidth);
}
public void setBackgroundColor(int color)
{
mBackgroundColor = color;
mBackgroundPaint.setColor(mBackgroundColor);
invalidate();
}
public Bitmap getBitmap()
{
drawBackground(mDrawCanvas);
drawPaths(mDrawCanvas);
return mCanvasBitmap;
}
public void undo()
{
if (mPaths.size() > 0)
{
mUndonePaths.add(mPaths.remove(mPaths.size() - 1));
mUndonePaints.add(mPaints.remove(mPaints.size() - 1));
invalidate();
}else if (mLastPaths.size() > 0){
for (Path p : mLastPaths){
mPaths.add(p);
}
if (mLastPaints.size() > 0) {
for (Paint p : mLastPaints) {
mPaints.add(p);
}
}
invalidate();
}
}
public void redo()
{
if (mUndonePaths.size() > 0)
{
mPaths.add(mUndonePaths.remove(mUndonePaths.size() - 1));
mPaints.add(mUndonePaints.remove(mUndonePaints.size() - 1));
}
invalidate();
}
public void clearCanvas()
{
if (mPaths.size() > 0) {
for (Path p : mPaths) {
mLastPaths.add(p);
}
if (mPaints.size() > 0){
for (Paint p : mPaints){
mLastPaints.add(p);
}
}
//TODO: there is a bug relate with on touch move
mDrawPath.reset();
mPaths.clear();
invalidate();
}
invalidate();
}
public void erase(boolean isEraseOn){
if (isEraseOn){
setPaintColor(Color.WHITE);
}
}
}
Screenshot
There is a fix for your current code issue:
package co.ctdworld.sketchapp;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class DrawingView extends View
{
private Path mDrawPath;
private Paint mBackgroundPaint;
private Paint mDrawPaint;
private Canvas mDrawCanvas;
private Bitmap mCanvasBitmap;
private ArrayList<Path> mPaths = new ArrayList<>();
private ArrayList<Paint> mPaints = new ArrayList<>();
private ArrayList<Path> mUndonePaths = new ArrayList<>();
private ArrayList<Paint> mUndonePaints = new ArrayList<>();
private ArrayList<Path> mLastPaths = new ArrayList<>();
private ArrayList<Paint> mLastPaints = new ArrayList<>();
// Set default values
private int mBackgroundColor = 0xFFFFFFFF;
private int mPaintColor = getContext().getResources().getColor(R.color.colorPrimaryDark);
private int mStrokeWidth = 8;
public DrawingView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
mDrawPath = new Path();
mBackgroundPaint = new Paint();
initPaint();
}
private void initPaint()
{
mDrawPaint = new Paint();
mDrawPaint.setColor(mPaintColor);
mDrawPaint.setAntiAlias(true);
mDrawPaint.setStrokeWidth(mStrokeWidth);
mDrawPaint.setStyle(Paint.Style.STROKE);
mDrawPaint.setStrokeJoin(Paint.Join.ROUND);
mDrawPaint.setStrokeCap(Paint.Cap.ROUND);
}
private void drawBackground(Canvas canvas)
{
mBackgroundPaint.setColor(mBackgroundColor);
mBackgroundPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), mBackgroundPaint);
}
private void drawPaths(Canvas canvas)
{
int i = 0;
for (Path p : mPaths)
{
canvas.drawPath(p, mPaints.get(i));
i++;
}
}
#Override
protected void onDraw(Canvas canvas)
{
drawBackground(canvas);
drawPaths(canvas);
canvas.drawPath(mDrawPath, mDrawPaint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mCanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mDrawCanvas = new Canvas(mCanvasBitmap);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mDrawPath.reset();
mDrawPath.moveTo(touchX, touchY);
mUndonePaths.clear();
//mDrawPath.addCircle(touchX, touchY, mStrokeWidth/10, Path.Direction.CW);
break;
case MotionEvent.ACTION_MOVE:
mDrawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
mDrawPath.lineTo(touchX, touchY);
mPaths.add(mDrawPath);
mPaints.add(mDrawPaint);
mDrawPath = new Path();
initPaint();
break;
default:
return false;
}
invalidate();
return true;
}
public void setPaintColor(int color)
{
mPaintColor = color;
mDrawPaint.setColor(mPaintColor);
}
public void setPaintStrokeWidth(int strokeWidth)
{
mStrokeWidth = strokeWidth;
mDrawPaint.setStrokeWidth(mStrokeWidth);
}
public void setBackgroundColor(int color)
{
mBackgroundColor = color;
mBackgroundPaint.setColor(mBackgroundColor);
invalidate();
}
public Bitmap getBitmap()
{
drawBackground(mDrawCanvas);
drawPaths(mDrawCanvas);
return mCanvasBitmap;
}
public void undo()
{
if (mPaths.size() > 0)
{
mUndonePaths.add(mPaths.remove(mPaths.size() - 1));
mUndonePaints.add(mPaints.remove(mPaints.size() - 1));
invalidate();
}else if (mLastPaths.size() > 0){
for (Path p : mLastPaths){
mPaths.add(p);
}
if (mLastPaints.size() > 0) {
for (Paint p : mLastPaints) {
mPaints.add(p);
}
}
invalidate();
}
}
public void redo()
{
if (mUndonePaths.size() > 0)
{
mPaths.add(mUndonePaths.remove(mUndonePaths.size() - 1));
mPaints.add(mUndonePaints.remove(mUndonePaints.size() - 1));
}
invalidate();
}
public void clearCanvas()
{
//for only last deleted path
mLastPaths.clear();
mLastPaints.clear();
if (mPaths.size() > 0) {
for (Path p : mPaths) {
mLastPaths.add(p);
}
if (mPaints.size() > 0){
for (Paint p : mPaints){
mLastPaints.add(p);
}
}
mPaths.clear();
mPaints.clear();
mUndonePaths.clear();
mUndonePaints.clear();
mDrawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
}
i want to set image on white canvas and want to draw on that image i don't know how to do that. i tried all possible method, but not work. this is my code help me if u want any other code then tell me. and please help me......
package com.example.drowingdemo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
// drawing path
private Path drawPath;
// drawing and canvas paint
private Paint drawPaint, canvasPaint;
// initial color
private int paintColor = 0xFF660000, paintAlpha = 255;
// canvas
private Canvas drawCanvas;
// canvas bitmap
private Bitmap canvasBitmap;
// brush sizes
private float brushSize, lastBrushSize;
// erase flag
private boolean erase = false;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
// setup drawing
private void setupDrawing() {
// prepare for drawing and setup paint stroke properties
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
// draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
// size assigned to view
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
// register user touches as drawing action
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
// respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
// redraw
invalidate();
return true;
}
// update color
public void setColor(String newColor) {
invalidate();
// check whether color value or pattern name
if (newColor.startsWith("#")) {
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
drawPaint.setShader(null);
} else {
// pattern
int patternID = getResources().getIdentifier(newColor, "drawable",
"com.example.drowingdemo");
// decode
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(),
patternID);
// create shader
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
// color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
}
// set brush size
public void setBrushSize(float newSize) {
float pixelAmount = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, newSize, getResources()
.getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
// get and set last brush size
public void setLastBrushSize(float lastSize) {
lastBrushSize = lastSize;
}
public float getLastBrushSize() {
return lastBrushSize;
}
// set erase true or false
public void setErase(boolean isErase) {
erase = isErase;
if (erase)
drawPaint
.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else
drawPaint.setXfermode(null);
}
// start new drawing
public void startNew() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
// return current alpha
public int getPaintAlpha() {
return Math.round((float) paintAlpha / 255 * 100);
}
// set alpha
public void setPaintAlpha(int newAlpha) {
paintAlpha = Math.round((float) newAlpha / 100 * 255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
}
}
Through the code, I didn't see which line loads an image.
In your code, Bitmap is set for Canvas in method onSizeChanged, but the bitmap is an empty bitmap, you may try the code to load image
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.your_image) //-->here load your image
.copy(Bitmap.Config.ARGB_8888, true);
drawCanvas = new Canvas(canvasBitmap);//-->set bitmap
}
In addition, drawPath.reset() is called before invalidate(), do not reset path before onDraw(),
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
// respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
invalidate();
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawPath = new Path();//--> use a new path after ACTION_UP
break;
default:
return false;
}
// redraw
drawCanvas.drawPath(drawPath, drawPaint);//--> Draw on canvasBitmap
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(canvasBitmap, 0, 0, null);//--> draw canvasBitmap on canvas
...
}
I can get Erasing to Work but cannot get Undo to Work
And I can get Undo to Work but Erasing cannot work.
I have tried multiple times to figure out why it is doing this. But i am having no success.
Here is my Drawing class:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
private Canvas backUp;
//canvas bitmap
private Bitmap canvasBitmap;
private Bitmap backUpBitmap;
private float brushSize;
private boolean erasing;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Integer> paints = new ArrayList<Integer>();
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawingView();
}
private void setupDrawingView() {
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setDither(true);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
brushSize = 5;
drawPaint.setStrokeWidth(brushSize);
erasing = false;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
backUpBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
backUp = new Canvas(backUpBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
for(int i = 0; i < paths.size(); i++) {
Integer j = paints.get(i);
Paint p = new Paint();
p.setColor(j.intValue());
p.setAntiAlias(true);
p.setDither(true);
p.setStyle(Paint.Style.STROKE);
p.setStrokeJoin(Paint.Join.ROUND);
p.setStrokeCap(Paint.Cap.ROUND);
p.setXfermode(null);
p.setStrokeWidth(5);
canvas.drawPath(paths.get(i), p);
}
drawPaint.setColor(paintColor);
if(erasing)
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawPath(drawPath, drawPaint);
canvas.drawBitmap(canvasBitmap, 0, 0, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
backUp.drawBitmap(canvasBitmap, 0, 0, null);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
invalidate();
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
if(!erasing) {
paints.add(paintColor);
paths.add(drawPath);
drawPath = new Path();
}
drawPath.reset();
invalidate();
//drawPath = new Path();
break;
default:
return false;
}
invalidate();
return true;
}
public void setColor(String newColor) {
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
public void setColor(int color) {
invalidate();
drawPaint.setColor(color);
}
public void setErase(boolean erase){
Mode x = PorterDuff.Mode.CLEAR;
erasing = erase;
if(erase) {
drawPaint.setXfermode(new PorterDuffXfermode(x));
} else {
drawPaint.setXfermode(null);
drawPaint.setColor(0xFF000000);
}
drawCanvas.drawPath(drawPath, drawPaint);
}
public void reset() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
drawPath.reset();
paths.clear();
paints.clear();
}
public void setBrushSize(float newSize) {
brushSize = newSize;
drawPaint.setStrokeWidth(newSize);
}
public void undo () {
if (paths.size() > 0) {
Path undoPath = paths.get(paths.size()-1);
undoPath.reset();
paths.remove(paths.size() -1);
paints.remove(paints.size()-1);
drawCanvas.drawBitmap(canvasBitmap, 0, 0, null);
invalidate();
} else {
Toast.makeText(getContext(), "Cannot Undo", Toast.LENGTH_SHORT).show();
}
}
public int getPaths() {
return paths.size();
}
}
create a new path every time you draw and save it on a stack, undo by poping paths from the stack
Sorry if the question is silly, but I'm new to Android. I read a lot on developer.android.сom, but solutions to my problem is not found, unfortunately.
Most of the code I found on staсkoverflow, finished the part itself.
This View inserted in the Activity in FrameLayout, over the text, and allows you to leave notes in the e-book.
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class PaintSurface extends View implements OnTouchListener {
private Canvas canvas;
private Path path;
private Paint paint;
private ArrayList<Path> paths = new ArrayList<Path>();
public PaintSurface(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.MITER);
paint.setStrokeCap(Paint.Cap.SQUARE);
paint.setColor(Color.RED);
paint.setStrokeWidth(16);
paint.setAlpha(100);
canvas = new Canvas();
path = new Path();
paths.add(path);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
for (Path p : paths) {
canvas.drawPath(p, paint);
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
path.reset();
path.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
path.lineTo(mX, mY);
canvas.drawPath(path, paint);
path = new Path();
paths.add(path);
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public void setColor(int color) {
paint.setColor(color);
}
}
Describe the problem.
I draw the line of the default color, red. Then, use the setColor() changes to green to draw a green line next to the red line. But the first red line also turns green. Such changes occur if you change the style or the stroke width.
How is it possible to paint a different color?
A feeling that in a few months this problem would seem to me ridiculous and stupid, and I myself will feel myself silly and I would be ashamed, but now I do not know how to solve this problem...
The Paint color only takes effect when you draw.
From your code you draw all the Paths at once.
for (Path p : paths) {
canvas.drawPath(p, paint);
}
This takes the same paint object and uses it to draw the paths, using what ever color was set last.
What you need to do is set the color between drawing.
paint.setColor(color.RED); // Will apply to first path.
for (Path p : paths) {
canvas.drawPath(p, paint);
paint.setColor(color.GREEN); // Will be applied on next Path.
}
A better solution would be
for (Path p : paths) {
//Determine Paint color Here.
paint.setColor(myColor); // where myColor is your variable to use for this layer.
// This could be from an array/List of colors matching to Paths.
canvas.drawPath(p, paint);
}
One thing that you can try is to create one Paint object for each path in array List.. This way you can specify different Paint properties for each path in ArrayList...
Try this code it will help to change canvas background color and paint color.I am using this in my app.
package com.kidsfingerpainting;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CanvasView extends View {
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private android.graphics.Path mPath;
private Paint mBitmapPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
public static int selectedcolor;
private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>();
public CanvasView(Context c, int width, int height) {
super(c);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(10);
mCanvas = new Canvas();
mPath = new Path();
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
selectedcolor = getResources().getColor(R.color.black);
}
public CanvasView(Context context, AttributeSet arr) {
super(context, arr);
}
// ////////////////////////all color for brush/////////////////
public void setPaintMode() {
mPaint.setColor(0xFF000000);
mPaint.setStrokeWidth(10);
}
public void set_PaintModetrans() {
mPaint.setColor(0x00000000);
mPaint.setStrokeWidth(10);
}
public void setPaintMode_violet() {
mPaint.setColor(0xFF8B00FF);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.violet);
}
public void setPaintMode_indigo() {
mPaint.setColor(0xFF000066);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.indigo);
}
public void setPaintMode_blue() {
mPaint.setColor(0xFF0000FF);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.blue);
}
public void setPaintMode_green() {
mPaint.setColor(0xFF00FF00);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.green);
}
public void setPaintMode_yellow() {
mPaint.setColor(0xFFFFFF00);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.yellow);
}
public void setPaintMode_orange() {
mPaint.setColor(0xFFFF7F00);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.orange);
}
public void setPaintMode_red() {
mPaint.setColor(0xFFFF0000);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.red);
}
public void setPaintMode_redbg() {
mCanvas.drawColor(0xFFFF0000);
mPaint.setColor(0x00000000);
}
public void setPaintMode_pink() {
mPaint.setColor(0xFFFF33CC);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.pink);
}
public void setPaintMode_white() {
mPaint.setColor(0xFFFFFFFF);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.white);
}
public void setPaintMode_black() {
mPaint.setColor(0xFF000000);
mPaint.setStrokeWidth(10);
selectedcolor = getResources().getColor(R.color.black);
}
// /////////////////////// all background color set code////////////
public void setPaintMode_blackbg() {
mCanvas.drawColor(0xFF000000);
}
public void setPaintMode_whitebg() {
mCanvas.drawColor(0xFFFFFFFF);
}
public void setPaintMode_pinkbg() {
mCanvas.drawColor(0xFFFF33CC);
}
public void setPaintMode_orangebg() {
mCanvas.drawColor(0xFFFF7F00);
}
public void setPaintMode_yellowbg() {
mCanvas.drawColor(0xFFFFFF00);
}
public void setPaintMode_greenbg() {
mCanvas.drawColor(0xFF00FF00);
}
public void setPaintMode_bluebg() {
mCanvas.drawColor(0xFF0000FF);
}
public void setPaintMode_indigobg() {
mCanvas.drawColor(0xFF000066);
}
public void setPaintMode_violetbg() {
mCanvas.drawColor(0xFF8B00FF);
}
// ////////////////////////////////////////////////////
public void setEraseMode() {
selectedcolor = getResources().getColor(R.color.white);
mPaint.setColor(0xFFFFFFFF);
mPaint.setStrokeWidth(10);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths) {
mPaint.setColor(colorsMap.get(p));
canvas.drawPath(p, mPaint);
}
mPaint.setColor(selectedcolor);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 8;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
paths.add(mPath);
colorsMap.put(mPath, selectedcolor);
mPath = new Path();
mPath.reset();
invalidate();
}
public void eraseAll() {
if (mPath != null) {
paths.clear();
}
invalidate();
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
// currentMoveList.add(mPath);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public void resetcanvas() {
mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
}
}
}
You can call it's any method from activity by doing this.
CanvasView canvas = new CanvasView(MainActivity.this, width, height);
frame_layout.addView(canvas);
Paste this in oncreate method.
// set Onclick listener and use following codes
undo = (ImageView) findViewById(R.id.undo);
undo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
canvas.onClickUndo();
}
});
eraser = (ImageView) findViewById(R.id.eraser);
eraser.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
canvas.setEraseMode();
}
});
clear = (ImageView) findViewById(R.id.clear);
clear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
canvas.eraseAll();
}
});
replace your onTouchEvent and onDraw method or you can use this custom view
package com.draw;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
private Paint paint;
private Path path;
private Paint canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
this.init();
this.paint.setAntiAlias(true);
this.paint.setStrokeWidth(4f);
this.paint.setColor(Color.BLACK);
this.paint.setStyle(Paint.Style.STROKE);
this.paint.setStrokeJoin(Paint.Join.ROUND);
}
private void init() {
this.paint = new Paint();
this.path = new Path();
this.canvasPaint = new Paint(Paint.DITHER_FLAG);
}
public void setStroke(float width) {
this.paint.setStrokeWidth(width);
}
public void setColor(int color) {
this.paint.setColor(color);
}
public void reset() {
this.drawCanvas.drawColor(0, Mode.CLEAR);
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
this.drawCanvas = new Canvas(this.canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(this.canvasBitmap, 0, 0, this.canvasPaint);
canvas.drawPath(this.path, this.paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
this.path.moveTo(eventX, eventY);
break;
case MotionEvent.ACTION_MOVE:
this.path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
this.drawCanvas.drawPath(this.path, this.paint);
this.path.reset();
break;
default:
return false;
}
invalidate();
return true;
}
}
I had the same problem, I have two methods in my DrawingView class, one to change the color when a different color is selected on a color palette. And another that changes the color randomly every few seconds with a handler.
I had to use invalidate() in both methods to sort of refresh what was affected on the main thread and not change anything previously drawn. Works great if you just use invalidate in your methods.
public void setColor(String newColor) {
//set color
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
//random color chosen automatically
public void randomColor () {
//invalidate needed here for the random color change every 30sec, to not change lines already drawn.
invalidate();
paintColor = Color.argb(255, rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
drawPaint.setColor(paintColor);
}
You describe the right way but when first time select the color, then it working correctly but again change then same problem occurred .
If you want to set up hexadecimal code for color in android then here is string
currentPaint.setColor(Color.parseColor("#B6B6B6"));