I want to draw a rectangle. The first corner should be the point where user first touches screen. When user moves his finger, it should draw the rectangle. Here's a link that shows a video what I want to do. But I don't understand it and maybe You can help me. I just want to draw that rectangle on a white background not on an image.
My code :
package com.example.androiddrawing;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CanvasView extends View {
private Canvas canvas;
private Paint paint = new Paint();
private Paint paint2 = new Paint();
private Paint paint3 = new Paint();
private Path path = new Path();
private Point point = new Point();
private static List<Path> lines = new ArrayList<Path>();
private static List<Point> points = new ArrayList<Point>();
private float x, x2, xc, xd, x3, x4;
private float y, y2, yc, yd, y3, y4;
private boolean touchStarted = false;
public enum DrawMode {
FreeDrawMode, RectDrawMode
};
public static DrawMode currentDrawMode;
public void setDrawMode(DrawMode newDrawMode) {
this.currentDrawMode = newDrawMode;
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint2.setAntiAlias(true);
paint2.setStrokeWidth(5);
paint2.setColor(Color.RED);
paint2.setStyle(Paint.Style.STROKE);
paint2.setStrokeJoin(Paint.Join.ROUND);
paint3.setAntiAlias(true);
paint3.setColor(Color.BLACK);
paint3.setStrokeWidth(10);
paint3.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
for (Path p : lines)
canvas.drawPath(p, paint);
canvas.drawPath(path, paint2);
for (Point point : points)
canvas.drawCircle(point.x, point.y, 0, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
System.out.println(currentDrawMode);
if (currentDrawMode == DrawMode.FreeDrawMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Set a new starting point
paint2.setColor(Color.RED);
path = new Path();
path.moveTo(x, y);
touchStarted = true;
break;
// return true;
case MotionEvent.ACTION_MOVE:
// Connect the points
touchStarted = false;
path.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
if (touchStarted) {
point = new Point();
point.x = (int) x;
point.y = (int) y;
paint2.setColor(Color.BLACK);
points.add(point);
touchStarted = false;
System.out.println("siin");
} else {
System.out.println("seal");
paint2.setColor(Color.BLACK);
lines.add(path);
}
break;
default:
return false;
}
} else if (currentDrawMode == DrawMode.RectDrawMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Set a new starting point
paint3.setColor(Color.RED);
//CODE HERE
break;
// return true;
case MotionEvent.ACTION_MOVE:
//CODE HERE
break;
case MotionEvent.ACTION_UP:
//CODE HERE
break;
default:
return false;
}
}
// Makes our view repaint and call onDraw
invalidate();
return true;
}
}
I should write the code where I put the comments //CODE HERE, but I really don't understand, how do I have to draw a rectangle.
You can use the below code. Hope this helps you.
public class DrawSample extends View {
int mStartX;
int mStartY;
int mEndX;
int mEndY;
Paint mPaint = new Paint();
int mSelectedColor = Color.BLACK;
public DrawSample(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint.setColor(mSelectedColor);
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);
setFocusable(true);
}
public DrawSample(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mStartX = (int) event.getX();
mStartY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
mEndX = (int) event.getX();
mEndY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
mEndX = (int) event.getX();
mEndY = (int) event.getY();
invalidate();
break;
default:
super.onTouchEvent(event);
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(mStartX, mStartY, mEndX, mEndY, mPaint);
}
}
You need to keep the start X and Y points, then, when user stop drawing in the MotionEvent.ACTION_UP get the ending X and Y to get 4 corners of the rectangle:
canvas.drawRect(startX, startY, x, y, paint3);
You can find more info about drawRect here and here.
EDIT i dont have nice environment to test it... but I found some errors in your answer:
else if (currentDrawMode == DrawMode.RectDrawMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Set a new starting point
paint3.setColor(Color.RED);
startX = event.getX();
startY = event.getY();
break;
// return true;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
canvas.drawRect(startX, startY, endX, endY, paint3);
//invalidate(); // Tell View that the canvas needs to be redrawn
break;
case MotionEvent.ACTION_UP:
paint3.setColor(Color.BLACK);
canvas.drawRect(startX, startY, endX, endY, paint3);
break;
default:
return false;
}
PS: if you want add info to your question edit it, but dont post new answers!!!
Related
I am studying android studio and touchevent.
First, my project is like paint.
My code is here.
package com.example.a2_touchevent;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import static android.graphics.drawable.GradientDrawable.LINE;
import static android.graphics.drawable.GradientDrawable.RECTANGLE;
public class MainActivity extends AppCompatActivity {
final static int LINE = 1, CIRCLE = 2, RECTANGLE = 3;
static int curShape = LINE;
static int color = Color.BLACK;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);
menu.add(0, 1, 0, "선 그리기"); //draw Line
menu.add(0, 2, 0, "원 그리기"); //draw Circle
menu.add(0, 3, 0, "사각형 그리기"); //draw Rectangle
SubMenu subMenu = menu.addSubMenu("색상 변경 >> "); //Colorchange
subMenu.add(0, 4, 0, "빨강"); //red
subMenu.add(0, 5, 0, "초록"); //green
subMenu.add(0, 6, 0, "파랑"); //blue
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case 1:
curShape = LINE;
return true;
case 2:
curShape = CIRCLE;
return true;
case 3:
curShape = RECTANGLE;
return true;
case 4:
color = Color.RED;
return true;
case 5:
color = Color.GREEN;
return true;
case 6:
color = Color.BLUE;
return true;
}
return super.onOptionsItemSelected(item);
}
private static class MyGraphicView extends View {
int startX = -1, startY = -1, stopX = -1, stopY = -1;
public MyGraphicView(Context context){
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
startY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
stopX = (int) event.getX();
stopY = (int) event.getY();
this.invalidate();
break;
}
return true;
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
switch (curShape) {
case LINE:
canvas.drawLine(startX, startY, stopX, stopY, paint);
break;
case CIRCLE:
int radius = (int) Math.sqrt(Math.pow(stopX - startX, 2) + Math.pow(stopY - startY, 2));
canvas.drawCircle(startX, startY, radius, paint);
break;
case RECTANGLE:
Rect rect = new Rect(startX, startY, stopX, stopY);
canvas.drawRect(rect, paint);
break;
}
}
}
}
and result is here.
https://ibb.co/dJMxNZ4
p.s How can I post GIF file in question?
Anyway, I want to save my draw before new mouse clickevent.
the hint in my textbook, use dynamic list, but I cant use it.
first, I create myShape class
private static class MyShape {
int shapeType;
int startX, startY, stopX, stopY;
int color;
static List<MyShape> myshape = new ArrayList<MyShape>();
}
and then, how can I use this class and save my drawing?
Thanks.
You can maintain a list of drawingData( data needed for drawing a shape ) and in onDraw function you can loop through them and draw. A sample implementation of your MyGraphicView may look something like the one below.
private static class MyGraphicView extends View {
DrawingData currentShape = null;
ArrayList<DrawingData> drawingData = new ArrayList<>();
public MyGraphicView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentShape = new DrawingData(curShape);
currentShape.startX = (int) event.getX();
currentShape.startY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
currentShape.stopX = (int) event.getX();
currentShape.stopY = (int) event.getY();
this.invalidate();
break;
case MotionEvent.ACTION_UP:
currentShape.stopX = (int) event.getX();
currentShape.stopY = (int) event.getY();
drawingData.add(currentShape);
currentShape = null;
this.invalidate();
break;
}
return true;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
for (DrawingData drawingDatum : drawingData) {
drawShape(drawingDatum, canvas, paint);
}
if (currentShape != null) {
drawShape(currentShape, canvas, paint);
}
}
private void drawShape(DrawingData drawingDatum, Canvas canvas, Paint paint) {
switch (drawingDatum.shape) {
case LINE:
canvas.drawLine(drawingDatum.startX, drawingDatum.startY, drawingDatum.stopX, drawingDatum.stopY, paint);
break;
case CIRCLE:
int radius = (int) Math.sqrt(Math.pow(drawingDatum.stopX - drawingDatum.startX, 2) + Math.pow(drawingDatum.stopY - drawingDatum.startY, 2));
canvas.drawCircle(drawingDatum.startX, drawingDatum.startY, radius, paint);
break;
case RECTANGLE:
Rect rect = new Rect(drawingDatum.startX, drawingDatum.startY, drawingDatum.stopX, drawingDatum.stopY);
canvas.drawRect(rect, paint);
break;
}
}
private static class DrawingData {
int shape;
int startX;
int startY;
int stopX;
int stopY;
public DrawingData(int shape) {
this.shape = shape;
}
}
}
I'm trying to draw bitmap multiple time something similar to this :
the code below makes bitmap just moving :
public class TheChainView extends View {
Bitmap bitmap;
float x = 200;
float y = 200;
public TheChainView(Context context, AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.heart);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
x = event.getX();
y = event.getY();
invalidate();
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, x, y, null);
}
}
how I can make a bitmap draw a multiple time whenever I touch the screen
This may not be a good solution but you can hold the co-coordinates in some data structure like below:
public class TheChainView extends View {
Bitmap bitmap;
List<Point> points = new ArrayList<>();
public TheChainView(Context context, AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.heart);
points.add(new Point(200, 200));
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
points.add(new Point(event.getX(), event.getY()));
invalidate();
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Point p : points) {
canvas.drawBitmap(bitmap, p.x, p.y, null);
}
}
static class Point {
float x, y;
Point(float x, float y) {
this.x = x;
this.y = y;
}
}
}
I wanted to draw the custom shape using multiple straight lines. For that, i used the canvas. But I can draw only one line. When I draw second, previous disappears.
My code is given.
public class CanvasBackground extends View {
public Paint paint;
public Context context;
public Canvas canvas;
public ScaleGestureDetector scaleGestureDetector;
float scalfactor = 1f;
boolean isDrawing;
private PointF startPoint, endPoint;
public CanvasBackground(Context context) {
super(context);
this.context = context;
paint = new Paint();
scaleGestureDetector = new ScaleGestureDetector(context, new CanvasScale());
setDrawingCacheEnabled(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
canvas.save();
DrawingZoomingCanvas(canvas);
DrawingLine(canvas);
canvas.restore();
Log.e("OnDraw >>>", "CALLING");
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startPoint = new PointF(event.getX(), event.getY());
endPoint = new PointF();
isDrawing = true;
break;
case MotionEvent.ACTION_MOVE:
if (isDrawing) {
endPoint.x = event.getX();
endPoint.y = event.getY();
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (isDrawing) {
endPoint.x = event.getX();
endPoint.y = event.getY();
//isDrawing = false;
invalidate();
}
break;
default:
break;
}
//scaleGestureDetector.onTouchEvent(event);
Log.e("OnTouch >>>", "CALLING" + isDrawing);
return true;
}
//drawing Matrix Canvas With Zoom
private void DrawingZoomingCanvas(Canvas canvas) {
//drawing Matarix
canvas.translate(scalfactor * 10, scalfactor * 10);
canvas.scale(scalfactor, scalfactor);
paint.setColor(Color.rgb(220, 220, 220));
for (int i = 0; i <= canvas.getHeight() * scalfactor; i += 10) {
canvas.drawLine(i, 0, i, canvas.getHeight(), paint);
canvas.drawLine(0, i, canvas.getWidth(), i, paint);
}
}
//drawing a line
private void DrawingLine(Canvas canvas) {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
if (isDrawing)
canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint);
}
private class CanvasScale extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
scalfactor *= scaleGestureDetector.getScaleFactor();
scalfactor = Math.max(0.1f, Math.min(scalfactor, 10.0f));
invalidate();
return true;
}
}
}
You are clearing your canvas each time you draw a line, so the previous line will be erased as you draw the new one.
You need to store the previous lines in a bitmap so you can draw these when you draw the new one.
based on the answer of this question:Android drawing a line to follow your finger
I tried my solution (see the code), but i get a shape like spaghetti.. How to get rid of the previous lines? I want to draw a straight line like in Microsoft Paint.
here's my code:
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downx = event.getX();
downy = event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
upx = event.getX();
upy = event.getY();
mCanvas.drawLine(downx, downy, upx, upy, mPaint);
invalidate();
break;
case MotionEvent.ACTION_UP:
upx = event.getX();
upy = event.getY();
mCanvas.drawLine(downx, downy, upx, upy, mPaint);
invalidate();
break;
}
return true;
}
Thank you all!
PS: It's not duplicated question,i explained above!
You shouldn't draw in onTouchEvent, don't store a reference to canvas, move drawLine to
#Override protected void onDraw(Canvas canvas) { ... }
invalidate() will call draw() for you which in turn calls onDraw().
In general: use UI events like onTouchEvent and onClick to modify the state of the view, then call invalidate() from those events and implement onDraw so it always renders the state of the object.
FingerLine.java
import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.*;
public class FingerLine extends View {
private final Paint mPaint;
private float startX;
private float startY;
private float endX;
private float endY;
public FingerLine(Context context) {
this(context, null);
}
public FingerLine(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Style.STROKE);
mPaint.setColor(Color.RED);
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(startX, startY, endX, endY, mPaint);
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
// Set the end to prevent initial jump (like on the demo recording)
endX = event.getX();
endY = event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
endX = event.getX();
endY = event.getY();
invalidate();
break;
}
return true;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<net.twisterrob.android.view.FingerLine
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
MainActivity.java
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Result
Note: I'm using <application android:theme="#style/Theme.AppCompat.Light">, but I don't think that could make a difference.
You need to reset the background color of the View, in the onDraw() function before your line drawing code call Canvas.drawColor(Color.WHITE), replacing WHITE with whatever your background color is. Or you can just call the super.onDraw(canvas) function in onDraw() before any of the other code.
Sorry for the lack of examples, I'm writing this from my phone.
Here's solution that make the line follows the finger. (and doesn't disappear after)
import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.*;
public class FingerLine extends View {
private final Paint mPaint;
private float startX;
private float startY;
private float endX;
private float endY;
public Canvas mCanvas;
public FingerLine(Context context) {
this(context, null);
mBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
}else {
mBitmap = Bitmap.createBitmap(height, height, Bitmap.Config.ARGB_8888);
}
mCanvas = new Canvas(mBitmap);
}
public FingerLine(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Style.STROKE);
mPaint.setColor(Color.RED);
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(startX, startY, endX, endY, mPaint);
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
endX = event.getX();
endY = event.getY();
mcanvas.drawLine(startX, startY, endX, endY, mPaint);
invalidate();
break;
}
return true;
}
}
Here's the kotlin version of the answer..
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
class FingerLineView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
private var mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private var startX = 0f
private var startY = 0f
private var endX = 0f
private var endY = 0f
init {
mPaint.style = Paint.Style.STROKE
mPaint.color = Color.RED
mPaint.strokeWidth = 4f
mPaint.strokeCap = Paint.Cap.ROUND
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawLine(startX, startY, endX, endY, mPaint)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event!!.action) {
MotionEvent.ACTION_DOWN -> {
startX = event.x
startY = event.y
// Set the end to prevent initial jump (like on the demo recording)
endX = event.x
endY = event.y
invalidate()
}
MotionEvent.ACTION_MOVE -> {
endX = event.x
endY = event.y
invalidate()
}
MotionEvent.ACTION_UP -> {
endX = event.x
endY = event.y
invalidate()
}
}
return true
}
}
I want to make a class which captures a human signature for my Android app. I have this code so far:
public class DrawView extends View implements OnTouchListener {
private static final String TAG = "DrawView";
List<Point> points = new ArrayList<Point>();
Paint paint = new Paint();
long oldTime = 0;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
// paint.setColor(Color.BLACK);
// paint.setAntiAlias(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
if (points.size() > 1) {
for (int i = points.size() - 2; i < points.size(); i++) {
if (i >= 0) {
Point point = points.get(i);
if (i == 0) {
Point next = points.get(i + 1);
point.dx = ((next.x - point.x) / 3);
point.dy = ((next.y - point.y) / 3);
} else if (i == points.size() - 1) {
Point prev = points.get(i - 1);
point.dx = ((point.x - prev.x) / 3);
point.dy = ((point.y - prev.y) / 3);
} else {
Point next = points.get(i + 1);
Point prev = points.get(i - 1);
point.dx = ((next.x - prev.x) / 3);
point.dy = ((next.y - prev.y) / 3);
}
}
}
}
boolean first = true;
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else {
Point prev = points.get(i - 1);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x
- point.dx, point.y - point.dy, point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}
return super.onTouchEvent(event);
}
public boolean checkTime() {
//Check if there was an input 400 ms ago
long newTime = System.currentTimeMillis();
long diffirence = newTime - oldTime;
if (oldTime == 0) {
oldTime = System.currentTimeMillis();
return true;
} else if (diffirence <= 400) {
oldTime = System.currentTimeMillis();
return true;
}
return false;
}
}
class Point {
float x, y;
float dx, dy;
#Override
public String toString() {
return x + ", " + y;
}
}
The problem is that the line will connect to the latest point when I start drawing again, even when I stop drawing for a while. This is of course not very useful for capturing human signatures, that's why I created the checkTime method. If you stop drawing for 400ms it returns false, when you start drawing again it will start a new line which is not connected to the old line. I only just don't know how I can implement my method, I tried a lot but the line keeps connecting to the latest point, maybe someone can help me.
It's probably faster to create the path in onTouch and only draw it in onDraw.
Replace onTouch with
Path path = new Path();
int prevx=0;
int prevy=0;
int prevdx=0;
int prevdy=0;
public boolean onTouch(View view, MotionEvent event)
{
int x = event.getX();
int y = event.getY();
int dx = (x-prevx)/3;
int dy = (y-prevy)/3;
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
path.moveTo(x, y);
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
path.cubicTo(prevx + prevdx, prevy + prevdy, x - dx, y - dy, x, y);
}
prevx=x;
prevy=y;
prevdx=dx;
prevdy=dy;
invalidate();
return true;
}
onDraw will be just
public void onDraw(Canvas canvas)
{
canvas.drawPath(path, paint);
}
I used this post from Lars Vogel, but many thanks to Marc Van Daele!
This is code wich paints the View:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
private Path path = new Path();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(6f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}
You have to call this activity to start paiting:
import android.app.Activity;
import android.os.Bundle;
public class SingleTouchActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SingleTouchEventView(this, null));
}
}