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.
Related
Here is how my set up to rotate looks.
I am listening for action down and move on the rotation icon, trying to calculate the angle of rotation and applying that angle of rotation to entire layout encapsulating the edittext. The applied rotation has to be about the center of encapsulating relative layout.
Here is how I am trying to achieve this, in the touchListener for rotation icon.
if(v == ivRotateSticker){
//TODO grab xc and yc using (top and bottom)/2 and (left and right)/2 to grab center of sticker after each rotation
final float x = event.getX();
final float y = event.getY();
rlTextStickerLayout.getGlobalVisibleRect(myViewRect);
xc = myViewRect.width()/2;
yc = myViewRect.height()/2;
dx = scaleReceiver.getWidth() - myViewRect.width();
dy = scaleReceiver.getHeight() - myViewRect.height();
leftBound = scaleReceiver.getX();
topBound = scaleReceiver.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mViewAngle = rlTextStickerLayout.getRotation();
mPrevAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
case MotionEvent.ACTION_MOVE:
Log.d("EventRegistered", " " + event.getRawX() + "--" + dx + " -- " + dy);
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
if (x >= leftBound && y >= topBound && x <= dx && y <= dy) {
float rot = (float) (mViewAngle + mCurrAngle - mPrevAngle);
rlTextStickerLayout.setRotation((float) (mViewAngle + mCurrAngle - mPrevAngle));
Log.d("stickerRotation"," "+rot);
}
break;
}
return true;
}
But the resulting rotation is glitchy and not as desired smooth. Also, if I move the sticker to a different location, how do I update the new center for rotation, as rotation after moving the sticker dramatically changes the center of rotation. How can I achieve a far more smooth rotation?
View's rotation to be animated to the specified values (90, 180, 270) in 1000ms:
view.animate().rotation(90f).setDuration(1000).start();
view.animate().rotation(180f).setDuration(1000).start();
view.animate().rotation(270f).setDuration(1000).start();
Using this library you can rotate whole view hierarchy https://github.com/rongi/rotate-layout
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.
I'm working with OpenGLES 2.0 in android. I need to move an OpenGL object with the taking the x and y axis from the touch event. But when I try to translate the object it acts weird. Same object gets displayed in two places with varying opacity.. and when the finger is lifted both the objects get disappeared.
My translation code is:
Matrix.setIdentityM(mtrxView, 0);
Matrix.translateM(mtrxView, 0, x, y, 0);
Matrix.multiplyMM(mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0);
I'm overriding onTouch() method to handle the ACTION_MOVE event:
public boolean onTouch(View v, MotionEvent ev) {
x = ev.getX();
y = ev.getY();
deltaX = x - downX;
deltaY = y - downY;
mScaleDetector.onTouchEvent(ev);
AppLog.v(TAG, "Screen xy cordinate is: " + x + " " + y + " ");
final int action = MotionEventCompat.getActionMasked(ev);
switch (action) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
if(!isZoomInProcess){
glRender.requestRender(x, y,GlSurfaceView.this);
requestRender();
}
break;
}
return true;
}
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.
I've just made a quick system that has two joysticks (one for movement, one for shooting) and they work with multitouch.
However, when you use both at the same time they interfere with each other (You slow down, turn weirdly, etc) and am wondering whether this is an issue with my phone (Nexus One, 2.3.6) or an issue with the code:
public void handleEvent(MotionEvent event) {
final int action = event.getAction();
switch(action & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN: {
pointerID = event.getPointerId(0);
int tx = (int) event.getX(event.findPointerIndex(pointerID));
int ty = (int) event.getY(event.findPointerIndex(pointerID));
boolean reset = true;
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
reset = false;
}
}
if(reset) pointerID = -1;
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
if(pointerID == -1) {
final int pointerIndex = event.getActionIndex();
pointerID = event.getPointerId(pointerIndex);
int tx = (int) event.getX(pointerIndex);
int ty = (int) event.getY(pointerIndex);
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
}
}
}
break;
}
case MotionEvent.ACTION_MOVE: {
if(pointerID != -1) {
final int pointerIndex = event.findPointerIndex(pointerID);
int tx = (int) event.getX(pointerIndex);
int ty = (int) event.getY(pointerIndex);
if(tx >= (x - radius * 2) && (tx <= (x + radius * 2))) {
if(ty >= (y - radius * 2) && (ty <= (y + radius * 2))) {
dx = (tx - x);
dy = (ty - y);
}
}
}
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = event.getActionIndex();
final int id = event.getPointerId(pointerIndex);
if(id == pointerID) {
dy = 0;
dx = 0;
pointerID = -1;
}
break;
}
case MotionEvent.ACTION_UP: {
if(-1 != pointerID) {
dy = 0;
dx = 0;
pointerID = -1;
}
break;
}
}
}
Important notes:
Each joystick is a class, and the handleEvent method is called for each joystick.
pointerID is an int belonging to each joystick
dy and dx are just the distance from the center of the joystick.
What you are missing is that if there are multiple touches happening at the same time, that one MotionEvent contains them all (and if one of the touches is of the type ACTION_MOVE, it also contains a history of that movement).
Use a loop over event.getPointerCount() (if it is >1) as indexes to get ID's for each touchpoint, which you can then use to track the touch and get the touch's x/y/other information.
Now the thing to realise is that the pointerID not only tracks the touch ... but it also can change if a touch point goes away (finishing with an ACTION_UP event); a POINTER_DOWN event will always add that touch with an ID at the end (so if you have two touches it will get the ID 2), but on a POINTER_UP (or POINTER_2_UP if it''s the second touch point), the points with a higher ID change ID by moving down.
So if you have touches with ID 0, 1 and 2, and the second touch (ID 1) goes POINTER_UP, you have to realise that pointerID 2 will change into ID 1. And if you have two touches (0 and 1), if ID 0 goes up, all of the sudden ID 1 becomes ID 0!
The trick is to keep track of this with some global variables (leftJoyStickID and rightJoyStickID) and some code in action_down and action_up. With just two touchpoints, the ternary operator is your friend:
if (IDofActionUpEvent == leftJoyStickID)
{
rightJoyStickID = IDofActionUpEvent == 0 ? 1 : 0;
}