I've implemented onTouch for my layout to function as buttons.
It all works great besides the fact that a 2 clicks sound is made sometimes as touching the button.
I've tried to debug it but I wasn't able to understand what is the problem.
Here is the onTouch code :
button.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
Log.d(TAG, "onTouch "+event.getAction());
switch (event.getAction())
{
case MotionEvent.ACTION_HOVER_ENTER:
v.setBackgroundResource(R.color.main_menu_buttons_bg_pressed);
break;
case MotionEvent.ACTION_HOVER_EXIT:
v.setBackgroundResource(R.color.background_color);
break;
case MotionEvent.ACTION_DOWN:
v.setBackgroundResource(R.color.main_menu_buttons_bg_pressed);
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "on click");
v.performClick();
v.setBackgroundResource(R.color.background_color);
break;
default:
// empty
}
return false;
}
});
As you can see I've added log messages, which usually prints :
onTouch 0
onTouch 2
onTouch 2
onTouch 2
onTouch 2
onTouch 1
on click
so it should be ok but yet the clicks are heard twice (sometimes, can't determine exactly when it happens)
it's the expected behaviour du of v.performClick(); , when the view has also an OnClikListener: From GrepCode
2480 public boolean More ...performClick() {
2481 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
2482
2483 if (mOnClickListener != null) {
2484 playSoundEffect(SoundEffectConstants.CLICK);
2485 mOnClickListener.onClick(this);
2486 return true;
2487 }
2488
2489 return false;
2490 }
Related
I did not able to set the onGenericMotionEvent on the button or any view. Means I did not get any response from onGenericMotionEvent method.
Below is my code:
<Button
android:id="#+id/btnMouse"
android:layout_width="match_parent"
android:layout_height="match_parent" />
my Java file coding:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_remote_controls);
btn1 = (Button) findViewById(R.id.btnMouse);
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
int pointerCount = event.getPointerCount();
switch (event.getAction() & event.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
Log.e("Mouse: ", "Right Click");
return true;
case MotionEvent.ACTION_DOWN:
Log.w("Mouse: ", "Left Click");
return true;
case MotionEvent.ACTION_HOVER_MOVE:
if (pointerCount == 1) {
Log.e("Mouse: ", "Move");
} else if (pointerCount == 2) {
Log.e("Mouse: ", "Scroll");
}
return true;
}
return false;
}
and when i use setOnTouchListener on button it works perfect, but i unable to get the MotionEvent.ACTION_HOVER_MOVE on my button, When i read documents it specify that setOnTouchListener can not handle MotionEvent.ACTION_HOVER_MOVE so that's why i want to use the onGenericMotionEvent on my button to get MotionEvent.ACTION_HOVER_MOVE action.
or any other way to implements MotionEvent.ACTION_HOVER_MOVE on the button?
But i don't know how can do that, please help
EDITED
By Android Button, I want to simulate the real mouse, Means when user dragged over it than i want to move my laptop mouse.
When i use MotionEvent.ACTION_MOVE: it works and it move the my laptop mouse, but before my mouse move it change the location of laptop mouse pointer where it is click on button, so ignoring that Android provide ACTION_HOVER_MOVE it is not perform ACTION_DOWN unlike ACTION_MOVE
Hey as I got your problem you want a hover effect to work on button when you touch on it.
You can use the code below just pass instance of your Button in this method and also customise colors for hover effects:
public void buttonEffect(View button){
button.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(Color.parseColor("#00BFFF"),PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
break;
}
case MotionEvent.ACTION_CANCEL:{
v.getBackground().clearColorFilter();
v.invalidate();
break;
}
}
return false;
}
});
}
Hope this help you...!!!
As per android MotionEvent documents: A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP). The motion contains the most recent point, as well as any intermediate points since the last down or move event.
ACTION_MOVE Android doc
so when i apply a setOnTouchListene on my view is perfectly works, It give me ACTION_DOWN, ACTION_UP, and ACTION_MOVE
but my problem is i just want to ignore a ACTION_DOWN events exactly before ACTION_MOVE. Because ACTION_MOVE event occur only after the ACTION_DOWN event as per its documents.
my coding:
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.e("Mouse: ", "Click");
break;
case MotionEvent.ACTION_MOVE:
Log.e("Mouse: ", "Move");
break;
}
return false;
}
});
So, there is any why to ignore ACTION_DOWN event. Because user only want to move not want to click, and ACTION_MOVE is also occur ACTION_DOWN before it execute it self.
Thanks...
According to your comment - you can play with counter. For example:
private static int counter = 0;
...
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
Log.e("Mouse: ", "Click");
break;
case MotionEvent.ACTION_MOVE:
counter++; //check how long the button is pressed
if(counter>10){
Log.e("Mouse: ", "Move");
}
break;
case MotionEvent.ACTION_UP:
if(counter<10){
//this is just onClick, handle it(10 is example, try different numbers)
}else{
//it's a move
}
counter = 0;
break;
}
return false;
}
});
I want to get activity or any control element's touch counts.
Like Android 4.2 on nexus Developer options Enable while touching 7 times.
What is the suitable event to handle it ?
You are getting 2 count's because the touch event are called every time a touch event is snet, like tump down and tump up (for example)
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
//add here the counter if you want when screen pressed
break;
case MotionEvent.ACTION_UP:
//add here the counter if you want when touch released
break;
default:
return super.onTouchEvent(event);
}
}
You can use a View.OnTouchListener, overriding the onTouch method :
#Override
public boolean onTouch(final View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// increment counter
break;
}
}
I've got a custom view which acts like a button. I want to change the background when user press it, revert the background to original when user moves the finger outside or release it and I also want to handle onClick/onLongClick events. The problem is that onTouch requires me to return true for ACTION_DOWN or it won't send me the ACTION_UP event. But if I return true the onClick listener won't work.
I thought I solved it by returning false in onTouch and registering onClick - it somehow worked, but was kinda against the docs. I've just received a message from an user telling me that he's not able to long-click on the button, so I'm wondering what's wrong here.
Part of the current code:
public boolean onTouch(View v, MotionEvent evt)
{
switch (evt.getAction())
{
case MotionEvent.ACTION_DOWN:
{
setSelection(true); // it just change the background
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
{
setSelection(false); // it just change the background
break;
}
}
return false;
}
public void onClick(View v)
{
// some other code here
}
public boolean onLongClick(View view)
{
// just showing a Toast here
return false;
}
// somewhere else in code
setOnTouchListener(this);
setOnClickListener(this);
setOnLongClickListener(this);
How do I make them work together correctly?
Thanks in advance
onClick & onLongClick is actually dispatched from View.onTouchEvent.
if you override View.onTouchEvent or set some specific View.OnTouchListener via setOnTouchListener,
you must care for that.
so your code should be something like:
public boolean onTouch(View v, MotionEvent evt)
{
// to dispatch click / long click event,
// you must pass the event to it's default callback View.onTouchEvent
boolean defaultResult = v.onTouchEvent(evt);
switch (evt.getAction())
{
case MotionEvent.ACTION_DOWN:
{
setSelection(true); // just changing the background
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
{
setSelection(false); // just changing the background
break;
}
default:
return defaultResult;
}
// if you reach here, you have consumed the event
return true;
}
I'm trying to create a custom GridView but i'm having troubles with the touch listeners.
What i want to do:
Create a GridView with custom Views.
Longpress on an item so it becomes 'editable'.
Drag the view horizontal or vertical to move it's position in the GridView.
Here's where i'm having trouble:
I'm implementing GestureDetector.OnGestureListener for the longpress functions, because for some reason using the gridview.setOnItemLongClickListener() isn't working when overriding the onTouchEvent() of the GridView itself (Which i need for the dragging part). So everything is fine at this point. Now i only need to know when the longpress is finished. So i though: "Well this shouldn't be hard." I couldn't have be more wrong. I've fiddled around for quite some time with this and it looks like using different touch events isn't helping me :/
When stepping through the onTouchEvent() i noticed that only 1 action is given: MotionEvent.ACTION_DOWN. So what am i doing wrong? i need the MotionEvent.ACTION_UP...
Found the culprit:
i was doing something like this
#Override
public boolean onTouchEvent(MotionEvent event) {
// Give everything to the gesture detector
boolean retValue = gestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE :
onMove();
break;
case MotionEvent.ACTION_UP :
onUp();
break;
case MotionEvent.ACTION_CANCEL:
onCancel();
break;
}
return retValue;
}
i think retValue was always returning false so no other events were triggered.
this fixed the issue:
#Override
public boolean onTouchEvent(MotionEvent event) {
// Give everything to the gesture detector
gestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE :
onMove();
break;
case MotionEvent.ACTION_UP :
onUp();
break;
case MotionEvent.ACTION_CANCEL:
onCancel();
break;
}
return true;
}