Move, rotate and resize edittext in android - android

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.

Related

Rotate android layout view about its center using touch listener

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

Diagram gets disappeared when trying to translate

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;
}

Transfer longpress from one android view to another, without releasing finger

We have a longpress detection on a button. When detected, the view should be dismissed (back to the game view) and the object chosen with the button shall be at the coordinates of the longpress. That's the easy part, the hard part is to then change the coordinates with the finger, without releasing it.
Okay so i'm trying to reformulate this: We have two views displayed on top of eachother. What we want is a longclick detected in the top view, to then dismiss the top view, and without releasing the finger, get touchevents in the bottom view.
This is our class gameView: (this code contains a lot of code unneccesay for the problem)
#Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
translateX = event.getX() - startX;
translateY = event.getY() - startY;
gestureHandler.setTranslation(translateX, translateY);
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2)
);
if(distance > 0) {
dragged = true;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
scaleToX = event.getX();
scaleToY = event.getY();
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
int x = (int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX));
int y = (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY));
map.click(getContext(), x, y);
for(CastleTile castleTile : map.getCastleTiles()) {
if(castleTile.getRect().contains((int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX)), (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY)))){
Log.d("Castle to your service", "Boes");
castleSettings.show();
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = DRAG;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactorX != 1f && scaleFactorY != 1f && dragged) || mode == ZOOM) {
invalidate();
}
return true;
}
#Override
public boolean onLongClick(View v) {
castleSettings.dismiss();
return true;
}
And this is the gestureHandler:
public void onLongPress(MotionEvent event) {
map.longClick(context, (int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX)), (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY)));
}
Sorry for eventual lack of information or bad explaination :)

imageview does not move on touch event android

MY imageview does not move when ontouch event is called...Though I can see ACTION_UP and ACTION_MOVE happening from the log traces.
Here is my code:-
public boolean onTouch(View v, MotionEvent motion) {
float dy ;
float dx;
double r = 0;
float angle = 0;
switch(v.getId())
{
case R.id.arrow:
switch(motion.getActionMasked())
{
case MotionEvent.ACTION_MOVE:
Log.w(this.getClass().getName(),"In MOTION MOVE");
mX1 = motion.getX();
mY1 = motion.getY();
break;
case MotionEvent.ACTION_UP:
Log.w(this.getClass().getName(),"In MOTION UP");
mX2 = motion.getX();
mY2 = motion.getY();
dy = -( mY2-mY1);
dx = -(mX2-mX1);
r = Math.atan2(dy, dx);
angle = (int)Math.toDegrees(r);
updateRotation(angle);
break;
default:
break;
}
Log.d(this.getClass().getName(), "Value of angle in ontouch: " + Double.toString(angle));
break;
default:
break;
}
return true;
}
Basically I am trying to calculate the angular displacement when user touches the imageview and changes its position.
======================================
Edit:- Below is my update rotation function:-
public void updateRotation(double angle)
{
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.arrow);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
String filePath = null;
Matrix mtx = new Matrix();
Log.d(this.getClass().getName(), "Value: " + Double.toString(angle));
if(angle > 90)
angle = 90;
mtx.postRotate((float) angle);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
Drawable draw =new BitmapDrawable(bitmap);
mImageView.setBackgroundDrawable(draw);
}
=========================================================
Edit 2: Modified function
public boolean onTouch(View v, MotionEvent motion) {
float dy ;
float dx;
double r = 0;
switch(v.getId())
{
case R.id.arrow:
switch(motion.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
mX1 = motion.getX();
mY1 = motion.getY();
break;
case MotionEvent.ACTION_MOVE:
Log.w(this.getClass().getName(),"In MOTION MOVE");
mX1 = motion.getX();
mY1 = motion.getY();
break;
case MotionEvent.ACTION_UP:
Log.w(this.getClass().getName(),"In MOTION UP");
mX2 = motion.getX();
mY2 = motion.getY();
dy = -( mY2-mY1);
dx = -(mX2-mX1);
r = Math.atan2(dy, dx);
mAngle = (int)Math.toDegrees(r);
updateRotation();
break;
default:
break;
}
Log.d(this.getClass().getName(), "Value of angle in ontouch: " + Float.toString(mAngle));
break;
default:
break;
}
return true;
}
=============================================
Edit 3:- Strange thing is that if i modify my onTouch event and perform all the calculations in ACTION_MOVE the imageview responds for each touch event, but this is not what I want as I cannot do the proper angluar rotation in ACTION_MOVE event
Ruchira,
From looking at your code and working with many onTouch innovations myself, I can tell you that the problem is definitely in your onTouchEvent(). You record the mX1 and mY1 in your ACTION_MOVE without recording the original ACTION_DOWN event. This means that every time you move your finger, the onTouchEvent() method thinks that this is the original position. Try this instead:
public boolean onTouch(View v, MotionEvent motion) {
float dy ;
float dx;
double r = 0;
float angle = 0;
switch(v.getId())
{
case R.id.arrow:
switch(motion.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
mX1 = motion.getX();
mY1 = motion.getY();
break;
case MotionEvent.ACTION_MOVE:
Log.w(this.getClass().getName(),"In MOTION MOVE");
//Just to support real time rotation, you could:
mX2 = motion.getX();
mY2 = motion.getY();
//... some rotation code.
break;
case MotionEvent.ACTION_UP:
Log.w(this.getClass().getName(),"In MOTION UP");
// All of this should be fine.
mX2 = motion.getX();
mY2 = motion.getY();
dy = -( mY2-mY1);
dx = -(mX2-mX1);
r = Math.atan2(dy, dx);
angle = (int)Math.toDegrees(r);
updateRotation(angle);
break;
default:
break;
}
Log.d(this.getClass().getName(), "Value of angle in ontouch: " + Double.toString(angle));
break;
default:
break;
}
return true;
}
That should at least track your numbers correctly, so that they may actually be used.
Additional Considerations
The most common mistake is to make sure that you have not set any of your tracking variables to final. If this is the case, the code will set it once, but not again...
When dealing with Drawables, it is important to get rid of the original Drawable and its callback. The reason for this is a well known issue that was never resolved in Android because a decision couldn't be made as to when exactly it was necessary and when it wasn't. Essentially, Android will eventually run out of memory, but will not necessarily tell you and just fail to update the image. This is how you do this (when replacing an image).
Drawable trash = mImageView.getBackgroundDrawable();
if (trash != null)
{ trash.setCallback(null);
trash.recycle();
trash = null;
}
mImageView.setBackgroundDrawable(draw);
Finally, you have to let the image know that it has to redraw itself. This isn't always the case, but is true more often than not. mImageView.invalidate(); will often resolve the issue, and should be placed on the last line in your updateRotation() method.
FuzzicalLogic

