I'm trying to implement some kind of drag and drop on ImageView. It's working not too bad except one thing :
when I begin to drag object, there is a slight shift on ImageView and I can't resolve this problem.
For example, when I touch the view, I get on logcat :
ACTION_DOWN (margin) : 12x300
then (without moving)
ACTION_MOVE : (margin) 12x245
So the wiew is immediatly redraw and it's not very pretty !
The offset on Y axis between ACTION_DOWN and ACTION_MOVE seems to be depending on bitmap.
Here is my onTouch event code :
the layout left and top margin are set on screen.
public boolean onTouch(View v, MotionEvent event) {
FrameLayout.LayoutParams layout = (LayoutParams) v.getLayoutParams();
if (layout != null){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d( tag, "ACTION_DOWN (margin) : " + layout.leftMargin + "x" + layout.topMargin);
// finger position on current view
localX = (int) event.getX();
localY = (int) event.getY();
// initial position
parentX = (int) event.getRawX();
parentY = (int) event.getRawY();
v.bringToFront();
Log.d(tag, "ACTION_DOWN : Local " + localX + "x" + localY);
Log.d(tag, "ACTION_DOWN : Raw " + parentX + "x" + parentY);
}
else if (event.getAction() == MotionEvent.ACTION_MOVE) {
// move current view on screen
layout.leftMargin = (int) event.getRawX() - localX;
layout.topMargin = (int) event.getRawY() - localY;
Log.d(tag, "ACTION_MOVE : (margin) " + layout.leftMargin+ "x" + layout.topMargin);
v.setLayoutParams(layout);
}
}
return true;
}
Is anybody can pointed me what i am doing wrong ?
Thanks.
I had a problem, which seems a bit similar. I solved it by setting gravity on the imageView's layoutParams to Gravity.NO_GRAVITY.
Related
I am trying to get coordinates of frame layout present in my screen in android.
I tried getLocationOnScreen but it is giving me 0. How to get the right value?
int[] location = new int[2];
face_oval_layout.getLocationOnScreen(location);
Util.log("X axis is " + location[0] + "and Y axis is " + location[1]);
Above snippet called inside camera take picture callback. Value of X and Y, both are 0.
frmLayout = (FrameLayout)findViewById(R.id.frameLayout1);
frmLayout.setFocusable(true);
EditText et = new EditText(this);
frmLayout.addView(et,100,100);
frmLayout.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("TESTING","touch x,y == " + event.getX() + "," + event.getY() );
frmLayout.setPadding(Math.round(event.getX()),Math.round(event.getY()) , 0, 0);
return true;
}
});
I need to move, rotate and resize edittext based on user's touch gestures.
Here is what I am doing.
1. Listen for ACTION_DOWN event to detect single finger touch and then use that for movement.
Listen for ACTION_POINTER_DOWN, and get the index count to detect two finger touch and then use ACTION_MOVE for rotation.
I need to make resize work such that only the width gets decreased on resize by touch.
Problem I am facing
Movement is working perfectly fine. But when I apply rotation using the ACTION_POINTER_DOWN, rotation goes all sorts of haywire. Any suggestions on how to make the view movement and rotation work together?
Here is the code for touchListener I have applied
tvMain.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
moving = true;
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("ActionPointerIndex", "" + event.getActionIndex());
int index = event.getActionIndex();
moving = false;
//FOR ROTATION DETAILS
xc = tvMain.getWidth() / 2;
yc = tvMain.getHeight() / 2;
x_ = event.getX();
y_ = event.getY();
Log.d("currentAnglePD", ": " + x_ + "," + y_);
if (index == 1) {
rotate = true;
mCurrAngle = Math.toDegrees(Math.atan2(x_ - xc, yc - y_));
moving = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (moving) {
leftBound = rootView.getX();
topBound = rootView.getY();
rightBound = rootView.getX() + 1280;
bottomBound = rootView.getY() + 618;
x = event.getRawX() - tvMain.getWidth() / 2;
y = event.getRawY() - tvMain.getHeight();
dx = Float.valueOf(rootView.getWidth() - tvMain.getWidth());
dy = Float.valueOf(rootView.getHeight() - tvMain.getHeight());
bottomBound_ = tvMain.getY() + tvMain.getHeight();
rightBound_ = tvMain.getX() + tvMain.getWidth();
if (x >= leftBound && y >= topBound && x <= dx && y <= dy) {
tvMain.setX(x);
tvMain.setY(y);
}
}
if (rotate) {
Log.d("currentAngleMove", ": " + x_ + "," + y_);
mPrevAngle = mCurrAngle;
mCurrAngle = Math.toDegrees(Math.atan2(x_ - event.getX(), yc - event.getY()));
animate(mPrevAngle, mCurrAngle, 0);
System.out.println(mCurrAngle);
}
break;
case MotionEvent.ACTION_POINTER_UP:
rotate = false;
break;
case MotionEvent.ACTION_UP:
rotate = false;
moving = false;
//tvMain.clearAnimation();
break;
}
return true;
}
});
Movement is working fine, but once I move the view, rotation goes haywire, and it does not rotate along its center. Once I stop rotating, the view stops listening for any more touch gestures.
Hello i would like to ask, how can i Display Toast near the user click point Like on image below using GraphView library:
http://android-graphview.org/
Thanks for any advice
EDIT:
I tried it using
seriesSin = new GraphViewSeries("Sinus curve", new GraphViewSeries.GraphViewSeriesStyle(Color.rgb(200, 50, 00), 3), data);
// SET ON TOUCH
graphView.setOnTouchListener(new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
int size = seriesSin.size();
float screenX = event.getX();
float screenY = event.getY();
float width_x = v.getWidth();
float viewX = screenX - v.getLeft();
float viewY = screenY - v.getTop();
float percent_x = (viewX/width_x);
int pos = (int) (size*percent_x);
System.out.println("X: " + viewX + " Y: " + viewY +" Percent = " +percent_x);
System.out.println("YVal = " +seriesSin.getY(pos));
return true;
}
return false;
}
});
But I cannot to get seriesSin.size and seriesSin.getY(pos)
You can't decide where to display the Toast. However, you could set up a custom view and show it using the coordinates (x and y) you get when detecting the touch. When you show the view, simply use those values to set up the layout params of the view, and voila.
Version 4.0.0 added an onTap() listener, that replicates your onTouch method above, it doesn't solve your Toast positioning issue, but could save you a few lines of code.
I can't work out on how to stop the shadow from leaving a specific zone when being dragged.
Do you have any idea on how to do that?
Thank's in advance
OK, so I finally worked it out with only a onTouch:
#Override
public boolean onTouch(View v, MotionEvent event) {
// Handles each of the expected events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (initPosX == 0 && initPosY == 0) {
initPosX = myImage.getX();
initPosY = myImage.getY();
}
// First finger down
text.setText("ACTION_DOWN x: " + event.getRawX() + ", y: " + event.getRawY());
break;
case MotionEvent.ACTION_UP:
// Last finger to be removed
text.setText("ACTION_UP x: " + event.getRawX() + ", y: " + event.getRawY());
myImage.setX(initPosX);
myImage.setY(initPosY);
break;
case MotionEvent.ACTION_MOVE:
// A finger moves
float calc_X = event.getRawX() - initPosX / 2 + myImage.getWidth() / 2;
float calc_Y = event.getRawY() - initPosY / 2 - myImage.getHeight() / 2;
if(calc_X > initPosX - delta && calc_X < initPosX + delta)
myImage.setX(calc_X);
if(calc_Y > initPosY - delta && calc_Y < initPosY + delta)
myImage.setY(calc_Y);
text.setText("X: " + event.getRawX() + "\nY: " + event.getRawY());
break;
}
return true;
}
It's such a shame though onDragListtener is not capable of doing such a basic stuff... I guess the Android crew did it on purpose.
Special thanks to pskink.
I am trying to drag and drop a crosshair onto a MapView. I have an ImageView button on the screen. When I touch it, the button disappears and a new ImageView appears. The new ImageView is supposed to sit centered under my finger until I release it somewhere, but for some reason the offset is incorrect. The crosshair appears down-right of where I am touching.
The image does move proportionately so I believe the problem is with the offset_x and offset_y which I define in the ACTION_DOWN section. Then, in ACTION_UP I need to createMarker(x,y) on the correct coordinates under my finger, but that is offset incorrectly as well.
I have tried various ways to make it centered, and some are better than others. I have so far been unable to make it work without using magic numbers.
As it is, I am using the click location and subtracting half the picture size. This makes sense to me. It's closer to correct if I subtract the whole picture size. I have tried various examples from the web, all of them suffer from inaccuracies with the View location.
Can you give me some advice?
crosshair = (ImageView)findViewById(R.id.crosshair);
frameLayout = (FrameLayout)findViewById(R.id.mapframe);
params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
crosshairImage = BitmapFactory.decodeResource(getResources(), R.drawable.crosshair);
crosshair.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
dragStatus = START_DRAGGING;
// hide the button and grab a mobile crosshair
v.setVisibility(View.INVISIBLE);
image = new ImageView(getBaseContext());
image.setImageBitmap(crosshairImage);
// set the image offsets to center the crosshair under my touch
offset_x = (int)event.getRawX() - (int)(crosshairImage.getWidth()/2) ;
offset_y = (int)event.getRawY() - (int)(crosshairImage.getHeight()/2) ;
// set the image location on the screen using padding
image.setPadding(offset_x, offset_y, 0, 0);
// add it to the screen so it shows up
frameLayout.addView(image, params);
frameLayout.invalidate();
if(LOG_V) Log.v(TAG, "Pressed Crosshair");
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if(dragStatus == START_DRAGGING) {
dragStatus = STOP_DRAGGING;
// place a marker on this spot
makeMarker((int)event.getX() + offset_x, (int)event.getY() + offset_y);
// make the button visible again
v.setVisibility(View.VISIBLE);
// remove the mobile crosshair
frameLayout.removeView(image);
if(LOG_V) Log.v(TAG, "Dropped Crosshair");
return true;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (dragStatus == START_DRAGGING) {
// compute how far it has moved from 'start' offset
int x = (int)event.getX() + offset_x;
int y = (int)event.getY() + offset_y;
// check that it's in bounds
int w = getWindowManager().getDefaultDisplay().getWidth();
int h = getWindowManager().getDefaultDisplay().getHeight();
if(x > w)
x = w;
if(y > h)
y = h;
// set the padding to change the image loc
image.setPadding(x, y, 0 , 0);
// draw it
image.invalidate();
frameLayout.requestLayout();
if(LOG_V) Log.v(TAG, "(" + offset_x + ", " + offset_y + ")");
return true;
}
}
return false;
}
});
You have written this code within touch_Down.
offset_x = (int)event.getRawX() - (int)(crosshairImage.getWidth()/2) ;
offset_y = (int)event.getRawY() - (int)(crosshairImage.getHeight()/2) ;
// set the image location on the screen using padding
image.setPadding(offset_x, offset_y, 0, 0);
Try writing it outside the if conditions, just to make sure, it is applied to all the touch events.
You can use new api available in drag and drop
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}