OnTouchEvent isn't sure where drawRect is - java

I have a Rect object which I draw using drawRect(Rect, Paint). I have a OnTouchEvent that checks if the touch position is inside the Rect. If the touch is inside the Rect then something on my screen changes.
The issue I'm having is: Where I have to touch to get the on touch statements to execute is around 50 pixels higher than the Rect object.
Here is the relevant parts of my code:
public class MainActivity extends Activity {
DrawView drawView;
RelativeLayout fLY;
static Rect newGame = new Rect(LEFT, 165 + 35, 320, 200 + 35);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
fLY = new RelativeLayout(this);
drawView = new DrawView(this);
fLY.addView(drawView);
setContentView(fLY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int touchX = (int)event.getX();
int touchY = (int)event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if(newGame.contains(touchX, touchY))reset();
}
}
And my DrawView class:
public class DrawView extends View{
Paint paint = new Paint();
int COLORS[] = Constants.COLORS;
int left = 250;
int size = 35;
public DrawView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawRect(MainActivity.newGame, paint);
}
}

It's probably off by exactly the height of the Status Bar. You can get the height of the status bar through this answer: Height of statusbar?
Then add that to your getY and it should work.

Related

How to draw different points with canvas in Android

I'm developing an Android application, I have to implement a function that allow me to draw different point in an activity.
This is my code:
public class MainActivity extends AppCompatActivity {
public Paint paint;
public List<Point> coords;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawingView(this));
paint = new Paint();
coords = new ArrayList();
ImageView iv = new ImageView(getApplicationContext());
iv.setImageResource(R.drawable.car);
iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
iv.setLayoutParams(parms);
}
class DrawingView extends SurfaceView {
private final SurfaceHolder surfaceHolder;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public DrawingView(Context context) {
super(context);
surfaceHolder = getHolder();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
addpoint(event.getX(), event.getY());
}
return false;
}
public void addpoint(float x, float y){
Point point = new Point();
point.x = Math.round(x);
point.y = Math.round(y);
coords.add(point);
for(int i = 0; i< coords.size(); i++) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
Everytime that I touch the screen I get and save the coordinates in a list, then I try to draw the list of point, but only one point remain on the screen, I don't understand why.
So how I can draw different point on the screen (and save it) ?
Another question: how I can show a background image ?
From the official Javadocs:
drawColor(int color) Fill the entire canvas' bitmap (restricted to the
current clip) with the specified color, using srcover porterduff mode.
So every time you draw a circle, first you clear the whole canvas with white color. So after a draw, the circle drawed before is cleared.
So one option is to save the current state of the background, and always draw it on top of the white, or try not using drawColor
for(int i = 0; i< coords.size(); i++) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
should be
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for(int i = 0; i< coords.size(); i++) {
canvas.drawCircle(coords.get(i).x, coords.get(i).y, 20, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
canvas.drawColor(Color.WHITE); Everytime ereases all the canvas and surfaceHolder.unlockCanvasAndPost(canvas); shows only the last added Circle

Trouble in drawing on Canvas (Android) in bounds

I'm making an alphabet draw app where users (normally kids) will be able to fill color in the alphabet images in the app...
I've made the app which enabled me to draw anything on the canvas using the code given below...
Main Activity:
public class MainActivity extends Activity {
SimpleDrawingView view;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
view = new SimpleDrawingView (this);
setContentView(view);
view.setBackgroundResource(R.drawable.a1);
}
}
SimpleDrawingView class which actually draws on the view:
public class SimpleDrawingView extends View
{
private final int paintColor = Color.BLACK;
// defines paint and canvas
private Paint drawPaint;
// stores next circle
private Path path = new Path();
public SimpleDrawingView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}
private void setupPaint() {
// Setup paint with color and stroke styles
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(15);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
#Override protected void onDraw(Canvas canvas) {
canvas.drawPath(path, drawPaint);
}
#Override public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(pointX, pointY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(pointX, pointY);
break;
default: return false; }
// Force a view to draw again
postInvalidate();
return true;
}
}
It let me fill in the alphabet but it draws on the whole screen/view. I want to let the user fill/draw on the alphabet only and not on the entire screen.
Can someone tell me what to do or atleast some guidelines to start it ?

