Using Finger Paints how to I activate a compare function? - android

I tried to do something to compare 2 bitmaps in the Finger Paints application. I first load the first bitmap into a 2d array, then i want to load the other output bitmap from finger paint into another array and compare both bitmap. My code doesn't work and i have no idea where should i edit. The compare function start right after the user press the "compare" option in the option menu. Please help me.
public class MainActivity extends GraphicsActivity
{
boolean check = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);
}
private Paint mPaint;
public class MyView extends View {
Bitmap mBitmap;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.c_1);
Bitmap bitmap2;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
int w1 = bitmap.getWidth();
int h1 = bitmap.getHeight();
int [][] array = new int [w1][h1];
int b=0;
int c=0;
int k=0;
int i, j;
int l=0;
View content = this;
{
for(int j = 0;j< w1; j++){
for(int i = 0;i< h1; i++,k++){
array[j][i]= bitmap.getPixel(j, i);
if(bitmap.getPixel(j, i)== 100);
{
b++;
}
}
}
System.out.println("numbers of gray:" + b);
}
public MyView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
content.setDrawingCacheEnabled(true);
content.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
}
#Override
public 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(Color.WHITE);
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
bitmap2 = content.getDrawingCache();
}
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);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
System.out.println("Coordinates:" + x + "," + y);
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 void compare(Boolean check){
if(check == true)
{
int w2 = bitmap2.getWidth();
int h2 = bitmap2.getHeight();
System.out.println("Width and Height of the product:" + w2 + "," + h2);
int [][] array1 = new int [w2][h2];
{
for(int j1 = 0;j1< w2; j1++){
for(int i1 = 0;i1< h2; i1++,l++){
array1[j1][i1]= bitmap2.getPixel(j1, i1);
if(array[j1][i1]== 100 && array1[j1][i1] == Color.RED);
{
c++;
}
}
}
System.out.println("numbers pixels touched:" + c);
}
int d=(b-c)/b*100;
Toast t = Toast.makeText(getBaseContext(), "Completion :" + d + "%", Toast.LENGTH_SHORT);
t.show();
}
}
}
private static final int CLEAR_MENU_ID = Menu.FIRST;
private static final int COMPARE_ID = Menu.FIRST + 1;
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, CLEAR_MENU_ID, 0, "Clear ALL");
menu.add(0, COMPARE_ID, 0, "Compare");
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case CLEAR_MENU_ID:
setContentView(new MyView(this));
check = false;
return true;
case COMPARE_ID:
check = true;
return true;
}
return super.onOptionsItemSelected(item);
}
}

You're not calling compare() anywhere.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case CLEAR_MENU_ID:
setContentView(new MyView(this));
check = false;
return true;
case COMPARE_ID:
check = true;
compare(check);
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
I can't see the purpose of the "check" variable but I assume that you are using it somewhere else.

Related

Inserting image into canvas

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()

Path draw in opposite direction at canvas when rotate android

