I am writing a simple code on ontouchevent..the code is
class MyTouchListener implements View.OnTouchListener{
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction()==MotionEvent.ACTION_DOWN)
{ Log.i(TAG, "^^^^^^^^^^^ACTION DOWN^^^^^^^^^^^^");
}
else if(event.getAction()==MotionEvent.ACTION_UP)
{
Log.i(TAG, "^^^^^^^^^^^ACTION UP^^^^^^^^^^^^");
}
}
while i pressed the screen it prints ^^^^^ACTION DOWN^^^^^
But when I released the screen it does not print ^^^^^^ACTION UP^^^^^^....
means MotionEvent.ACTION_UP fails..why this is so??
Try with MotionEvent.ACTION_CANCEL
#Override
public boolean onTouch(final View view, final MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
setColorFilter(Color.argb(155, 185, 185, 185));
}
else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
setColorFilter(Color.argb(0, 185, 185, 185));
}
return false;
}
or add a log in your ontouch method
Log.d("tag", "motionEvent=" + motionEvent);
well ACTION_DOWN is happening just once after that action move should be happening and in the and action up...
but there is one problem , for example if you have a touchable area of 48dip x 48dip and if you touch that area and move you finger away (while dragging) I mean you press and you drag you finger away from the touchable area than action up will not happen !!!
Action up will happen only in case when you take your finer of the screen but you are still in the touchable area. I hope you understand me what I am trying to say.
if you want mouse up to happen that touch the touchable area do not drag you finger away and take you finger away from the screen, you know just like taping then the up event will happen
Related
OnTouchEvent is being fired after the second time touch; yet, I want it to be fired after the first touch itself.
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
//too avoid touch being detected continuously
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (Function.system[5] == "Gravity: on") {
//some action...
}
}
return super.onTouchEvent(event)
}
You need to tell Android to continue to respond to touch events. Returning true let's you capture events from action down , action move and then action up.
Please add the return true for each event
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
//too avoid touch being detected continuously
if (event.getAction() == MotionEvent.ACTION_DOWN) {
}
return true;
}
Please try and seee if this works for you
I have a button that types something in edit text and I am using on touch listener to do so when I press for audio to get played when left number gets typed.
zero.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
sp.play(soundIdShot1, 1, 1, 0, 0, 1f);
rect = new Rect(zero.getLeft(), zero.getTop(), zero.getRight(), zero.getBottom());
}
if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
if(!rect.contains(zero.getLeft() + (int) motionEvent.getX(), zero.getTop() + (int) motionEvent.getY())){
}
} if(motionEvent.getAction() == MotionEvent.ACTION_UP){
number.append("0");
}
So, what I want to do is when I press, a sound is made and when I remove my finger the number gets typed in edit text field and when I move my finger outside the button's region with swipe nothing happens and nothing gets typed so as you get from the code I made it work with action down and action up but I can't figure it out with action move and how to make it work as I want
I'm animating a View that shows if i slide up, and hide if i slide down.
The problem is that only work when sliding up. If i slide down, the view move along with my finger but when i release the touch, it goes up again.
Here is the code that i use for the animation & slide.
v.setY(480);
v.setVisibility(View.VISIBLE);
v.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN){
v.animate().translationY(480);
return true;
} else if (action == MotionEvent.ACTION_UP) {
v.animate().translationY(0);
return true;
}
return true;
}
});
What am i missing?
ACTION_UP and ACTION_DOWN don't mean direction.
ACTION_DOWN means an event when you have just touched the screen.
ACTION_UP means an event when you have just released your finger.
Here is my very standard button onTouchListener:
b.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
b.setPressed(true);
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
b.setPressed(false);
// Do the button action stuff here
}
return true;
}
});
When the user presses down on the button I set the button to "pressed". When the user lifts the finger I set the button to "not pressed" and then do the stuff the button is supposed to do.
This is all great except for the case where the user presses the button and then, while continuing to keep the finger down, moves the finger outside of the button area. When the finger is lifted the ACTION_UP stuff runs anyway. I would like for this behavior to act as a "cancel" of the button press. So, as soon as the pressed finger moves outside the button area I'd like to b.setPressed(false); and then NOT do the button action stuff when the finger is raised.
I've tried using MotionEvent.ACTION_CANCEL and MotionEvent.ACTION_OUTSIDE (as suggested by How to detect when finger slides off the ImageButton?) but I must be missing something because they're not working.
From Detect when a user moves off of a button in Android it would appear that this can be done with event.getX() and event.getY(). If getX() is negative you're off the left and if getY() is negative you're off the top, but to figure out if you're off the right or bottom I'll have to figure out the size of the button and then... there has to be a simpler way. Is there?
You had the right answer. Use getWidth() and getHeight() to get the width and height and check if x or y is greater.
ACTION_CANCEL doesn't work because CANCEL is generated when a parent view takes control of the touch events, like a ListView does when scrolling.
ACTION_OUTSIDE only happens in some unusual cases where you request it. It isn't going to be generated for just a normal MOVE or UP.
Since no one posted any code, here is one. A Boolean is used to indicate when the respective actions should be performed.
The MotionEvent.ACTION_MOVE event is handled to check if the finger is moved out of the bounds. If yes, b.setPressed(false); is called and the boolean is used to indicate that MotionEvent.ACTION_UP shouldn't be fired the next time, ie to cancel the button click.
And in MotionEvent.ACTION_UP, call b.setPressed(false); only if our boolean doesn't indicate a skip (as mentioned above). And if it does, invert the boolean so that button action stuff would execute the next time.
private Boolean notNow = false;
private Rect rect; // Variable rect to hold the bounds of the view
b.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN){
b.setPressed(true);
rect = new Rect(v.Left, v.Top, v.Right, v.Bottom);
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP){
if (!notNow){
b.setPressed(false);
}
else //button press canceled
notNow = false;
}
if((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE){
if(!notNow)
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
// finger moved out of bounds
b.setPressed(false);
notNow = true; //cancel button press the next time
}
}
return true;
});
I am having this problem where ACTION_CANCEL is not triggered, I have implemented it in my other project and it's working fine. It seems that ACTION_UP is the only MotionEvent that is called after ACTION_DOWN. I wanted to trigger ACTION_CANCEL once my finger is not anymore in the view or outside the screen.
Sample scenario: I click on the view which is a LinearLayout btw, on ACTION_DOWN its background is changed to a "clicked/dimmed" version of the image and when ACTION_UP is triggered its background changes back to the default image only if the finger is within the LinearLayout. Now the problem is when I press it and kept my finger on the screen, and drag my finger outside the LinearLayout, ACTION_UP is still triggered where it shouldn't have.
Here's my code:
dimView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(final View view,
final MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("TAG", "DOWN");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
Log.d("TAG", "UP");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
Log.d("TAG", "CANCEL");
return true;
}
return false;
}
});
where: dimView is a LinearLayout
I've been debugging this for a really long time and it bothered me a lot since this came up very randomly. I then tested my code on different devices and realized the API implementation changed with Android 4.2.
The expected behaviour and code work absolutely fine with Android 4.1.2 (tested on Galaxy Tab 2) but the bug you describe can be seen on a Nexus 7 (Android 4.2).
Apparently Android changed the way MotionEvents are handled in API 17.
One particular case when the bug does not occur is when the view is located in a GroupLayout under a ScrollView. When scrolling is possible the ACTION_CANCEL gets fired. However when no scrolling is possible the bug persists.
At first I tried combining an OnClickListener and OnTouchListener so that the last can handle just the animations but to no avail. Dispatching the Events from parents also doesn't work.
One workaround is to capture ACTION_MOVE events and check if the finger is located outside of the view's boundaries using v.getX() and v.getY() and comparing them to event.getX() and event.getY() respectably. A global boolean variable (isOutside) can be used to store the most current information. Before firing up the ACTION_UP you can check the latest state of isOutside and perform your animations and action accordingly. You can also return true or false depending on whether you captured the event or not.
Update: After digging a bit here i found this solution:
Android: Detect if user touches and drags out of button region? and compiled this code. The idea is the same except that it creates a rectangle and checks if the event boundaries are within the rectangle of the view.
someView.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG,"Touched: "+event.getAction());
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG,"ACTION_DOWN");
animateImageButtonOnClick(v, event);
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
}
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d(TAG,"ACTION_UP");
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
Log.d(TAG,"ACTION_UP - outside");
animateImageButtonOnRelease(v, event);
} else {
Log.d(TAG,"ACTION_UP - inside");
// do your stuff here
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE){
if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
animateImageButtonOnReleaseWithLowDuration(v, event);
}
}
if (event.getAction() == MotionEvent.ACTION_CANCEL){
Log.d(TAG,"ACTION_CANCEL");
animateImageButtonOnRelease(v, event);
return true;
}
return true;
}
});
Override dispatchTouchEvent method maybe deal with it;
dimView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
// to call super touch method
return false;
}
});
#Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
// TODO Auto-generated method stub
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("TAG", "DOWN");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
Log.d("TAG", "UP");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
Log.d("TAG", "CANCEL");
return true;
}
return super.dispatchTouchEvent(motionEvent);
}