getting wrong x y from OnTouchListener - android

I'm trying to draw a circle where I touch so I'm using the OnTouchListener to get the x,y coordinates.
But when I run the code on the emulator the circle is not drawn where I clicked.
public class MainActivity extends AppCompatActivity {
Canvas canvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//------------------
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
int screenWidth = displaymetrics.widthPixels;//480
int screenHeight = displaymetrics.heightPixels;//1920
Bitmap bg = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bg);
RelativeLayout ll = (RelativeLayout) findViewById(R.id.RelativeLayoutCells);
ll.setBackgroundDrawable(new BitmapDrawable(bg));
ll.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float xf = event.getRawX();
float yf = event.getRawY();
Log.d("=", String.valueOf(x) + " " + String.valueOf(xf));
Paint fillpaint= new Paint();;
fillpaint.setColor(Color.RED);
fillpaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(xf, yf, 5, fillpaint);
canvas.drawCircle(x, y, 15, fillpaint);
}
Button button = (Button) findViewById(R.id.button);
button.setText("ghj");
return false;
}
});
}
}

You should not use event.getRawX(). The returned value is completly raw and not adjusted to your view. If the canvas is not scaled, use event.getX() instead. It makes a difference because of what it returns. getX returns x adjusted to custom views but getRawX is based on the screen which causes inaccuracy.

Related

Drawing a circle on ImageView2 in same coordinates as ImageView1 if i tap a place in ImageView1 and Vice versa

I'm trying to make find the difference game app, but I never made anything like that and since I'm a new to development I'm stuck
well baby Steps are always needed to learn xD
I read in some documentation that i have to get each ImageView height and width separately so when i touch imageView1 its coordinates can be set to ImageVIew2 and ViceVersa I MAYBE BE WRONG XD
Right now I have a layout with 2 Images set vertically
<RelativeLayout
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"
tools:context=".PlayActivity"
android:id="#+id/hello1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/hello">
<ImageView
android:id="#+id/image1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#drawable/pic_9" />
<ImageView
android:id="#+id/image2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#drawable/pic_9a" />
</LinearLayout>
What i want to do is if i tap a place in image1 a circle should be created on the same place in image2
after reading along a few things i have made a circle if i tap the layout but i am stuck after this i cant find what to do next maybe i cant find documentation related to my problems
public class PlayActivity extends AppCompatActivity {
RelativeLayout layout;
float x = 0;
float y = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
layout=(RelativeLayout) findViewById(R.id.hello1);
layout.addView(new CustomView(PlayActivity.this));
}
public class CustomView extends View {
Bitmap mBitmap;
Paint paint;
public CustomView(Context context) {
super(context);
mBitmap = Bitmap.createBitmap(400, 800, Bitmap.Config.ARGB_8888);
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, 50, paint);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
x = event.getX();
y = event.getY();
invalidate();
}
return false;
}
}}
Right now i think my two ImageView arent separate because when i touch between the 2 images a circle is created which shouldn't since imageView1 ends im not sure if im thinking in right direction its just my guess on how should it work for the game to work I MAYBE BE WRONG XD
I still have a long way to go, but I'm stuck here
can anyone help?
I replaced my PlayActivity code using Tejas Pandya
RelativeLayout layout;
float x = 0;
float y = 0;
ImageView ImageView1, ImageView2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
layout=(RelativeLayout) findViewById(R.id.hello1);
layout.addView(new CustomView(PlayActivity.this));
ImageView1 = (ImageView) findViewById(R.id.image1);
ImageView2 = (ImageView) findViewById(R.id.image2);
}
public class CustomView extends View {
public CustomView(Context context) {
super(context);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
x = event.getX();
y = event.getY();
invalidate();
drawCircle(R.id.image2,ImageView2,x,y);
}
return false;
}
public void drawCircle(int my_image_id, ImageView my_imageview, float x , float y){
BitmapFactory.Options myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), my_image_id,myOptions);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
Bitmap workingBitmap = Bitmap.createBitmap(bitmap);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
canvas.drawCircle(x, y, 25, paint);
my_imageview.setAdjustViewBounds(true);
my_imageview.setImageBitmap(mutableBitmap);
}
}
and i get this error
E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at android.graphics.Bitmap.createBitmap(Bitmap.java:742)
at com.example.pc.blazedifferencegame.PlayActivity$CustomView.drawCircle(PlayActivity.java:68)
at com.example.pc.blazedifferencegame.PlayActivity$CustomView.onTouchEvent(PlayActivity.java:49)
When You tape on Image . You are getting x,y coordinate in
x = event.getX();
y = event.getY();
Now you have x,y coordinate . call your drawCircle() method on both of your imageview with this same x,y coordinate.
For Drawing circle :
make one function drawCircle();
public void drawCircle(int my_image_id,Imageview my_imageview,int x ,int y){
BitmapFactory.Options myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), my_image_id,myOptions);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
//please check here . you've got your bitmap or it is null.
// if it is null,there might be some problem with decoding your resources above.
Bitmap workingBitmap = Bitmap.createBitmap(bitmap);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
canvas.drawCircle(x, y, 25, paint);
my_imageview.setAdjustViewBounds(true);
my_imageview.setImageBitmap(mutableBitmap);
}
now for
image 1 . use drawCircle(R.id.imageview1,imageview,x,y) and for
image 2 . use drawCircle(R.id.imageview2,imageview2,x,y)