Hi i am erasing bitmap that is draw at canvas with touch (fingers) that is working fine the problem i am facing is after rotate bitmap at canvas paths draw in opposition direction mean bitmap erase in opposition direction of my finger touch .
DrawingPane.class
public class DrawingPanel extends ImageView implements OnTouchListener {
private Matrix mMatrix = new Matrix();
private float mScaleFactor = 1f;
private float mRotationDegrees = 0.f;
private float mFocusX = 0.f;
private float mFocusY = 0.f;
private int mAlpha = 255;
private int mImageHeight, mImageWidth;
private ScaleGestureDetector mScaleDetector;
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
private ShoveGestureDetector mShoveDetector;
private boolean isMoving=false;
EditPhotoActivity editActivity;
Bitmap overlayDefault;
Bitmap overlay;
Bitmap bmp,bmp2;
Paint pTouch;
int whichTabSelected=0;
private Path mPath;
Display display ;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Float> xlist = new ArrayList<Float>();
private ArrayList<Float> ylist = new ArrayList<Float>();
#SuppressLint("NewApi")
public DrawingPanel(Context context, int colorPaint,Bitmap bmp) {
super(context);
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
display = ((Activity)context).getWindowManager().getDefaultDisplay();
mFocusX = display.getWidth()/2f;
mFocusY = display.getHeight()/2f;
try {
overlayDefault=bmp;
overlay=bmp;
overlay=overlay.copy(Config.ARGB_8888, true);
overlay.setHasAlpha(true);
} catch (Exception e) {
e.printStackTrace();
}
mImageHeight = getHeight();
mImageWidth = getWidth();
// Setup Gesture Detectors
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mRotateDetector = new RotateGestureDetector(context, new RotateListener());
mMoveDetector = new MoveGestureDetector(context, new MoveListener());
mShoveDetector = new ShoveGestureDetector(context, new ShoveListener());
pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);
pTouch.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
pTouch.setColor(Color.TRANSPARENT);
//pTouch.setMaskFilter(new BlurMaskFilter(30, Blur.SOLID));
pTouch.setStyle(Paint.Style.STROKE);
pTouch.setStrokeJoin(Paint.Join.ROUND);
pTouch.setStrokeCap(Paint.Cap.ROUND);
pTouch.setStrokeWidth(50);
pTouch.setAntiAlias(true);
setFocusable(true);
setFocusableInTouchMode(true);
mPath = new Path();
paths.add(mPath);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mImageHeight=getHeight();
mImageWidth=getWidth();
bmp = Bitmap.createScaledBitmap(overlay, w, h, false);
bmp2 = Bitmap.createScaledBitmap(overlayDefault, w, h, false);
overlay = bmp.copy(Config.ARGB_8888, true);
overlayDefault = bmp2.copy(Config.ARGB_8888, true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
// mCanvas.drawBitmap(overlayDefault,0, 0, null); //exclude this line to show all as you draw
// mCanvas.drawCircle(X, Y, 80, pTouch);
//draw the overlay over the background
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
if(isMoving)
{
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
}
else
{
mMatrix.postTranslate(0,0);
}
canvas.setMatrix(mMatrix);
canvas.drawBitmap(overlay,0,0, null);
for (Path p : paths) {
canvas.drawPath(p, pTouch);
}
super.onDraw(canvas);
}
public Bitmap getBitmap(){
Bitmap b = Bitmap.createScaledBitmap(overlay,display.getWidth() ,display.getWidth(), false);
overlay = b.copy(Config.ARGB_8888, true);
return overlay;
}
public void setBitmap(Bitmap bmp1){
overlay = bmp1;
invalidate();
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
public void touch_start(float x, float y) {
if(xlist.size()>0 && ylist.size()>0){
xlist.clear();
ylist.clear();
}
xlist.add(x);
ylist.add(y);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
mPath.transform(mMatrix, mPath);
invalidate();
}
public 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;
mPath.transform(mMatrix, mPath);
}
xlist.add(x);
ylist.add(y);
invalidate();
}
public void touch_up() {
mPath.lineTo(mX, mY);
mPath = new Path();
mPath.transform(mMatrix, mPath);
paths.add(mPath);
invalidate();
}
public void OnTouchParent(MotionEvent event){
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
float x = event.getX();
float y = event.getY();
/*switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(whichTabSelected==Constant.ERASE)
{
touch_start(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if(whichTabSelected==Constant.ERASE)
{
touch_move(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(whichTabSelected==Constant.ERASE)
{
touch_up();
invalidate();
}
break;
}
if(whichTabSelected==Constant.ERASE)
{
return true;
}
else
{
return false;
}*/
invalidate();
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(getTabMode()==Constant.PANZOOM)
{
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
}
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(getTabMode()==Constant.ERASE)
{
touch_start(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if(getTabMode()==Constant.ERASE)
{
touch_move(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(getTabMode()==Constant.ERASE)
{
touch_up();
invalidate();
}
break;
}
invalidate();
return true;
}
public void setBottomTabMode(int mode)
{
whichTabSelected=mode;
}
public int getTabMode()
{
return whichTabSelected;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
return true;
}
}
private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
#Override
public boolean onRotate(RotateGestureDetector detector) {
mRotationDegrees -= detector.getRotationDegreesDelta();
return true;
}
}
private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
#Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
isMoving=true;
// mFocusX = detector.getFocusX();
// mFocusY = detector.getFocusY();
return true;
}
}
private class ShoveListener extends ShoveGestureDetector.SimpleOnShoveGestureListener {
#Override
public boolean onShove(ShoveGestureDetector detector) {
mAlpha += detector.getShovePixelsDelta();
if (mAlpha > 255)
mAlpha = 255;
else if (mAlpha < 0)
mAlpha = 0;
return true;
}
}
}
I fixed my problem. Actually when i rotate canvas the event.getX() and event.getY() were not map to current rotation of matrix so by adding this line in mMatrix.invert(tempMatrix); in OnDraw() and also map current x,y in OnTouch() by adding this in OnTouch() method .
float[] coords = new float[] { event.getX(), event.getY() };
tempMatrix.mapPoints(coords);
float x = coords[0];//event.getX();
float y = coords[1];//event.getY();
its working fine .
This effect is happening because you are applying the matrix twice to paths.
Once at touch_start/touch_move by doing mPath.transform(mMatrix, mPath);.
And then again at onDraw(Canvas canvas) by canvas.setMatrix(mMatrix); and then canvas.drawPath(p, pTouch);.
To fix, try to remove the mPath.transform(mMatrix, mPath); from touch_start/touch_move.
Also, I do not know if it is a good practice to set the matrix directly to the canvas. Instead of canvas.setMatrix(mMatrix);, I would prefer to do the following:
canvas.save();
canvas.concat(mMatrix);
//write the code....
canvas.restore();