onSingleTapConfirmed not giving accurate y coordinate

MainActivity class Code which uses GestureDetector to get coordinate:
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener {
DrawView drawView;
private GestureDetectorCompat g1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawView = new DrawView(this);
drawView.setBackgroundColor(Color.TRANSPARENT);
setContentView(drawView);
g1 = new GestureDetectorCompat(this,this);
g1.setOnDoubleTapListener(this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
g1.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
drawView.setXandY(e.getX(), e.getY());
Log.v("id2","message2");
return false;
}
Code which uses this coordinate:
public class DrawView extends View {
Paint paint = new Paint();
static float x_touch = -1;
static float y_touch = -1;
static int [][] arr = new int[][]{{-1,-1,-1},{-1,-1,-1},{-1,-1,-1}};
static int maxX = -1, maxY = -1;
public DrawView(Context context) {
super(context);
super.setWillNotDraw(false);
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Display mdisp = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point mdispSize = new Point();
mdisp.getSize(mdispSize);
maxX = mdispSize.x;
maxY = mdispSize.y;
canvas.drawLine(maxX/3, 0, maxX/3, maxY, paint);
canvas.drawLine(maxX*2/3, 0, maxX*2/3, maxY, paint);
canvas.drawLine(0, maxY / 3, maxX, maxY / 3, paint);//This is first Horizontal line
canvas.drawLine(0, maxY * 2 / 3, maxX, maxY * 2 / 3, paint); //This is second horizontal line
Log.v("id1", "message1");
paint.setTextSize(150f);
if (x_touch>0 && y_touch>0) {
if (x_touch < maxX/3 && y_touch < maxY/3)
canvas.drawText("X", maxX/6, maxY/6, paint);
else if (x_touch>maxX/3 && x_touch<2*maxX/3 && y_touch<maxY/3)
canvas.drawText("X", maxX/2, maxY/6, paint);
else if (x_touch>maxX*2/3 && y_touch<maxY/3)
canvas.drawText("X", 5*maxX/6, maxY/6, paint);
else if (x_touch<maxX/3 && y_touch>maxY/3 && y_touch<2*maxY/3)
canvas.drawText("X", maxX/6, maxY/2, paint);
else if (x_touch>maxX/3 && x_touch<2*maxX/3 && y_touch>maxY/3 && y_touch<2*maxY/3)
canvas.drawText("X", maxX/2, maxY/2, paint);
else if (x_touch>2*maxX/3 && y_touch>maxY/3 && y_touch<2*maxY/3)
canvas.drawText("X", 5*maxX/6, maxY/2, paint);
else if (x_touch<maxX/3 && y_touch>2*maxY/3)
canvas.drawText("X", maxX/6, 5*maxY/6, paint);
else if (x_touch>maxX/3 && x_touch<2*maxX/3 && y_touch>2*maxY/3)
canvas.drawText("X", maxX/2, 5*maxY/6, paint);
else if (x_touch>2*maxX/3 && y_touch>2*maxY/3)
canvas.drawText("X", 5*maxX/6, 5*maxY/6, paint);
Log.v("id3", "maxX="+Float.toString(maxX)+" maxY="+Float.toString(maxY)+
" x_touch="+Float.toString(x_touch)+" y_touch="+Float.toString(y_touch));
}
}
public void setXandY(float x, float y) {
x_touch = x;
y_touch = y;
this.invalidate();
}
}
Clicking just above first horizontal line prints "X" below the first horizontal line and Clicking just above second horizontal line prints "X" below the second horizontal line.
Logcat shows that clicking just above first horizontal line does give a value greater than maxY/3.
EDIT: I tried removing titlebar from the app and its accuracy improved to some extent but still not very accurate.
The problem is that you are using the MotionEvent received by the onTouchEvent of your Activity (documentation) so the coordinates you are receiving are Activity based instead of View based.
To solve your problem you can move the gesture detection to your DrawView:
public class DrawView extends View implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
private GestureDetectorCompat g1;
public DrawView(final Context context) {
super(context);
g1 = new GestureDetectorCompat(getContext(), this);
g1.setOnDoubleTapListener(this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
g1.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
setXandY(e.getX(), e.getY());
Log.v("id2","message2");
return false;
}
}
Also, to receive touch events on your DrawView don't forget to make it clickable:
drawView.setClickable(true);
Edit based on the comments:
In this example the black X represents the touch.
When you receive the MotionEvent on the onTouchEvent of the View, the coordinates you receive are View related, so you will receive (124, 187).
When you receive the MotionEvent on the onTouchEvent of the Activity, the coordinates you receive are Activity related, so you will receive (324, 487).
When you draw on the View the coordinates are View related, so if you draw the coordinates received Activity related, you will draw on the red point.

Android - custom button with shape drawables and a gradient programmatically

I want to make a custom button like this program does with perhaps a radial gradient.
I subclassed view, and draw three shape drawables and then draw the text. the text seems off center, so I tried to draw a bounding rectangle for the text, but no luck there. and was planning on adding a click listener to get button like behaviour.
perhaps I should subclass button, but where to draw my drawables so they don't get messed up by the button's text being drawn.
Any pointers will be appreciated.
thanks
Edit2: see second attempt below.
Edit3: the reason for the bounty is to figure out why subclassing drawable does not work. the gradient is not so important.
edit4: discovered drawRect before getTextBounds() in DrawableView::OnDraw().
package acme.drawables;
import android.content.*;
import android.content.pm.*;
import android.graphics.*;
import android.graphics.drawable.*;
import android.graphics.drawable.shapes.*;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.*;
import android.view.Menu;
import android.view.View;
import android.widget.*;
import static java.lang.Math.*;
public class MainActivity extends AppCompatActivity {
DrawableView drawableView;
LinearLayout row(boolean isRow1) {
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(w,d);
int m=(int)round(w*margin);
layoutParams.setMargins(m,m,m,m);
for(int i=0;i<n;i++)
layout.addView(drawableView=new DrawableView(this,i,isRow1),layoutParams);
return layout;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
DisplayMetrics metrics=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
w=d=(int)round(metrics.densityDpi);
LinearLayout row1=row(true);
LinearLayout row2=row(false);
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(row1);
layout.addView(row2);
LinearLayout l=new LinearLayout(this);
setContentView(layout);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
public class DrawableView extends View {
public DrawableView(Context context,int column,boolean isRow1) {
super(context);
setBackgroundColor(Color.TRANSPARENT);
this.column=column;
text=""+(char)('0'+column);
int r=(int)round(w*radius);
d0=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
d0.getPaint().setColor(0xff000000);
d0.setBounds(0,0,w,d);
d1=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
d1.getPaint().setColor(on[column]);
d1.setBounds(edge,edge,w-edge,d-edge);
d2=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
int b=(int)round(w*border);
d2.setBounds(b/2,b/2,w-b/2,d-b/2);
d2.getPaint().setColor(isRow1?on[column]:off[column]);
}
protected void onDraw(Canvas canvas) {
d0.draw(canvas);
d1.draw(canvas);
d2.draw(canvas);
Paint paint = new Paint();
//paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
//canvas.drawPaint(paint);
paint.setColor(Color.CYAN);
paint.setTextSize(w*95/100);
Rect r=new Rect();
paint.getTextBounds(text,0,1,r); // were switched
canvas.drawRect(r,paint); // were switched
int x=(w-r.width())/2,y=(d-r.height())/2;
paint.setColor(Color.BLACK);
canvas.drawText(text,x,d-y,paint);
}
final int column;
final String text;
ShapeDrawable d0, d1, d2;
}
final int n=5, edge=1;
double margin=.10, radius=.05, border=.15;
int w, d;
final int[] on=new int[]{0xffff0000,0xffffff00,0xff00ff00,0xff0000ff,0xffff8000};
final int[] off=new int[]{0xff800000,0xff808000,0xff008000,0xff000080,0xff804000};
}
This version tries to subclass drawable and use a button. but the button's drawing seems to interfere with drawing my drawable shapes. it looks like the bounds are being ignored.
package acme.drawables;
import android.content.*;
import android.content.pm.*;
import android.graphics.*;
import android.graphics.drawable.*;
import android.graphics.drawable.shapes.*;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.*;
import android.view.Menu;
import android.view.View;
import android.widget.*;
import static java.lang.Math.*;
public class MainActivity extends AppCompatActivity {
LinearLayout row(boolean isRow1) {
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(w,d);
int m=(int)round(w*margin);
layoutParams.setMargins(m,m,m,m);
if(true)
for(int i=0;i<n;i++) { // subclass drawable
Button b=new Button(this);
b.setText(""+(char)('0'+i));
b.setBackground(new MyDrawable(i,i/n%2==0));
layout.addView(b,layoutParams);
}
else
for(int i=0;i<n;i++) // use drawable view with canvas draw text
layout.addView(drawableView=new DrawableView(i,isRow1),layoutParams);
return layout;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
DisplayMetrics metrics=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
w=d=(int)round(metrics.densityDpi);
LinearLayout row1=row(true);
LinearLayout row2=row(false);
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(row1);
layout.addView(row2);
LinearLayout l=new LinearLayout(this);
setContentView(layout);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
public class MyDrawable extends Drawable {
public MyDrawable(int column,boolean isRow1) {
drawableView=new DrawableView(column,isRow1);
}
public void setAlpha(int alpha) {
System.out.println("ignoring set alpha to: "+alpha);
}
public void setColorFilter(ColorFilter colorFilter) {
System.out.println("ignoring set color filter to: "+colorFilter);
}
public int getOpacity() {
return PixelFormat.OPAQUE;
}
public void draw(Canvas canvas) {
System.out.println(this+" is drawing.");
drawableView.d0.draw(canvas);
System.out.println("d0 bounds: "+drawableView.d0.getBounds());
drawableView.d1.draw(canvas);
System.out.println("d1 bounds: "+drawableView.d1.getBounds());
drawableView.d2.draw(canvas);
System.out.println("d2 bounds: "+drawableView.d2.getBounds());
}
final DrawableView drawableView; // cheat by delegating
}
public class DrawableView extends View {
public DrawableView(int column,boolean isRow1) {
super(MainActivity.this);
setBackgroundColor(Color.TRANSPARENT);
this.column=column;
text=""+(char)('0'+column);
int r=(int)round(w*radius);
d0=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
d0.getPaint().setColor(0xff000000);
d0.setBounds(0,0,w,d);
d1=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
d1.getPaint().setColor(on[column]);
d1.setBounds(edge,edge,w-edge,d-edge);
d2=new ShapeDrawable(new RoundRectShape(new float[]{r,r,r,r,r,r,r,r},null,null));
int b=(int)round(w*border);
d2.setBounds(b/2,b/2,w-b/2,d-b/2);
d2.getPaint().setColor(isRow1?on[column]:off[column]);
}
protected void onDraw(Canvas canvas) {
d0.draw(canvas);
d1.draw(canvas);
d2.draw(canvas);
Paint paint=new Paint();
//paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
//canvas.drawPaint(paint);
paint.setColor(Color.CYAN);
paint.setTextSize(w*95/100);
Rect r=new Rect();
canvas.drawRect(r,paint);
paint.getTextBounds(text,0,1,r);
int x=(w-r.width())/2, y=(d-r.height())/2;
paint.setColor(Color.BLACK);
canvas.drawText(text,x,d-y,paint);
}
final int column;
final String text;
ShapeDrawable d0, d1, d2;
}
DrawableView drawableView;
final int n=5, edge=1;
double margin=.10, radius=.05, border=.15;
int w, d;
final int[] on=new int[]{0xffff0000,0xffffff00,0xff00ff00,0xff0000ff,0xffff8000};
final int[] off=new int[]{0xff800000,0xff808000,0xff008000,0xff000080,0xff804000};
}
1) Use alignment to draw text at the center in your DrawableView (should help with the text seems off center):
paint.setTextAlign(Align.CENTER); // <- should help you with centering
paint.getTextBounds(text, 0, 1, r);
int x = w / 2, y = (d - r.height()) / 2; // <- was updated too
2) To answer your question the reason for the bounty is to figure out why subclassing drawable does not work:
I suppose it's because you create DrawableView in MyDrawable and don't add it to any container which means you don't measure and layout it. So, it's probably zero height and width.
3) I would suggest you to use Button instead of custom views and drawables. You extend from Button and do additional drawings in the end of onDraw method, something like this:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// your custom drawing over button
}
Original Incorrect Answer
the reason for the bounty is to figure out why subclassing drawable does not work
Try to check if you need to call:
super.onDraw(canvas) in DrawableView.onDraw
super.draw(canvas) in MyDrawable.draw
use this code to make gradient button
Button your_button= findViewById(R.id.button);
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[] {0xFF616261,0xFF131313});
gd.setCornerRadius(0f);
your_button.setBackgroundDrawable(gd);
It is not a good idea to create Drawable depended on a View.
As Eugen Pechanec suggested, make MyDrawable and DrawableView static.
You are using ShapeDrawables only in MyDrawable, so you can move it from DrawableView.
It can be something like this:
public static class MyDrawable extends Drawable {
private ShapeDrawable d0, d1, d2;
private int edge;
private int border;
public MyDrawable(int color1, int color2, int radius, int edge, int border) {
this.edge = edge;
this.border = border;
float[] outerRadii = new float[] {
radius, radius,
radius, radius,
radius, radius,
radius, radius
};
d0 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));
d0.getPaint().setColor(0xff000000);
d1 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));
d1.getPaint().setColor(color1);
d2 = new ShapeDrawable(new RoundRectShape(outerRadii, null, null));
d2.getPaint().setColor(color2);
}
public void setAlpha(int alpha) {
System.out.println("ignoring set alpha to: " + alpha);
}
public void setColorFilter(ColorFilter colorFilter) {
System.out.println("ignoring set color filter to: " + colorFilter);
}
public int getOpacity() {
return PixelFormat.OPAQUE;
}
public void draw(Canvas canvas) {
System.out.println(this + " is drawing.");
d0.draw(canvas);
System.out.println("d0 bounds: " + d0.getBounds());
d1.draw(canvas);
System.out.println("d1 bounds: " + d1.getBounds());
d2.draw(canvas);
System.out.println("d2 bounds: " + d2.getBounds());
}
#Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
d0.setBounds(left, top, right, bottom);
d1.setBounds(left + edge, top + edge, right - edge, bottom - edge);
d2.setBounds(left + border / 2, top + border / 2,
right - border / 2, bottom - border / 2);
}
}
You can consider to not use ShapeDrawable and draw the shapes by yourself:
public static class MyDrawable extends Drawable {
private int radius;
private int edge;
private int border;
private RectF bounds1 = new RectF();
private RectF bounds2 = new RectF();
private RectF bounds3 = new RectF();
private Paint paint1 = new Paint();
private Paint paint2 = new Paint();
private Paint paint3 = new Paint();
public MyDrawable(int color1, int color2, int radius, int edge, int border) {
this.radius = radius;
this.edge = edge;
this.border = border;
float[] outerRadii = new float[] {
radius, radius,
radius, radius,
radius, radius,
radius, radius
};
paint1.setColor(0xff000000);
paint2.setColor(color1);
paint3.setColor(color2);
}
public void setAlpha(int alpha) {
System.out.println("ignoring set alpha to: " + alpha);
}
public void setColorFilter(ColorFilter colorFilter) {
System.out.println("ignoring set color filter to: " + colorFilter);
}
public int getOpacity() {
return PixelFormat.OPAQUE;
}
public void draw(Canvas canvas) {
canvas.drawRoundRect(bounds1, radius, radius, paint1);
canvas.drawRoundRect(bounds2, radius, radius, paint2);
canvas.drawRoundRect(bounds3, radius, radius, paint3);
}
#Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
bounds1.set(left, top, right, bottom);
bounds2.set(bounds1);
bounds2.inset(edge, edge);
bounds3.set(bounds1);
bounds3.inset(border / 2, border / 2);
}
}
By the way, it is good to use StateListDrawable for a Button.
So you can use MyDrawable like this:
MyDrawable drawable = new MyDrawable(...);
MyDrawable drawablePressed = new MyDrawable(...);
MyDrawable drawableFocused = new MyDrawable(...);
StateListDrawable stateDrawable = new StateListDrawable();
stateDrawable.addState(new int[]{android.R.attr.state_pressed}, drawablePressed);
stateDrawable.addState(new int[]{android.R.attr.state_focused}, drawableFocused);
stateDrawable.addState(new int[]{}, drawable);
Button button = (Button) findViewById(R.id.button);
button.setBackground(stateDrawable);