mLayout.addView() works one time only

I started lately developing for android and got stuck trying to add multiple Views to a Layout. It actually works for the first touch, but after that it does nothing. The Log though keeps working and showing that the touch has been detected and shows the position of the event. I have the following code
public class MainActivity extends Activity {
private LinearLayout mLayout;
private Context con = this;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = (LinearLayout) findViewById(R.id.lLayout);
mLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mLayout.addView(createNewView(event.getX(), event.getY()));
Log.d("this ","View has been add." + event.getX()+ ", " + event.getY());
break;
}
return false;
}
});
}
private markerView createNewView(float x, float y) {
final LayoutParams lparams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
final markerView mView = new markerView(con, 150, x, y);
mView.setLayoutParams(lparams);
return mView;
}}
and
public class markerView extends View implements View.OnTouchListener{
private Paint paint = new Paint();
private int diameter;
private float X,Y;
public markerView(Context context, int dia, float dx, float dy) {
super(context);
diameter = dia;
X = dx; Y = dy;
paint.setColor(Color.GREEN);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth((float) 4.0);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.drawCircle(X, Y, diameter, paint);
canvas.restore();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}}
Try remove final tag on your final markerView mView = new markerView(con, 150, x, y);
i just found that the Views ave been created but never show up because the first one has the size of the parentLayout. so i just add the following methode and it worked. the position needs to be changed because of the RelativeLayout but thats not a problem ;)
here is the code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(2*diameter, 2*diameter);
}

How to draw smooth graphics outside of a vanilla Activity with setContentView

I have an interesting situation if someone can see what i'm doing wrong? I have a class called TrackView below. It essentially opens up a hole where you touch the screen to reveal a hidden background only at that touch point. This all works great when I call it from setContentView(new TrackView(this)). Graphics are fast and fluid. If I use the exact same TrackView class in the manner below which is started from a service(why i'm using WindowManager), graphics are drawn very poorly and slow. The structure of the view hierarchy in each case is identical. I've also tried SurfaceView and the problem did not go away.
public class OverlayTesting
{
private WindowManager wm;
private LayoutInflater li;
private RelativeLayout rl;
private View v;
private TrackView tv;
public OverlayTesting(Context context)
{
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
li = LayoutInflater.from(context);
v = li.inflate(R.layout.activity_overlay, null);
rl = (RelativeLayout) v.findViewById(R.id.relativeLayout);
tv = new TrackView(context);
rl.addView(tv);
}
public void show()
{
wm.addView(rl, new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
}
private class TrackView extends View
{
Bitmap bitmapBase;
Bitmap bitmapDefault;
Bitmap bitmapUsed;
Canvas canvasBase;
Canvas canvasDefault;
Canvas canvasUsed;
Paint paint1;
Paint paint2;
int displayHeight;
int displayWidth;
int X = -100;
int Y = -100;
public TrackView(Context context)
{
super(context);
Display display = wm.getDefaultDisplay();
Point point = new Point();
display.getSize(point);
displayWidth = point.x;
displayHeight = point.y;
// create base background
bitmapBase = Bitmap.createBitmap(displayWidth, displayHeight, Bitmap.Config.ARGB_8888);
canvasBase = new Canvas(bitmapBase);
canvasBase.drawColor(Color.WHITE);
// create overlays and masks
bitmapDefault = Bitmap.createBitmap(displayWidth, displayHeight, Bitmap.Config.ARGB_8888);
canvasDefault = new Canvas(bitmapDefault);
canvasDefault.drawColor(Color.BLACK);
bitmapUsed = Bitmap.createBitmap(displayWidth, displayHeight, Bitmap.Config.ARGB_8888);
canvasUsed = new Canvas(bitmapUsed);
// paint structures here
}
#Override
public boolean onTouchEvent(MotionEvent ev)
{
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
X = (int) ev.getX();
Y = (int) ev.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
X = (int) ev.getX();
Y = (int) ev.getY();
invalidate();
break;
}
return true;
}
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// refresh overlay with default bitmap and open new hole at XY
// refresh overlay code here
// refresh core view canvas showing only area at XY
// draw canvas code here
}
}
}