How to draw with multiple fingers in canvas

I am using android Canvas class from creating a drawing application. This is my first attempt to work with the Canvas class. So far the code that I used is working fine and the drawing is working fine. But what I realized in this code is that it allow the user to draw with one finger only, I mean to say if the user used more then one finger to draw on canvas it doesn't allow the user to draw with multiple fingers. I go through documentation regarding multiple touch events but failed to implement it in my code. So can anyone help me to figure this out?
The code I used for drawing on canvas:
public class DrawView extends View implements OnTouchListener
{
private Canvas m_Canvas;
private Path m_Path;
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> arrayListPaths = new ArrayList<Pair<Path, Paint>>();
ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private Bitmap bitmapToCanvas;
private static final float TOUCH_TOLERANCE = 4;
public DrawView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
m_Path = new Path();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
bitmapToCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_Canvas = new Canvas(bitmapToCanvas);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmapToCanvas, 0f, 0f, null);
canvas.drawPath(m_Path, m_Paint);
}
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;
}
private void touch_start(float x, float y)
{
undonePaths.clear();
m_Path.reset();
m_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)
{
m_Path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up()
{
m_Path.lineTo(mX, mY);
// commit the path to our offscreen
m_Canvas.drawPath(m_Path, m_Paint);
// kill this so we don't double draw
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
arrayListPaths.add(new Pair<Path, Paint>(m_Path, newPaint));
m_Path = new Path();
}
}
I tried making changes in my code to support multiple touch, but it doesn't work properly. This is my changed code.
Since there is no answer with working code, I can share a working example. The key is to have an array of currently active pointer ids and their paths. It is also important to know that in case of multiple moving pointers, onTouchEvent gets called only once for all of them and you need to iterate through all of the pointers to draw their new positions.
public class DrawView extends View {
private Paint drawPaint, canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private SparseArray<Path> paths;
public DrawingView(Context context) {
super(context);
setupDrawing();
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupDrawing();
}
private void setupDrawing() {
paths = new SparseArray<>();
drawPaint = new Paint();
drawPaint.setColor(Color.RED);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#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);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (int i=0; i<paths.size(); i++) {
canvas.drawPath(paths.valueAt(i), drawPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int id = event.getPointerId(index);
Path path;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
path = new Path();
path.moveTo(event.getX(index), event.getY(index));
paths.put(id, path);
break;
case MotionEvent.ACTION_MOVE:
for (int i=0; i<event.getPointerCount(); i++) {
id = event.getPointerId(i);
path = paths.get(id);
if (path != null) path.lineTo(event.getX(i), event.getY(i));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
path = paths.get(id);
if (path != null) {
drawCanvas.drawPath(path, drawPaint);
paths.remove(id);
}
break;
default:
return false;
}
invalidate();
return true;
}
}
See Making Sense of Multitouch, it helped me a lot. It explanes how to handle multi touches
Points to remember
1.Make sure that you switch on action & MotionEvent.ACTION_MASK
2.if you want to draw multiple lines at same time, follow PointerId of each pointer which comes in MotionEvent.ACTION_POINTER_DOWN and release it in MotionEvent.ACTION_POINTER_UP by comparing pointer ids.
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
// Existing code ...
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
Edit
Please see this code... This still has some issues but i think you can debug it and fix those ... Also the logic is not there persisting lines please implement that...
package com.example.stackgmfdght;
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.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
public class JustDoIt extends View
{
private Canvas m_Canvas;
// private Path m_Path;
int current_path_count=-1;
ArrayList <Path> m_Path_list = new ArrayList<Path>();
ArrayList <Float> mX_list = new ArrayList<Float>();
ArrayList <Float> mY_list = new ArrayList<Float>();
ArrayList <Integer> mActivePointerId_list = new ArrayList<Integer>();
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> arrayListPaths = new ArrayList<Pair<Path, Paint>>();
//ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private Bitmap bitmapToCanvas;
private static final float TOUCH_TOLERANCE = 4;
public JustDoIt (Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public JustDoIt(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setFocusable(true);
setFocusableInTouchMode(true);
onCanvasInitialization();
}
public void onCanvasInitialization()
{
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#37A1D1"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
// m_Path = new Path();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
bitmapToCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_Canvas = new Canvas(bitmapToCanvas);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmapToCanvas, 0f, 0f, null);
for(int i=0;i<=current_path_count;i++)
{
canvas.drawPath(m_Path_list.get(i), m_Paint);
}
}
public void onDrawCanvas()
{
for (Pair<Path, Paint> p : arrayListPaths)
{
m_Canvas.drawPath(p.first, p.second);
}
}
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
#Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
float x = event.getX();
float y = event.getY();
current_path_count=0;
mActivePointerId_list.add ( event.getPointerId(0),current_path_count);
touch_start((x ),(y ),current_path_count );
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
{
if(event.getPointerCount()>current_path_count)
{
current_path_count++;
float x = event.getX(current_path_count);
float y = event.getY(current_path_count);
mActivePointerId_list.add ( event.getPointerId(current_path_count),current_path_count);
touch_start((x ),(y ),current_path_count);
}
}
break;
case MotionEvent.ACTION_MOVE:
{
for(int i=0;i<=current_path_count;i++)
{ try{
int pointerIndex = event
.findPointerIndex(mActivePointerId_list.get(i));
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
touch_move((x ),(y ),i);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
break;
case MotionEvent.ACTION_UP:
{ current_path_count=-1;
for(int i=0;i<=current_path_count;i++)
{
touch_up(i);
}
mActivePointerId_list = new ArrayList<Integer>();
}
break;
case MotionEvent.ACTION_CANCEL:
{
mActivePointerId = INVALID_POINTER_ID;
current_path_count=-1;
}
break;
case MotionEvent.ACTION_POINTER_UP:
{
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
for(int i=0;i<=current_path_count;i++)
{
if (pointerId == mActivePointerId_list.get(i))
{
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
mActivePointerId_list.remove(i);
touch_up(i);
break;
}
}
}
break;
case MotionEvent.ACTION_OUTSIDE:
break;
}
invalidate();
return true;
}
private void touch_start(float x, float y, int count)
{
// undonePaths.clear();
Path m_Path=new Path();
m_Path_list.add(count,m_Path);
m_Path_list.get(count).reset();
m_Path_list.get(count).moveTo(x, y);
mX_list.add(count,x);
mY_list.add(count,y);
}
private void touch_move(float x, float y,int count)
{
float dx = Math.abs(x - mX_list.get(count));
float dy = Math.abs(y - mY_list.get(count));
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
m_Path_list.get(count).quadTo(mX_list.get(count), mY_list.get(count), (x + mX_list.get(count))/2, (y + mY_list.get(count))/2);
try{
mX_list.remove(count);
mY_list.remove(count);
}
catch(Exception e)
{
e.printStackTrace();
}
mX_list.add(count,x);
mY_list.add(count,y);
}
}
private void touch_up(int count)
{
m_Path_list.get(count).lineTo(mX_list.get(count), mY_list.get(count));
// commit the path to our offscreen
m_Canvas.drawPath( m_Path_list.get(count), m_Paint);
// kill this so we don't double draw
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
arrayListPaths.add(new Pair<Path, Paint>( m_Path_list.get(count), newPaint));
m_Path_list.remove(count);
mX_list.remove(count);
mY_list.remove(count);
}
}
Here example for copy-paste. Just create class that extend View and implement following methods.
private final Paint paint = new Paint(); // Don't forgot to init color, form etc.
#Override
protected void onDraw(Canvas canvas) {
for (int size = paths.size(), i = 0; i < size; i++) {
Path path = paths.get(i);
if (path != null) {
canvas.drawPath(path, paint);
}
}
}
private HashMap<Integer, Float> mX = new HashMap<Integer, Float>();
private HashMap<Integer, Float> mY = new HashMap<Integer, Float>();
private HashMap<Integer, Path> paths = new HashMap<Integer, Path>();
#Override
public boolean onTouchEvent(MotionEvent event) {
int maskedAction = event.getActionMasked();
Log.d(TAG, "onTouchEvent");
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = new Path();
p.moveTo(event.getX(i), event.getY(i));
paths.put(event.getPointerId(i), p);
mX.put(event.getPointerId(i), event.getX(i));
mY.put(event.getPointerId(i), event.getY(i));
}
break;
}
case MotionEvent.ACTION_MOVE: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = paths.get(event.getPointerId(i));
if (p != null) {
float x = event.getX(i);
float y = event.getY(i);
p.quadTo(mX.get(event.getPointerId(i)), mY.get(event.getPointerId(i)), (x + mX.get(event.getPointerId(i))) / 2,
(y + mY.get(event.getPointerId(i))) / 2);
mX.put(event.getPointerId(i), event.getX(i));
mY.put(event.getPointerId(i), event.getY(i));
}
}
invalidate();
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
Path p = paths.get(event.getPointerId(i));
if (p != null) {
p.lineTo(event.getX(i), event.getY(i));
invalidate();
paths.remove(event.getPointerId(i));
mX.remove(event.getPointerId(i));
mY.remove(event.getPointerId(i));
}
}
break;
}
}
return true;
}

