I am trying to slide up a layout in android using touch listener. I am expecting the MOTION_UP should be intercepted when the user touches the screen and drags the finger up the screen. And MOTION_DOWN the other way. But when i debug, both Up and Down are called.
I am trying to slide the layout up when I drag up using animation. I don't understand what i am doing wrong. Did anyone had this situation before? Any hints are helpful, Thank you.
This is my code:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MainActivity extends Activity implements AnimationListener,
OnDragListener {
// Animation
private Animation animSlideUp;
private ImageView img;
private Rect rect;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.interstitialImg);
img.setOnDragListener(this);
img.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
System.out.println("up");
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v
.getBottom());
v.getHitRect(rect);
if (rect.contains(Math.round(v.getX() + event.getX()),
Math.round(v.getY() + event.getY()))) {
System.out.println("inside");
// Animation slide_up = AnimationUtils.loadAnimation(
// getApplicationContext(), R.anim.slide_up);
// img.startAnimation(slide_up);
} else {
// outside
System.out.println("outside");
}
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("down");
// Construct a rect of the view's bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v
.getBottom());
return true;
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
// if (!rect.contains(v.getLeft() + (int) event.getX(),
// v.getTop() + (int) event.getY())) {
// // User moved outside bounds
// System.out.println("moved outside bounds " + rect);
// }
}
return true;
}
});
}
@Override
public void onAnimationEnd(Animation animation) {
// check for zoom in animation
if (animation == animSlideUp) {
System.out.println("animation: " + animation);
overridePendingTransition(R.anim.slide_up, R.anim.slide_up);
finish();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@SuppressLint("NewApi")
@Override
public boolean onDrag(View v, DragEvent e) {
if (e.getAction() == DragEvent.ACTION_DROP) {
System.out.println("action drop");
View view = (View) e.getLocalState();
ViewGroup from = (ViewGroup) view.getParent();
from.removeView(view);
RelativeLayout to = (RelativeLayout) v;
to.addView(view);
view.setVisibility(View.VISIBLE);
}
return true;
}
@Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.slide_up, R.anim.slide_up);
}
}
I am expecting the MOTION_UP should be intercepted when the user touches the screen and drags the finger up the screen.
Uh, no.
Docs to the rescue:
public static final int ACTION_DOWN A pressed gesture has started, the motion contains the initial starting location.
Think of ACTION_DOWN as the very start of user interaction. DOWN
DOES NOT INDICATE DIRECTION. In a crude sense, it tells you that the user has put his/her finger(s) down on the screen.
Similarly:
public static final int ACTION_UP A pressed gesture has finished, the motion contains the final release location as well as any intermediate points since the last down or move event.
Again, UP
is not what you're assuming it to be. It means that the user has lifted his/her finger(s) off the screen.
Let's look at your code now:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v
.getBottom());
v.getHitRect(rect);
if (rect.contains(Math.round(v.getX() + event.getX()),
Math.round(v.getY() + event.getY()))) {
System.out.println("inside");
// Animation slide_up = AnimationUtils.loadAnimation(
// getApplicationContext(), R.anim.slide_up);
// img.startAnimation(slide_up);
} else {
// outside
System.out.println("outside");
}
First, getHitRect(Rect)
fills the rect
you supply as an argument. So, initializing it with v.getLeft(), v.getTop(), v.getRight(), v.getBottom()
is not required.
Second, since you are setting an OnTouchListener
on img
, why do you need to check if event.getX()
and event.getY()
are inside the view's bounds? In fact, you don't. Because, onTouch(...)
will not be triggered if the user touches outside.
Third, you may not need to implement an OnTouchListener
to do what you want.. or at least, not in the way you currently are. For example, if all you are looking for is if the user has flinged
the view UP or DOWN, you can rely on a SimpleOnGestureListener
. The accepted answer on this question will show you how to use it: Android: How to handle right to left swipe gestures.
So what exactly are these ACTION_DOWN and ACTION_UP events used for? Well, you work with them when you need finer control: like reacting to user input immediately. For example, you cannot even afford the basic functionality of moving a view around the screen using a SimpleOnGestureListener
.