In my app I want to draw a line on imageview.I want to write a line with finger when i touch it.This is my requirement.For that i googled alot And fallow the bellow link:
How to draw a Line in ImageView on Android?.
In my activity i have created the object to MyImageView class and in my OnTouchListener override onTouch() method and in MotionEvent.ACTION_DOWN: switch case i have written update() method.And i am getting this error:" The method update() is undefined for the type new View.OnTouchListener(){}".So please any one suggest me to how to do this.Thanks for any help inadvance.
This is my code:
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN: // first finger down only
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
og.d(TAG, "mode=DRAG"); // write to LogCat
mode1 = DRAG1;
if(checkPencil){
//update();
}
break;
case MotionEvent.ACTION_UP: // first finger lifted
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode1 = NONE1;
Log.d(TAG, "mode1=NONE1");
break;
case MotionEvent.ACTION_MOVE:
if (mode1 == DRAG1)
{
if(check){ matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
}
else if (mode1 == ZOOM1)
{
if(check){
Log.e("if elseeeeeee","dfgrtgytey");
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
// its for rotation..
if (lastEvent!=null){
newRot = rotation(event);
//if (Constant.TRACE) Log.d("Degreeeeeeeeeee", "newRot="+(newRot));
float r = newRot-d; matrix.postRotate(r, view.getMeasuredWidth()/2, view.getMeasuredHeight()/2);
}
}
}
break;
//rotation..
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) { savedMatrix.set(matrix);
midPoint(mid, event);
mode1 = ZOOM1;
Log.d(TAG, "mode=ZOOM")
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
}//switch
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
});
In my app drag the image,rotate the image and zoom the image everything is working fine.And my requirement is when i click the button drawing functionality will be working.that is the reason i have written the update method in this block:"if(checkPencil){
//update();
}.But it is not working.
Canvas c = null;
c = mSurfaceHolder.lockCanvas();
imageview.line(canvas);
mSurfaceHolder.unlockCanvasAndPost(c);
public void line(Canvas draw){
// set the layout parameters
// get the background image as ImageView
// Use the gesture Overlay concept.
}
The link you posted should work. Instead of using the stock image view, create a class which extends it. The imageview you extend will support a method called addLine which will add the line in an arraylist and override the onDraw method to draw the lines in the arraylist
public class Line{
int x1,y2, x2,y2;
Paint p;
public Line(int x1, y1, x2, y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
p= new Paint(Paint.ANTI_ALIAS_FLAG);
}
public void draw(Canvas c){
c.drawLine(x1, y1, x2, y2, p);
}
}
public class MyImageView extends ImageView{
ArrayList<Line> lines;
public void addLine(int x1, int y1, int x2, int y2){
lines.add(new Line(x1,y1,x2,y2));
//this.invalidate(); //queue a call to the onDraw method
}
public MyImageView(Context context) {
super(context);
lines = new ArrayList<Line>();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(Line l : lines){
l.draw(canvas);
}
}
}
hye friends
Simple Line Drawing with canvas:-
public class MainActivity extends Activity {
private RelativeLayout relativelayout;
private Paint mPaint, mBitmapPaint;
private MyView mView;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativelayout = (RelativeLayout) findViewById(R.id.item);
DisplayMetrics metrics = getBaseContext().getResources().getDisplayMetrics();
int w = metrics.widthPixels;
int h = metrics.heightPixels;
System.out.println(" width " + w);
System.out.println(" height " + h);
mView = new MyView(this, w, h);
mView.setDrawingCacheEnabled(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.Black);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(5);
relativelayout.addView(mView);
}
public class MyView extends View {
public MyView(Context c, int w, int h) {
super(c);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapPaint
.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
#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(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 5;
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();
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;
}
}
}
Related
i have a layout for drawing content_designer.xml
<Button
android:id="#+id/loadBMP"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="Load"/>
<com.system.v.construct.Drawing
android:id="#+id/canvasDraw"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
In my activity i set the view and whe user click the button bmp must be loaded.
setContentView(R.layout.content_designer);
Button load=(Button)findViewById(R.id.loadBMP);
final Drawing drawing=new Drawing(this);
load.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"Click",Toast.LENGTH_LONG).show();
drawing.looadBMP();
}
});
In drawing class i have a method looadBMP()
But the image doesnt load, i'm beginner in drawing, so sorry for mistake
Here is a full Drawin class seems like method on Draw is executed first, i need bmp image load on button click:
public class Drawing extends View implements OnTouchListener {
private Canvas mCanvas;
private Path mPath;
public Paint mPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
Bitmap bmp;
public static Canvas myCanvas;
public Drawing(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
public void looadBMP()
{
setFocusable(true);
setFocusableInTouchMode(true);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.simple);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas(bmp);
mPath = new Path();
paths.add(mPath);
mCanvas.drawBitmap(bmp, 0, 0, mPaint);
for (Path p : paths) {
mCanvas.drawPath(p, mPaint);
}
}
#Override
protected void onDraw(Canvas canvas) {
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
//Drawing dw = new Drawing();
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 = new Path();
paths.add(mPath);
}
#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;
}
}
I have written an Android application with a Canvas for drawing with a stylus. It works well. When I'm pushing the upper function key of my stylus I would like to erase the drawing by brushing over the text. The normal drawing is in black, so I thought to do the erase with white (on top of the black line). My problem is that all lines change the color when I press the upper function key of the stylus (i.e. all lines are then white) instead of just painting the new draw line in white.
Another option would be to delete elements from the path for the erase. If somebody has a solution for this, I would be happy too.
The layout looks as follows:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="StylusBaselineA">
<inf.ethz.ch.affectivestudy.CanvasView
android:id="#+id/baselineACanvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textColor="#FFFFFF" />
</android.support.constraint.ConstraintLayout>
The CanvasView class look as follows:
public class CanvasView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Path mPathErase;
Context context;
private Paint mPaint;
private Paint mPaintErase;
private float mX, mY;
private static final float TOLERANCE = 5;
private boolean erase = false;
public CanvasView(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;
// we set a new Path
mPath = new Path();
mPathErase = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
mPaintErase = new Paint();
mPaintErase.setAntiAlias(true);
mPaintErase.setColor(Color.WHITE);
mPaintErase.setStyle(Paint.Style.STROKE);
mPaintErase.setStrokeJoin(Paint.Join.ROUND);
mPaintErase.setStrokeWidth(4f);
}
// override onSizeChanged
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// your Canvas will draw onto the defined Bitmap
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw the mPath with the mPaint on the canvas when onDraw
if (erase) {
canvas.drawPath(mPathErase, mPaintErase);
} else {
canvas.drawPath(mPath, mPaint);
}
}
// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
if (erase) {
mPathErase.moveTo(x, y);
} else {
mPath.moveTo(x, y);
}
mX = x;
mY = y;
}
// when ACTION_MOVE move touch according to the x,y values
private void moveTouch(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOLERANCE || dy >= TOLERANCE) {
if (erase) {
mPathErase.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
} else {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
}
mX = x;
mY = y;
}
}
public void clearCanvas() {
mPath.reset();
mPathErase.reset();
invalidate();
}
// when ACTION_UP stop touch
private void upTouch() {
if (erase) {
mPathErase.lineTo(mX, mY);
} else {
mPath.lineTo(mX, mY);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
// Upper function key of stylus
erase = true;
} else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER) {
// Touch input
erase = false;
return false;
} else {
erase = false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
}
Try this.
public class CanvasActivity extends AppCompatActivity {
private Paint mPaint;
View mView;
Button clear;
private Canvas mCanvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_canvas);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.Linear_layout);
mView = new DrawingView(this);
layout.addView(mView, new LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT));
clear= (Button) findViewById(R.id.clear);
clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCanvas.drawColor(Color.WHITE);
}
});
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#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) {
super.onDraw(canvas);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// 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;
}
}
}
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();
Can someone explain me why on earth this piece of code does not draw every object?
public class A extends View {
private Paint paint = new Paint();
private Path path = new Path();
ArrayList<Pair<Path, Paint>> paths = new ArrayList<Pair<Path, Paint>>();
public A(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
for (Pair<Path, Paint> p : paths) {
canvas.drawPath(p.first, p.second);
}
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(3f);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int color = Color.rgb(new Random().nextInt(255),
new Random().nextInt(255),
new Random().nextInt(255));
paint.setColor(color);
path.reset(); //new stroke, get old one erased
int historySize = event.getHistorySize();
for (int i = 0; i > historySize; i++) {
path.moveTo(eventX, eventY);
}
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
return true;
case MotionEvent.ACTION_UP:
path.lineTo(eventX, eventY);
// End of stroke, add this to the collection
paths.add(new Pair<Path, Paint>(path, paint));
break;
default:
break;
}
// Schedules a repaint.
invalidate();
return true;
}
}
I'm catching every strokes with the onTouchEvent and i create different path/paint ojects stored in a Pair one. Sadly in my OnDraw when I try to draw them all it fails ..
I've read some topic without finding right answer. Each time some people recommend to create and work in a bitmap and draw it to the screen but i'd like to avoid this solution.
Thank's for your help !
The problem is that you always use the same Path and Paint object. You should create new Path and Paint each time MotionEvent.ACTION_DOWN is fired
Remove the path.reset in switch condition. The draw works. But color does change even for previous draw. You resetting the paths which is clearing the previous draw.
I would use a different pair (path and paint) everytime to draw.
In case you want to draw using canvas the below code work's just fine.
I would also add a color picker to allow user to pick color of his choice.
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);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
// 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;
}
}
You need to use only one Path and Paint object.
A detailed tutorial on this whole thing can in fact be found here:
Making a basic single touch drawing app on Android - Creative Punch
I am writing mini app for signature, user use finger for paint.
I draw in function onPaint but nothing. I don't understand, I debugged but I didn't fix it. I see, if I draw in function onCreate is ok.
I want draw in onPaint.
public class Main extends Activity{
ImageView drawingImageView;
float downx = 0;
float downy = 0;
float upx = 0;
float upy = 0;
private Bitmap bitmap;
private Canvas canvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawingImageView = (ImageView) this.findViewById(R.id.imageView1);
bitmap = Bitmap.createBitmap((int) getWindowManager()
.getDefaultDisplay().getWidth(), (int) getWindowManager()
.getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
drawingImageView.setImageBitmap(bitmap);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.GREEN);
mPaint.setTextSize(20);
mPaint.setTypeface(Typeface.DEFAULT);
canvas.drawLine(0, 0, 200, 200, mPaint);
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawLine(0, 0, 100, 100, 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
canvas.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);
onDraw(canvas);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
onDraw(canvas);
break;
case MotionEvent.ACTION_UP:
touch_up();
onDraw(canvas);
break;
}
return true;
}
}
call canvas.restore(); after all drawing operations.
Beside the awful code formatting: you can't call onDraw() with a self created canvas in a onTouch method. To get a basic feeling about 2D drawing, check my tutorial series