android how to draw Bitmap in random x y every 3 second in touch event

public class MyGameView extends View implements OnTouchListener{
static int x, y;
final static int radius = 25;
private int androidX;
private int androidY;
Paint paint;
Bitmap android;
boolean touch = false;
Handler handler = new Handler();
private Runnable r = new Runnable() {
#Override
public void run() {
invalidate();
}
};
private Runnable r2 = new Runnable() {
#Override
public void run() {
androidX = (int) Math.ceil(Math.random() * (MyGameView.this.getWidth()-android.getWidth()));
androidY = (int) Math.ceil(Math.random() * (MyGameView.this.getHeight()-android.getHeight()));
}
};
public MyGameView(Context context) {
super(context);
paint = new Paint();
paint.setAntiAlias(true); // smooth rendering
android = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
setFocusable(true);
setOnTouchListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
if(touch == true){
paint.setARGB(255, 222, 78, 112);
canvas.drawBitmap(android, androidX, androidY, null);
canvas.drawCircle(x,y,radius,paint);
}
handler.postDelayed(r, 1000);
handler.postDelayed(r2, 3000);
super.onDraw(canvas);
}
#Override
public boolean onTouch(View view, MotionEvent event) {
x=(int)event.getX()-(radius/2);
y=(int)event.getY()-(radius/2);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
touch = true;
break;
case MotionEvent.ACTION_UP:
touch = false;
break;
}
invalidate();
return true;
}
}
Here my code
What i want is when i hold my finger the bitmap start drawing every 3 second in random position x y.
Everything work but the problem image draw like crazy to every position and i can't figure how to do that i try calling invalidate() on ACTION_DOWN but now my circle draw every 3 second to the position i touch.
Any help is appreciate.
I'm not convinced that I totally understand what you want, but the problem with your code is the following: onDraw is called very often. In each of those calls, you run r2 with a delay of 3 seconds. So effectively, r2 is just run as often as onDraw, but the first time is delayed for 3 seconds.
What I think you want to do instead is run r2 in a separate thread and continuously update the position every 3 seconds, as in:
public class MyGameView extends View implements OnTouchListener{
static int x, y;
final static int radius = 25;
private int androidX;
private int androidY;
Paint paint;
Bitmap android;
boolean touch = false;
private Runnable r2 = new Runnable() {
#Override
public void run() {
androidX = (int) Math.ceil(Math.random() * (MyGameView.this.getWidth()-android.getWidth()));
androidY = (int) Math.ceil(Math.random() * (MyGameView.this.getHeight()-android.getHeight()));
}
};
public MyGameView(Context context) {
super(context);
paint = new Paint();
paint.setAntiAlias(true); // smooth rendering
android = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
setFocusable(true);
setOnTouchListener(this);
new Thread(r2).start(); // run r2 in a separate thread
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(touch == true){
paint.setARGB(255, 222, 78, 112);
canvas.drawBitmap(android, androidX, androidY, null);
canvas.drawCircle(x,y,radius,paint);
}
}
#Override
public boolean onTouch(View view, MotionEvent event) {
x=(int)event.getX()-(radius/2);
y=(int)event.getY()-(radius/2);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
touch = true;
break;
case MotionEvent.ACTION_UP:
touch = false;
break;
}
return true;
}
}

Categories