Draw and remove a bitmap icon on canvas

I am developing an app where the user can mark a damage icon on a car. The car here is basically an image and the damage icon is also an image. I am able to draw an image, where the user touches the car, using this code:
public class TestActivity extends Activity {
private Button btn_save, btn_resume;
private ImageView iv_canvas;
private Bitmap baseBitmap;
private Canvas canvas;
private Paint paint;
public Bitmap bt;
public Bitmap ct;
boolean ismove = false;
private static final int SWIPE_MIN_DISTANCE = 50;
int i = 0;
private float x = 0;
public HashMap<String, String> testholdmap = new HashMap<String, String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// The initialization of a brush, brush width is 5, color is red
paint = new Paint();
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
iv_canvas = (ImageView) findViewById(R.id.iv_canvas);
iv_canvas.setOnTouchListener(touch);
bt = BitmapFactory.decodeResource(getResources(),
R.drawable.damage_mark_r_ic);
}
private View.OnTouchListener touch = new OnTouchListener() {
// Coordinate definition finger touch
float startX;
float startY;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
// Press the user action
case MotionEvent.ACTION_DOWN:
// The first drawing initializes the memory image, specify the
// background is white
if (baseBitmap == null) {
baseBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.b_ferrari_f152_000_0000).copy(
Bitmap.Config.ARGB_8888, true);
canvas = new Canvas(baseBitmap);
}
// Recording began to touch point coordinate
startX = event.getX();
startY = event.getY();
break;
// The user's finger on the screen of mobile action
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
float stopX = event.getX();
float stopY = event.getY();
if (startX == stopX) {
canvas.drawBitmap(bt, startX, startY, paint);
// The pictures to the ImageView
iv_canvas.setImageBitmap(baseBitmap);
} else if (startX - stopX > 50 || stopX - startX > 50) {
baseBitmap = null;
}
break;
default:
break;
}
return true;
}
};
}
My problem is figuring out how to remove this icon if it already drawn. I want it to function this way: I draw a damage icon on x,y position, and if the user clicks on x,y position again, then this damage icon will be removed.
How can I achieve this?
Use this:
canvas.drawColor(0, Mode.CLEAR);
or
overlayBitmap.eraseColor(Color.TRANSPARENT);
This sets an existing Bitmap to all transparent.
My solution would be like follows :
Every time the user click on image - store the damge bounds (x,y,w,h) in list
and Draw it on the canvas
If user click again at the same damage image - remove it from list and redraw(clean canvas - Canvas.drawColor(Color.WHITE)) everything again : the car and remaining images in the list

How to draw onto an ImageView Bitmap with finger and obtain coordinates and save the drawn image