Touch move gesture logic...how to determine direction of movement in 2d?

How can i determine the direction of gesture ? The use case is shown in the image link. what is the right logic for detecting in which direction the person is trying to move the ball in the circular path ? I have called the direction method in move gesture...Can someone help me fine tune this ... ?
http://www.shrenikvikam.com/wp-content/uploads/2011/04/214e422a43E11S3.png-150x134.png
private String getDirection(float firstTouchX, float finalTouchX){
if((firstTouchX - finalTouchX)>0)
return "Left";
else
return "Right";
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
// MotionEvent class constant signifying a finger-down event
case MotionEvent.ACTION_DOWN: {
Log.d("ACTION DOWN","Value ->");
final float x = event.getX();
final float y = event.getY();
initialTouchX = x;
initialTouchY = y;
break;
}
// MotionEvent class constant signifying a finger-drag event
case MotionEvent.ACTION_MOVE: {
final float x = event.getX();
final float y = event.getY();
final String direction = getDirection(initialTouchX,x);
Log.d("ACTION MOVE","diff in initial and cur value of x ->" + direction + (initialTouchX - x) + initialTouchX + "y->" + initialTouchY);
break;
}
// MotionEvent class constant signifying a finger-up event
case MotionEvent.ACTION_UP: {
Log.d("ACTION UP","Value ->");
break;
}
}
return true;
}
It seems like the slope of the line formed by the two touch points should be equal to the tangent of the circle at that point. This link has most of the math to pursue such a solution
I have used the difference between angles to the center point of the circle with good success. That may be the way to go as well.
If you are trying to determine which way to move the ball around the ciricle, it doesn't make sense for getDirection to return "Left" and "Right", it should be working with "Clockwise" and "Counterclockwise". Consider, for example, when the ball is at the 20 marker in your image: At this point every point on the circle is "Right" of where you are now...
In order to determine if the ball is moving clockwise or counterclockwise you need to consider both the x and y co-ordinates of the touch points, the x co-ordinate alone is not sufficient. You also need to know where the centre of the circle is. I would suggest in order to determine the direction of movement, you calculate the angle between the touch points and the centre of the circle.
prevTouchX = event.getHistoricalX(event.getHistorySize()-1);
currentTouchX = event.getX();
if(currentTouchX<prevTouchX){
Log.d("LEFT",event.getX()+" and "+event.getY());
}
if(currentTouchX>prevTouchX){
Log.d("RIGHT",event.getX()+" and "+event.getY());
}
Similarly for UP/DOWN
I use this code for rotating a view. It works very well. Have a look at this;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
firstX = event.getX();
firstY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
int dx =(int) (event.getX() - firstX);
int dy =(int) (event.getY() - firstY);
Log.d("Distance Rotate Touch",Integer.toString((int) (firstX-dx)));
if (signView.getRotation()<180){
if (firstX - dx > 15 && firstY - dy > 15 ){
View.setRotation(signView.getRotation()-5);
}else if(firstX - dx < -15 && firstY - dy < 15 ){
View.setRotation(signView.getRotation()+5);
}
}else {
if (firstX - dx > 10 && firstY - dy < -10 ){
View.setRotation(signView.getRotation()+5);
}else if(firstX-dx < -10 && firstY - dy < -15 ){
View.setRotation(signView.getRotation()-5);
}
}
break;
default: return true;
}

Categories

Resources