I have been developing the application for drawing and I have some problems: the mean for drawing by a finger has been done already, but now I need to make anything that allow user to write a common text label on a View. So, please, look at my code:
public class PainterView extends View implements DrawingListener {
private Painter painter;
private Bitmap bitmap;
private Paint bitmapPaint;
private Path path;
private Paint paint;
public PainterView(Context context, Painter painter) {
super(context);
this.painter=painter;
this.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
PainterView.this.painter.touchStart(x, y);
break;
case MotionEvent.ACTION_MOVE:
PainterView.this.painter.touchMove(x, y);
break;
case MotionEvent.ACTION_UP:
PainterView.this.painter.touchUp();
break;
}
return true;
}
});
this.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.e("event", "click");
}
});
this.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
Log.e("event", "long");
return true;
}
});
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
protected void onDraw(Canvas canvas) {
if (bitmap!=null) {
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
canvas.drawPath(path, paint);
}
}
public void onPictureUpdate(Bitmap bitmap, Paint bitmapPaint, Path path, Paint paint) {
this.bitmap=bitmap;
this.bitmapPaint=bitmapPaint;
this.path=path;
this.paint=paint;
invalidate();
}
public void setPainter(Painter painter) {
this.painter=painter;
}
}
It's code for drawing; the process of drawing is in Painter class. So, now I need to allow user to write a simple text. I thought that I can do it using long clicks - user do a long click, keypad is opened, and user can input a text. But it doesn't work! I don't see any strings in my Log.
Please, tell me advice about my problem or some idea how I can realize what I need.
I'm pretty sure the OnTouchListener is consuming the touch event when you return true. Try return super.onTouch(v, event).
Related
I am drawing on the canvas properly and saving it into a bitmap.
However, I want to reset the canvas to white by clicking a button.
Here is my code:
public class Canvas extends View {
Paint paint;
Path path;
boolean cc = false;
public Canvas(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
path = new Path();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5f);
}
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
if (!cc) {
canvas.drawPath(path, paint);
}
else {
canvas.drawColor(Color.WHITE);
cc = false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float xPos = event.getX();
float yPos = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(xPos, yPos);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(xPos, yPos);
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
invalidate();
return true;
}
public void clear() {
cc = true;
invalidate();
}
my clear() function set cc to "true" then invalidate() calls the onDraw() function. But it seems that "cc" is not recognized inside the onDraw() or it has always the same value inside.
I tried the path.reset() with no result.
calling clear() does not return any error.
Seems you'd want the path to get cleared too when your clear() method is called, so do that, then use the fact that the path is empty to clear the canvas.
public void clear() {
path.reset();
invalidate();
}
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
if (path.isEmpty()) {
canvas.drawColor(Color.WHITE);
} else {
canvas.drawPath(path, paint);
}
}
That entirely eliminates the cc field.
To clear all your canvas use this:
Paint transparent = new Paint();
transparent.setAlpha(0);
Update:
Add this line in your button onclick():
canvas.drawColor(Color.WHITE);
And remove it from the draw function.
I want to edit my drawing painted image. I am getting a bitmap image and setting it into a canvas bitmap, but the old image is not appearing. I have tried using the drawingView.refresh() and recycle() methods, but couldn't make it work.
private DrawingView mDrawingView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawing);
if(datadtlimgsItem !=null && datadtlimgsItem.getImageStr()
!=null) {
decodedString = Base64.decode(datadtlimgsItem.getImageStr(),
Base64.DEFAULT);
decodedByte = BitmapFactory.decodeByteArray(decodedString, 0,
decodedString.length);
decodedByte = Util.resize(decodedByte, 400, 100);
mDrawingView.canvasBitmap = decodedByte;
}
}
public class DrawingView extends View{
// To hold the path that will be drawn.
private Path drawPath;
// Paint object to draw drawPath and drawCanvas.
private Paint drawPaint, canvasPaint;
// initial color
private int paintColor = 0xff000000;
private int previousColor = paintColor;
// canvas on which drawing takes place.
private Canvas drawCanvas;
// canvas bitmap
public Bitmap canvasBitmap;
// Brush stroke width
private float brushSize, lastBrushSize;
// To enable and disable erasing mode.
private boolean erase = false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setUpDrawing();
}
/**
* Initialize all objects required for drawing here.
* One time initialization reduces resource consumption.
*/
private void setUpDrawing(){
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
// Making drawing smooth.
drawPaint.setAntiAlias(true);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
// Initial brush size is medium.
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
drawPaint.setStrokeWidth(brushSize);
}
#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) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// X and Y position of user touch.
float touchX = event.getX();
float touchY = event.getY();
// Draw the path according to the touch event taking place.
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
if (erase){
drawPaint.setXfermode(new
PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
drawPaint.setXfermode(null);
break;
default:
return false;
}
// invalidate the view so that canvas is redrawn.
invalidate();
return true;
}
public void setColor(String newColor){
// invalidate the view
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
previousColor = paintColor;
}
public void setBrushSize(float newSize){
float pixelAmount =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
public void setErase(boolean isErase){
//set erase true or false
erase = isErase;
if(erase) {
drawPaint.setColor(Color.WHITE);
//drawPaint.setXfermode(new
PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
else {
drawPaint.setColor(previousColor);
drawPaint.setXfermode(null);
}
}
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
I have a view like Paint I want to show old image getting from activity in current view and then edit my image.
image is blank but i need to show previous image here
here is saved image want to edit this image
I have a view like Paint I want to show old image getting from activity in current view and then edit my image. I have a view like Paint I want to show old image getting from activity in current view and then edit my image. I have a view like Paint I want to show old image getting from activity in current view and then edit my image. I have a view like Paint I want to show old image getting from activity in current view and then edit my image. I have a view like Paint I want to show old image getting from activity in current view and then edit my image.
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (canvasBitmap == null){
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}
drawCanvas = new Canvas(canvasBitmap);
}
i'm working on a project where i create mirror of drawing. my main logic is working fine.Only thing causing Problem is Redo and undo functionality.
i have searched a lot. implement may methods but couldn't get success. Following is my Drawing Class.
DrawingView.java
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
this.context=context;
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
brushSize = getResources().getInteger(R.integer.small_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPath1 = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//size assigned to view
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
width=w;
height=h;
Log.d("width,height", w + " , " + h);
drawCanvas = new Canvas(canvasBitmap);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
for (Path p : paths){canvas.drawPath(p, drawPaint);}
canvas.drawPath(drawPath, drawPaint);
Log.i("OnDRAWING", "REACH ON DRAW");
/*canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
canvas.drawPath(drawPath1, drawPaint);*/
}
//register user touches as drawing action
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.reset();
undonePaths.clear();
drawPath.moveTo(touchX, touchY);
undonePaths.clear();
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);// commit the path to our offscreen
paths.add(drawPath);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
drawCanvas.drawPath(drawPath1, drawPaint);
drawPath1.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
What i am missing here?
Any suggestions/ideas/examples which is the best way to implement this kind of functionality on my project?
Canvas drawing is sort of hierarchal in that drawing happens in the order that you do them.
So all drawing should be done in onDraw and only here.
Your draw events should be pushed on a draw stack. You do not store a canvas. You just store the operations that are supposed to happen when the drawing eventually occurs (coordinates, width, and color of a path for example).
An "undo" operation can be done by popping from the drawing stack and pushing the event to a "redo" stack. The "redo" event can be done by popping from the "redo" stack and pushing back on to the "drawing" stack.
In onDraw method of your View, just scan through the drawing events and draw on the canvas.
EDIT:
The onDraw() method would just iterate through your drawing operations. So first you could have an interface called DrawEvent like so:
public interface DrawEvent {
void draw(Canvas c);
}
Then in your View class have your collection of DrawEvents and iterate through them in onDraw(Canvas c).
public class MyView extends View {
Deque<DrawEvent> drawEvents = new LinkedList<DrawEvent>();
#Override
public void onDraw(Canvas c) {
for (DrawEvent e : drawEvents) {
e.draw(c);
}
}
}
I want to make it so that pressing the screen moves my rectangle. The listener gives output to console but it doesn't invalidate the screen.
public class DrawView extends View{
Paint paint = new Paint();
static int x = 20;
static int y = 20;
public DrawView(Context context){
super(context);
paint.setColor(Color.GREEN);
}
#Override
public void onDraw(Canvas canvas){
canvas.drawRect(x,y,100,100,paint);
}
public void OTListener(){
setOnTouchListener(new OnTouchListener(){
public boolean onTouch(View DrawView, MotionEvent e){
x = 100;
y = 100;
invalidate();
return false;
}
});
}
}
Try this. It should work if it is the top view in your view hierarchy.
You'll have to check out event.getAction() if you want to do more advanced stuff in onTouchEvent()...
public class DrawView extends View {
Paint paintRect = new Paint();
Paint paintClear = new Paint();
private Point touch = new Point();
public DrawView(Context context){
super(context);
paintClear.setColor(Color.BLACK);
paintRect.setColor(Color.GREEN);
}
#Override
public void onDraw(Canvas canvas){
canvas.drawPaint(paintClear);
canvas.drawRect(touch.x-50,touch.y-50,touch.x+50,touch.y+50,paintRect);
}
private void touch(int x, int y) {
touch.set(x,y);
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
touch((int)event.getX(), (int)event.getY());
return true;
}
}
Using invalidate() in another method doesn't work. You need to use postinvalidate() if you want to refresh activity from another method.
I have been developing the application, and I need that drawingg is executed in another thread. Now my code is:
public class PainterView extends View implements DrawingListener {
//private GestureDetector detector;
private Context context;
private Painter painter;
private Bitmap background;
private Bitmap bitmap;
private Paint bitmapPaint;
private Path path;
private Paint paint;
private float x;
private float y;
private boolean isErasing=false;
private boolean isTextDrawing=false;
private ExecutorService pool;
public PainterView(Context context, Painter painter) {
super(context);
this.context = context;
this.painter = painter;
pool=Executors.newFixedThreadPool(3);
//detector = new GestureDetector(context, new GestureListener());
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(final Canvas canvas) {
if (bitmap != null) {
pool.submit(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
synchronized (PainterView.this) {
canvas.drawBitmap(background, 0, 0, bitmapPaint);
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
canvas.drawPath(path, paint);
}
}
});
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//detector.onTouchEvent(event);
x = event.getX();
y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
painter.touchStart(x, y);
break;
case MotionEvent.ACTION_MOVE:
painter.touchMove(x, y);
break;
case MotionEvent.ACTION_UP:
painter.touchUp();
break;
}
return true;
}
#Override
public void onPictureUpdate(Bitmap background, Bitmap bitmap, Paint bitmapPaint, Path path, Paint paint) {
this.background=background;
this.bitmap = bitmap;
this.bitmapPaint = bitmapPaint;
this.path = path;
this.paint = paint;
invalidate();
}
public void setPainter(Painter painter) {
this.painter = painter;
}
}
I thought that if I uses ExecutorService then the application can draw in another thread, but it doesn't work - when I draw the screen of device blinkes. So, please, tell me, how can I use multithreading for drawing using SurfaceHolder and other elements? I need to make as few as possible changes in my code.
You can only draw in the main UI thread. You should use SurfaceView, since it was made specifically to support drawing from secondary threads.
One of the purposes of this class is to provide a surface in which a
secondary thread can render into the screen. If you are going to use
it this way, you need to be aware of some threading semantics.
source
See also this video: Learn Android Tutorial 1.28- Introduction to the SurfaceView