Eraser in Android View

I'm creating an application to draw on canvas. To draw I set the pen color to black.
for pen button
int black = Color.BLACK;
mDrawPaint = new DrawPaint(Capture.this, null,black);
where DrawPaint extends View
Now to create eraser I just changed the pen color to white that is the background color of the canvas. Like this
for eraser button
int white = Color.WHITE;
mDrawPaint = new DrawPaint(Capture.this, null,white);
But again if I select the pen button which has pen color black and draw something on canvas, it again automatically redraws the previous paint what I drew before erasing it. Also the eraser erases a big rectangular area. Please explain me what is going wrong. Thank you.
Here is the DrawPaint Constructor
public DrawPaint(Context context, AttributeSet attrs, int color) {
super(context, attrs);
this.destroyDrawingCache();
paint.setAntiAlias(true);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
}
public boolean onTouchEvent(MotionEvent event) {
eventX = event.getX();
eventY = event.getY();
button1.setEnabled(true);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
lastTouchX = eventX;
lastTouchY = eventY;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
resetDirtyRect(eventX, eventY);
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
expandDirtyRect(historicalX, historicalY);
path.lineTo(historicalX, historicalY);
}
path.lineTo(eventX, eventY);
break;
default:
debug("Ignored touch event: " + event.toString());
return false;
}
invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
(int) (dirtyRect.top - HALF_STROKE_WIDTH),
(int) (dirtyRect.right + HALF_STROKE_WIDTH),
(int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
lastTouchX = eventX;
lastTouchY = eventY;
return true;
}
For Eraser you can use this code...
mPaint.setMaskFilter(null);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
and about that square color prob...
Check this out..
this is the best example for canvas drawing with erase, blur and Emboss effect...
public class FingerText extends Activity
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);
//this is the line that sets the initial pen color
mPaint.setColor(inkColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(2);
}
private Paint mPaint;
private Bitmap mBitmap;
private boolean inkChosen;
private int bgColor = 0xFFFFFFFF; //set initial bg color var to white
private int inkColor = 0xFF000000; //set initial ink color var to black
public void colorChanged(int color) {
//This is the implementation of the interface from colorpickerdialog.java
if (inkChosen){
mPaint.setColor(color);
inkColor = color;
}
else {
mBitmap.eraseColor (color);
bgColor = color;
//set the color to the user's last ink color choice
mPaint.setColor(inkColor);
}
}
public class MyView extends View {
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context c) {
super(c);
mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
//this sets the bg color for the bitmap
mBitmap.eraseColor (bgColor);
mCanvas = new Canvas(mBitmap);
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);
}
#Override
protected void onDraw(Canvas canvas) {
//this is the line that changes the bg color in the initial canvas
canvas.drawColor(bgColor);
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 BG_COLOR_ID = Menu.FIRST;
private static final int INK_MENU_ID = Menu.FIRST + 1;
private static final int CLEAR_MENU_ID = Menu.FIRST + 2;
private static final int ERASER_MENU_ID = Menu.FIRST + 3;
private static final int SEND_MENU_ID = Menu.FIRST + 4;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, BG_COLOR_ID, 0, "Background Color").setShortcut('3', 'b');
menu.add(0, INK_MENU_ID, 0, "Ink Color").setShortcut('4', 'c');
menu.add(0, CLEAR_MENU_ID, 0, "Clear All").setShortcut('5', 'e');
menu.add(0, ERASER_MENU_ID, 0, "Eraser").setShortcut('6', 'x');
menu.add(0, SEND_MENU_ID, 0, "Send").setShortcut('7', 's');
/**** 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 BG_COLOR_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
inkChosen = false;
return true;
case INK_MENU_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
//remember the user's last ink choice color so we can revert after eraser
//to background color change -- otherwise ink is last bg color
inkColor = mPaint.getColor();
inkChosen = true;
return true;
case CLEAR_MENU_ID:
mBitmap.eraseColor (bgColor);
return true;
case ERASER_MENU_ID:
//set pen color to bg color for 'erasing'
mPaint.setColor(bgColor);
return true;
case SEND_MENU_ID:
/* TODO need to decide whether to save image locally
* and how to make it available if so. really only need to
* save if we want to let users view later, or pick a
* previous message to send again
*/
// this try-catch block creates a private file and an
// inputstream pointing to it for reading
FileInputStream ifs;
try {
FileOutputStream fs = openFileOutput("message_image", Context.MODE_PRIVATE);
mBitmap.compress(CompressFormat.PNG, 100, fs);
ifs = openFileInput("message_image");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return true;
}
// inserts file pointed to by ifs into image gallery
String url = Images.Media.insertImage(getContentResolver(),
BitmapFactory.decodeStream(ifs),
"Message image1", "Message image");
// alternative: inserts mBitmap into image gallery
/* String url = Images.Media.insertImage(getContentResolver(),
mBitmap, "Message image1", "Message image");
*/
// creates the Intent to open the messaging app
// with the image at url attached
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra("sms_body", "Message created using FingerText");
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(url));
sendIntent.setType("image/png");
startActivity(sendIntent);
/* TODO delete the image from the content provider
* following line deletes the image, but too soon!
*/
// getContentResolver().delete(Uri.parse(url), null, null);
//this resets canvas after send
//could also reset to last user settings w/o var resets
bgColor = 0xFFFFFFFF; //set bg color var back to white
inkColor = 0xFF000000; //set ink color var back to black
mBitmap.eraseColor (bgColor);
return true;
}
return super.onOptionsItemSelected(item);
}
}

