I am trying to use the method mCanvas.drawBitmap(iconBitmap,x-100,y-100, mBitmapPaint); on my MotionEvent.ACTION_DOWN event in my custom view class. However, the image I want to show does not appear on the canvas at that point. I am trying to make a paint application where users can draw free hand and insert images at the same time to play with them.
This is my custom view class:
package com.example.shazs.autismate;
public class PaintView extends View {
public static int BRUSH_SIZE = 20;
public static final int DEFAULT_COLOR = Color.RED;
public static final int DEFAULT_BG_COLOR = Color.WHITE;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Paint mBitmapPaint;
private Canvas mCanvas;
private Bitmap iconBitmap;
private static AtomicBoolean drawIcon = new AtomicBoolean();
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void emboss() {
emboss = true;
blur = false;
}
public void blur() {
emboss = false;
blur = true;
}
public void setPaintColor(int color){
if (currentColor!=color)
Log.d("xyzn","current color changed");
else
Log.d("xyzn","current color not changed");
currentColor=color;
}
public void drawBitmap(Bitmap bm){
drawIcon.set(true);
iconBitmap = bm;
}
public int getPaintColor(){
return currentColor;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);
mPath.reset();
mPath.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 >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN :
if (drawIcon.get()){
mCanvas.drawBitmap(iconBitmap,x-100,y-100, mBitmapPaint);
mCanvas.save();
break;
}
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
if (drawIcon.get())
break;
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
if (drawIcon.get()){
drawIcon.set(false);
break;
}
touchUp();
invalidate();
break;
}
return true;
}
}
Main Activity which uses this custom view class and passes the bitmap of object to draw:
public class drawActivity extends AppCompatActivity implements
ColorPickerDialog.OnColorChangedListener {
private PaintView paintView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.css_layout);
paintView = (PaintView) findViewById(R.id.paintView);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.draw:
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.apple);
paintView.drawBitmap(bm);
break;
I use drawIcon to see if the user needs to insert icon or just draw freehand.
Interestingly, when I go into application view of my phone to view all currently running applications, the icon/image shows on the canvas. However when I return to the application, it dissappears. It only happens once after I insert the icon, not repeatedly.
OK, I had to remove the line
mCanvas.drawColor(backgroundColor);
from my onDraw(Canvas canvas) method and call invalidate()
Related
I have a problem with my drawing app, in that the mask filters are using a lot of paramaters and lisiting it in to the array list. I think everytime I draw the maskfilter gets added to the arraylist and then the canvas draws the whole array list from scratch. Or it is the problem with onDraw please give me suggestions for performance improvements.
public class PaintingActivity extends AppCompatActivity {
private PaintView paintView;
private Toolbar mTopToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_paint);
mTopToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(mTopToolbar);
paintView = (PaintView) findViewById(R.id.paintView);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.draw_menu, menu);
return super.onCreateOptionsMenu(menu);
}
private void colorPicker() {
final Context context = PaintingActivity.this;
ColorPickerDialogBuilder
.with(context)
.setTitle("Choose color")
.initialColor(DEFAULT_COLOR)
.wheelType(ColorPickerView.WHEEL_TYPE.CIRCLE)
.density(12)
.setOnColorSelectedListener(new OnColorSelectedListener() {
#Override
public void onColorSelected(int selectedColor) {
Toast.makeText(context, "onColorSelected: 0x" + Integer.toHexString(selectedColor), Toast.LENGTH_SHORT).show();
}
})
.setPositiveButton("ok", new ColorPickerClickListener() {
#Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
//changeBackgroundColor(selectedColor);
}
})
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.build()
.show();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.normal:
paintView.normal();
return true;
case R.id.emboss:
paintView.emboss();
return true;
case R.id.blur:
paintView.blur();
return true;
case R.id.color_picker:
colorPicker();
return true;
case R.id.clear:
paintView.clear();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Then my PaintView
public class PaintView extends View {
public static int BRUSH_SIZE = 20;
public static final int DEFAULT_COLOR = Color.RED;
public static final int DEFAULT_BG_COLOR = Color.WHITE;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void emboss() {
emboss = true;
blur = false;
}
public void blur() {
emboss = false;
blur = true;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);
mPath.reset();
mPath.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 >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch(event.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;
}
}
Also my layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lolow.asserty.asserty.paint.PaintingActivity"
android:background="#color/lightGrey">
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.lolow.asserty.asserty.paint.PaintView
android:id="#+id/paintView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="40dp"
android:layout_marginBottom="100dp"
android:background="#drawable/paint_view_border"/>
</RelativeLayout>
</RelativeLayout>
This is also my path class:
public class FingerPath {
public int color;
public boolean emboss;
public boolean blur;
public int strokeWidth;
public Path path;
public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path) {
this.color = color;
this.emboss = emboss;
this.blur = blur;
this.strokeWidth = strokeWidth;
this.path = path;
}
}
I'm trying to implement a erase function on the Fingerpaint App in the Api Demo's in Android. I change some code based on my needs. At first the erase function works well. I used:
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
It works well when the path has been drawn in the bitmap. But when I implement the Undo and Redo function(the way I achieve it is by using two arraylist and save the path there), PorterDuffXfermode doesn't work. Please take a look at this:
At image 1 I draw some paths(stored in an arraylist. Not drawn in the bitmap canvas)
Then at 2 thats the time I pressed the erase icon. I dont know what causing all the paths to became black. Then at 3 I tried to erase the paths I made(PorterDuffXFermode some says its black). Then when I switch back to drawing mode. It seems that instead or erasing, all it did was draw another path.
Any solutions for this? or workarounds?
Here is the code when to my drawingClass:
//this is where the drawing takes place
public class DrawingClass 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;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize,lastBrushSize;
private boolean erase = false;
//array list for paths
private ArrayList<PathPoints> paths = new ArrayList<PathPoints>();
private ArrayList<PathPoints> undonePaths = new ArrayList<PathPoints>();
public Context context;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public DrawingClass(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
setupDrawing();
}
private void setupDrawing(){
setFocusable(true);
setFocusableInTouchMode(true);
//instantiate the variable to get the last brush size
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
//get drawing area setup for interaction
drawCanvas = new Canvas();
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
//initial properties
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);
//paths.add(new PathPoints(drawPath, paintColor, brushSize));
}
public void setBrushSize(float newSize){
//update brush size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
invalidate();
}
public void setLastBrushSize(float lastSize){
//set the last brush size
lastBrushSize = lastSize;
invalidate();
}
public float getLastBrushSize(){
//return the last brush size
return lastBrushSize;
}
public void setErase(boolean isErase){
//set erase true or false
erase = isErase;
if (erase) {
//drawPaint.setColor(Color.WHITE);
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
else drawPaint.setXfermode(null);
}
public void startNew(){
//creates a new canvass
drawCanvas.drawColor(0,PorterDuff.Mode.CLEAR);
drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
setDrawingCacheEnabled(true);
String imgSaved = MediaStore.Images.Media.insertImage(
context.getContentResolver(), getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
destroyDrawingCache();
paths.clear();
undonePaths.clear();
invalidate();
}
#Override
protected void onSizeChanged(int w,int h,int oldw,int oldh){
//view given size
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas){
//draw view
//save the strokes in the bitmap
//canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (PathPoints p : paths){
drawPaint.setColor(p.getColor());
drawPaint.setStrokeWidth(p.getBrush());
invalidate();
canvas.drawPath(p.getPath(), drawPaint);
}
}
private void touch_start(float x, float y){
drawPath.reset();
drawPath.moveTo(x, (float) (y+.1));
drawPath.lineTo(x, y);
drawPath.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) {
drawPath.quadTo(mX, mY, (x + mX)/2, (y+ mY)/2);
mX = x;
mY = y;
}
}
private void touch_up(){
drawPath.lineTo(mX, mY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath = new Path();
paths.add(new PathPoints(drawPath, paintColor, brushSize));
}
#Override
public boolean onTouchEvent(MotionEvent event){
//detect user touch
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
touch_start(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
invalidate();
touch_move(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
invalidate();
touch_up();
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public void undoPath(){
if (paths.size()>0) {
undonePaths.add(paths.remove(paths.size()-1));
} else {
Log.d("Undo", "No paths left");
}
invalidate();
}
public void redoPath(){
if (undonePaths.size()>0) {
paths.add(undonePaths.remove(undonePaths.size()-1));
} else {
Log.d("Redo", "No paths left");
}
invalidate();
}
public void setColor(String newColor){
//set color
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
invalidate();
}
class PathPoints{
private Path path;
private int color;
private float brushsize;
private int x, y;
//holds the paths data
public PathPoints(Path path, int color, float brushsize) {
this.path = path;
this.color = color;
this.brushsize = brushsize;
}
public Path getPath() {
return path;
}
public void setPath(Path path) {
this.path = path;
}
public float getBrush(){
return brushsize;
}
public void setBrush(float brushsize){
this.brushsize = brushsize;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
}
MainActivity.java
public class MainActivity extends Activity implements OnClickListener {
private DrawingView drawView;
int mColor;
String savedFilePath = "";
public static ArrayList<Path> undonePaths = new ArrayList<Path>();
public static ArrayList<Path> paths = new ArrayList<Path>();
//buttons
Canvas bitmapCanvas;
RelativeLayout mRelativeLayoutScreenShot;
static String mImagePath;
private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn;
//sizes
private float smallBrush, mediumBrush, largeBrush;
ImageButton mImageViewPicklColor;
private boolean isFileAlreadySaved = false;
ImageButton mImageButtonList;
ImageButton mImageButtonShare;
File file;
Bitmap bitmap;
Button mButtonUNDo;
Dialog mDialogDate;
Button mButtonRedo;
boolean isStartAdl=false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDialogDate= new Dialog(MainActivity.this, android.R.style.Theme_NoTitleBar| android.R.style.Theme_Translucent|android.R.style.Theme_Holo_Dialog);
mDialogDate.setCancelable(true);
mDialogDate.requestWindowFeature(Window.FEATURE_NO_TITLE);
}
#Override
protected void onResume() {
super.onResume();
savedFilePath="";
mColor = 0xff0000ff;
//get drawing view
mButtonUNDo=(Button)findViewById(R.id.btn_undo);
mButtonRedo=(Button)findViewById(R.id.btn_redo);
drawView = (DrawingView)findViewById(R.id.drawing);
mImageViewPicklColor=(ImageButton)findViewById(R.id.pick_color);
RelativeLayout paintLayout = (RelativeLayout)findViewById(R.id.paint_colors);
mImageButtonShare=(ImageButton)findViewById(R.id.share);
mImageButtonList=(ImageButton)findViewById(R.id.list);
mRelativeLayoutScreenShot=(RelativeLayout)findViewById(R.id.rr_draw);
mImageButtonList.setOnClickListener(this);
//sizes from dimensions
smallBrush = getResources().getInteger(R.integer.small_size);
mediumBrush = getResources().getInteger(R.integer.medium_size);
largeBrush = getResources().getInteger(R.integer.large_size);
//draw button
drawBtn = (ImageButton)findViewById(R.id.draw_btn);
drawBtn.setOnClickListener(this);
File direct = new File(Environment.getExternalStorageDirectory() + "/androidpaint");
if(!direct.exists())
{
if(direct.mkdir());//directory is created;
}
mImagePath = Environment.getExternalStorageDirectory() + "/androidpaint";
//set initial size
drawView.setBrushSize(mediumBrush);
//erase button
eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
eraseBtn.setOnClickListener(this);
//new button
newBtn = (ImageButton)findViewById(R.id.new_btn);
newBtn.setOnClickListener(this);
//save button
saveBtn = (ImageButton)findViewById(R.id.save_btn);
saveBtn.setOnClickListener(this);
mButtonRedo.setOnClickListener(this);
mButtonUNDo.setOnClickListener(this);
mImageViewPicklColor.setOnClickListener(this);
mImageButtonShare.setOnClickListener(this);
drawView.setErase(false);
drawView.setBrushSize(drawView.getLastBrushSize());
drawView.setColor(mColor);
if (isStartAdl==true) {
Intent intent = getIntent();
finish();
startActivity(intent);
}
}
#Override
public void onClick(View view){
if (view.getId()==R.id.btn_undo) {
System.out.println("UNDO "+paths.size());
if (paths.size() > 0) {
undonePaths.add(paths
.remove(paths.size() - 1));
drawView.invalidate();
}
}
else if(view.getId()==R.id.erase_btn)
{
drawView.setErase(true);
}
else if (view.getId()==R.id.btn_redo) {
if (undonePaths.size()>0) {
paths.add(undonePaths.remove(undonePaths.size()-1));
drawView.invalidate();
}
}
});
}
DrawingView.java
public class DrawingView extends View {
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//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);
System.out.println("cadslfjds");
MainActivity.paths.add(drawPath);
}
//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);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(canvasPaints);
for (Path p : MainActivity.paths) {
if(colorsMap.size()>0)
{
drawPaint.setColor(colorsMap.get(p));
canvas.drawPath(p, drawPaint);
}
}
drawPaint.setColor(paintColor);
canvas.drawPath(drawPath, drawPaint);
private void touch_start(float x, float y) {
drawPath.reset();
drawPath.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) {
drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
drawPath.lineTo(mX, mY);
drawCanvas.drawPath(drawPath, drawPaint);
MainActivity.paths.add(drawPath);
colorsMap.put(drawPath, paintColor);
drawPath = new Path();
drawPath.reset();
}
#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);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public void setColor(int newColor){
invalidate();
paintColor = newColor;
drawPaint.setColor(paintColor);
}
//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();
}
When I paint normal picture, it will come like below
When I click erase Button, it will come like below
When I run above code, the issue is when I click erase button then erase not working properly whole picture convert it into black, so any idea how can I solve it ?
Your code is looking perfect, but problem is you are setting white color as a background on canvas while erasing on canvas then white background also is being erased. So you have to again set white background after erasing some portion on canvas.
#Override
protected void onDraw(Canvas canvas) {
//set background white
canvas.drawColor(Color.WHITE);
super.dispatchDraw(canvas);
}
Check this demo code
All you're doing in setErase is setting a porter duff mode. You aren't actually redrawing anything. At a minimum you need to call invalidate to update the screen.
I need to draw a bitmap and yet change it when buttons are pressed on an activity class. I have tried using a View class but unfortunately I am having no luck. I thought this would be a simple enough task.
Does anyone have an idea in how to do this? I have been struggling on this for 2 days and nowhere seems to give a decent solution.
Activity Class
public class PhonicsActivity extends Activity{
int letterStatus = 0;
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1_phonics);
final Intent phonicsBackIntent = new Intent(this, PhonicsMenu.class);
final Button nextButton = (Button) findViewById(R.id.nextbutton);
final Button backButton = (Button) findViewById(R.id.backbutton);
final Button menuButton = (Button) findViewById(R.id.menubutton);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
View Class
public class PhonicsView extends View {
private int letterStatus = 1;
public PhonicsView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public PhonicsView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public PhonicsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
}
protected void onDraw(Canvas canvas) {
drawLetterA(canvas);
if (letterStatus == 2){
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lettera);
canvas.drawBitmap(myBitmap, 0, 0, null);
}
}
I need the buttons in the activity to cover the previous image or clear the canvas and then draw the next letter.
This is a fingerpaint from Google try to begin something with and customize it to figure out your issue
public class FingerPaint extends GraphicsActivity
implements ColorPickerDialog.OnColorChangedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
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);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#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);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
private static final int COLOR_MENU_ID = Menu.FIRST;
private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;
private static final int BLUR_MENU_ID = Menu.FIRST + 2;
private static final int ERASE_MENU_ID = Menu.FIRST + 3;
private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');
menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');
menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');
/**** Is this the mechanism to extend with filter effects?
Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(
Menu.ALTERNATIVE, 0,
new ComponentName(this, NotesList.class),
null, intent, 0, null);
*****/
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case COLOR_MENU_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
return true;
case EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
return true;
case BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
return true;
case SRCATOP_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.SRC_ATOP));
mPaint.setAlpha(0x80);
return true;
}
return super.onOptionsItemSelected(item);
}
}
I try to load the customview class that is inside my mainclass in xml. Because to save the image in view i create buttons in the xml, i need to load these customview in framelayout of my xml. By start these i simply put the view class in linear Layout, It cause forceclose :(
My MainClass.java
public class FingerPaint extends Activity
implements ColorPickerDialog.OnColorChangedListener {
int height,width;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth(); // deprecated
height = display.getHeight();
Log.i("FingerPaint", ""+width+""+height);
//setContentView(new MyView(this));--->It Works fine. But need these in xml
setContentView(R.layout.paint);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context c) {
super(c);
Bitmap bm = BitmapFactory.decodeFile("/sdcard/angel.jpg");
if (bm != null) {
setBackgroundDrawable(new BitmapDrawable(bm));
Log.i("FingerPaint", "setbackground"+bm.getHeight());
}
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#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.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
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);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#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);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
private static final int COLOR_MENU_ID = Menu.FIRST;
private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;
private static final int BLUR_MENU_ID = Menu.FIRST + 2;
private static final int ERASE_MENU_ID = Menu.FIRST + 3;
private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');
menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');
menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');
/**** Is this the mechanism to extend with filter effects?
Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(
Menu.ALTERNATIVE, 0,
new ComponentName(this, NotesList.class),
null, intent, 0, null);
*****/
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case COLOR_MENU_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
return true;
case EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
return true;
case BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
/*//mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
mPaint.setColor(Color.TRANSPARENT);*/
return true;
case SRCATOP_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.SRC_ATOP));
mPaint.setAlpha(0x80);
return true;
}
return super.onOptionsItemSelected(item);
}
}
And paint.xml as,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.powercamerapro.FingerPaint.MyView android:id="#+id/myView1"
android:layout_width="wrap_content" android:layout_height="wrap_content">
</com.powercamerapro.FingerPaint.MyView>
</LinearLayout>
It throws Exception,
ERROR/AndroidRuntime(670): Caused by: java.lang.ClassNotFoundException: com.powercamerapro.FingerPaint.MyView in loader dalvik.system.PathClassLoader#44e8c840
Kindly point out my mistake and how to be correct these.
use like this for inner class com.powercamerapro.FingerPaint$MyView
and use <view class="com.powercamerapro.FingerPaint$MyView" />
+
You need to add public static to the inner class