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
Related
I have a button that I would like clickable only by a stylus.
I used the method setClickable to enable or disable the click on the button, but how can I do that is clickable only with a pen?
the button should be clickable only when MotionEvent.TOOL_TYPE_STYLUS
how do i can?
you could override the Button's onTouchListener, and return immediately it the touch event is not performed through TOOL_TYPE_STYLUS. To retrieve this information, you can use
getToolType(int pointerX)
From the documentation
Gets the tool type of a pointer for the given pointer index
if it returns TOOL_TYPE_STYLUS, then you can simply check the MotionEvent for the ACTION_DOWN/ACTION_UP, and call performClick(). E.g.
b.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
if (event.getAction() == MotionEvent.ACTION_UP ) {
performClick();
return true;
}
}
return false;
}
});
Hi i want to pass the touch event to the parent, only if the touch has moved, when the user clicks i want to handle it within the child, so i tried this within the child:
private boolean moved = false;
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN) {
super.onTouchEvent(event);
moved = false;
return false;
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
moved = true;
return false;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
return !moved;
}
return true;
}
but when i return false on ACTION_DOWN i do not get ACTION_UP
On the time ACTION_DOWN occours i do not know if i will handle it or not
According to this official Android developer site link (Read Capturing touch events for a single view section)
Beware of creating a listener that returns false for the
ACTION_DOWN event. If you do this, the listener will not be called
for the subsequent ACTION_MOVE and ACTION_UP string of events.
This is because ACTION_DOWN is the starting point for all touch
events.
"If you return true from an ACTION_DOWN event you are interested in the rest of the events in that gesture. A "gesture" in this case means all events until the final ACTION_UP or ACTION_CANCEL. Returning false from an ACTION_DOWN means you do not want the event and other views will have the opportunity to handle it. If you have overlapping views this can be a sibling view. If not it will bubble up to the parent."
- What is meaning of boolean value returned from an event-handling method in Android
When you return false you don't consume touch event and it is passed to the parent (and as you've found out by experiment you can't proceed on that gesture), if you return true - you take responsibility of processing.
So try this
private boolean moved = false;
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// CALL YOUR PARENT onTouch() IF YOU NEED TO
moved = false;
}
else if (event.getAction() == MotionEvent.ACTION_MOVE)
moved = true;
else if (event.getAction() == MotionEvent.ACTION_UP)
return !moved;
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);
}
I have a custom listview in my android application. When a user press an item in the list I want to change the background color of the pressed item. This is the code for that behaviour:
tempView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
isDown = false;
tempView.setBackgroundColor(Color.parseColor("#f47920"));
}
if (event.getAction() == MotionEvent.ACTION_UP) {
tempView.setBackgroundResource(R.drawable.list_selector_focused);
}
if(event.getAction() == MotionEvent.ACTION_MOVE) {
tempView.setBackgroundResource(R.drawable.list_selector_focused);
}
return false;
}
});
But when I "Fling" my finger over the screen to scroll the listview, an item is also marked, and the "pressed" color will be static. How can I avoid this?
MotionEvent.ACTION_UP will not be caught unless you return true from onTouch() to inform Android system that you handled the whole touch event.
I have the following code which creates an ImageButton and plays a sound when clicked:
ImageButton SoundButton1 = (ImageButton)findViewById(R.id.sound1);
SoundButton1.setImageResource(R.drawable.my_button);
SoundButton1.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ) {
mSoundManager.playSound(1);
return true;
}
return false;
}
});
The problem is that I want the image on the ImageButton to change when you press it. The OnTouchListener appears to be overriding the touch and not allowing the images to change. As soon as I remove the OnTouchListener, the ImageButton swaps to a different image when pressed. Any ideas on how I can have the images change on the ImageButton while still using the OnTouchListener? Thank you very much!
SoundButton1.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ) {
mSoundManager.playSound(1);
btnmode.setImageResource(R.drawable.modeitempressed);
}
elseif (event.getAction() == MotionEvent.ACTION_UP ) {
btnmode.setImageResource(R.drawable.modeitemnormal);
}
return false;
}
});
I think the solution is simple: remove the return true from the ontouchlistener. Since that blocks all further operations that respond to touch and input. Make it return false too.
This way it will allow other actions to also respond to the touch.