How to add CustomView to Layout fromXML?

I want to add this PaintingView() that is in this Activity from XML file.
public class Full extends Activity implements ColorPickerDialog.OnColorChangedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.paint);
FrameLayout myFrameLayout = (FrameLayout) findViewById(R.id.framelayout);
myimage = (ImageView) findViewById(R.id.ImageView01);
InputStream is = this.getResources().openRawResource(imageId1);
originalBitmap = BitmapFactory.decodeStream(is);
myimage.setImageBitmap(originalBitmap);
myimage.setScaleType(ScaleType.MATRIX);
mView = (PaintingView)findViewById(R.id.my_view);
mView.setDrawingCacheEnabled(true);
mView.setVisibility(View.INVISIBLE);
final ImageButton paint = (ImageButton) findViewById(R.id.paint_button);
paint.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
mView.setVisibility(View.VISIBLE);
}
});
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(4);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
//////////////******** Menu Creation *************////////////////
private static final int COLOR_MENU_ID = Menu.FIRST;
private static final int BLUR_MENU_ID = Menu.FIRST + 1;
private static final int ERASE_MENU_ID = Menu.FIRST + 2;
private static final int BRUSH_MENU_ID = Menu.FIRST + 3;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
menu.add(0, BLUR_MENU_ID, 0, "Glow Draw").setShortcut('5', 'z');
menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
menu.add(0, BRUSH_MENU_ID, 0, "Brush").setShortcut('5', 'z');
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 ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
return true;
case BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case BRUSH_MENU_ID:
sizeSeekBar.setVisibility(View.VISIBLE);
/////////*************** Stroke width changed *************//////////////
sizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
#Override
public void onProgressChanged(SeekBar seekBar,int progress, boolean fromUser) {
strokeWidth = sizeSeekBar.getProgress(); // b == progress value.
mPaint.setStrokeWidth(strokeWidth);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) { }
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Context c = getBaseContext();
Toast.makeText(c, " BrushWidth " + strokeWidth, Toast.LENGTH_SHORT).show();
sizeSeekBar.setVisibility(View.INVISIBLE);
}
});
return true;
}
return super.onOptionsItemSelected(item);
}
/////// colour changed function, getting value from ColorPickerDialog ///////
public void colorChanged(int color) {
mPaint.setColor(color);
}
////////////******************* Pinting view *******************///////////////////
/// MY PAINTING view /////////
public class PaintingView extends View {
int bh = originalBitmap.getHeight();
int bw = originalBitmap.getWidth();
public PaintingView(Context c) {
super(c);
//mBitmap = Bitmap.createScaledBitmap(originalBitmap,bw,bh,true);
mBitmap = Bitmap.createBitmap(bw,bh,Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
public PaintingView (Context c, int color) {
super(c);
mBitmap = Bitmap.createBitmap(bw,bh,Bitmap.Config.ARGB_8888);
//mBitmap = Bitmap.createScaledBitmap(originalBitmap,bw,bh,true);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)) ;
mCanvas.drawColor(color);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
/*mBitmap = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);*/
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
////////************touching evants for painting**************///////
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;
} //end of touch events for image
}// end MyView
}
Xml format is:
// tried like this UnSuccess.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="#+id/relativeLayout1">
<com.logistics.wheresTheParty.photoTab.ImageViewTouch
android:id="#+id/imageViewTouch" android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</RelativeLayout>
Change as per your package name and classname....
you can add your custom view to your xml layout using
<ParentLayout>
<yourPackagePath.customviewname
//layout attributes come here
/>
</ParentLayout>
In the particular case of your question.
<pathtoyourclass.PaintingView
//layout attributes
/>

Categories

Resources