Basically i have a grid(stored as an image) like so:
What I need to do is draw on this grid with my finger(multiple strokes) and display and save this new bitmap.
Additionally, while drawing I need to obtain the coordinates of the stroke so I can calculate some data from it(The whole grid is divided into zones ).
The coordinate part was simple, which I did using Rect(), getX() and getY() viz.
int getZoneLocation(int x, int y)
{
Rect rectangle = new Rect();
amslerView.getGlobalVisibleRect(rectangle);
String coords = "Left:%d Top:%d Right:%d Bottom:%d ActionBarHeight:%d StatusBarHeight:%d";
// Zone 1 Rectangle
Log.i("Rectangle Coordinates",
String.format(coords, rectangle.left, rectangle.top, rectangle.right, rectangle.bottom, getActionBarHeight(), getStatusBarSize()));
Rect outerMostRect = new Rect(rectangle);
int xOffset = rectangle.width() / 10;
int yOffset = rectangle.height() / 10;
Log.i("Rectangle Attribs", "Width: " + xOffset + "Height: " + yOffset);
// Zone 2 Rectangle
Rect zone2Rectangle = new Rect(outerMostRect.left + xOffset, outerMostRect.top + yOffset, outerMostRect.right - xOffset, outerMostRect.bottom
- yOffset);
Log.i("Zone 2 Coordinates", "" + zone2Rectangle.left + " " + zone2Rectangle.top + " " + zone2Rectangle.right + " " + zone2Rectangle.bottom);
// Zone 3 Rectangle
Rect zone3Rectangle = new Rect(zone2Rectangle.left + xOffset, zone2Rectangle.top + yOffset, zone2Rectangle.right - xOffset,
zone2Rectangle.bottom - yOffset);
// Zone 4 Rectangle
Rect zone4Rectangle = new Rect(zone3Rectangle.left + xOffset, zone3Rectangle.top + yOffset, zone3Rectangle.right - xOffset,
zone3Rectangle.bottom - yOffset);
// Zone 5 Rectangle
Rect zone5Rectangle = new Rect(zone4Rectangle.left + xOffset, zone4Rectangle.top + yOffset, zone4Rectangle.right - xOffset,
zone4Rectangle.bottom - yOffset);
// Check from inside out for point existence
if (zone5Rectangle.contains(x, y))
{
return 5;
} else if (zone4Rectangle.contains(x, y))
{
return 4;
} else if (zone3Rectangle.contains(x, y))
{
return 3;
} else if (zone2Rectangle.contains(x, y))
{
return 2;
} else if (outerMostRect.contains(x, y))
{
return 1;
}
return -1;
}
Basically what I did was obtain the localVisibleRect from the ImageView that displays this grid and then simply call this method to obtain the data I need inside to onTouchListener.
Now the real dilemma for me is how to implement the finger drawing along with this, and what exactly to use to implement this.
So far I've looked at SurfaceView, Canvas and even GestureOverlayView(which is stupid I know).
I've also taken a look at the FingerPaint demo from the api examples, but that draws onto an empty view and I honestly have no idea on how to implement this with an ImageView.
Any suggestions would be invaluable.
you can use this class:
import android.view.View.OnTouchListener;
public class XCanvas extends ImageView implements OnTouchListener
{
private Activity context = null;
private Paint paint = null;
public XCanvas(Activity context)
{
super(context);
this.context = context;
this.paint = new Paint();
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint.setAntiAlias(true);
}
#Override
protected void onDraw(Canvas g)
{
super.onDraw(g);
//Set background
this.paint.setColor(Color.rgb(0xff, 0xff, 0xff));
g.drawRect(0, 0, this.getWidth(), this.getHeight(), this.paint);
//Paint everything here!
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction() & MotionEvent.ACTION_MASK;
switch (action)
{
case MotionEvent.ACTION_DOWN:
{
this.pointerPressed(event);
break;
}
case MotionEvent.ACTION_MOVE:
{
this.pointerDragged(event);
break;
}
case MotionEvent.ACTION_UP:
{
this.pointerReleased();
break;
}
}
return true;
}
protected void pointerPressed(MotionEvent event)
{
//you can save touch point here!
}
protected void pointerDragged(MotionEvent event)
{
//for get x ==> eveevent.getX()
//for get y ==> eveevent.getY()
this.repaint();
}
protected void pointerReleased()
{
}
public void repaint()
{
this.invalidate();
}
}
and for use class paste this code in main activity:
private XCanvas xCanvas = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//getWindow().setBackgroundDrawableResource(R.color.MapBackground);
this.xCanvas = new XCanvas(this);
this.xCanvas.repaint();
setContentView(this.xCanvas);
this.xCanvas.requestFocus();
}

Categories

Resources