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;
}
Related
I have
RelativeLayout
A---BIG IMAGE
B---MEDIUM IMAGE
C---SMALL IMAGE
The picture is looking like this
I have used below java code
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
return false;
}
return true;
}
Problem is that whenever I click on small (BLACK) Image
I got following output
IMG_L_A
IMG_L_B
IMG_L_C
Whenever I click on Middle Image I got
IMG_L_A
IMG_L_B
On OuterImage big image
IMG_L_A
Why I am getting it's all behind ImageView's OnTouch Method
It is working perfect with onClick but not with OnTouch
It's because the views are stacked on top of each other.
The important point here is to know the importance of the Boolean flag that you return from your onTouchListener. The boolean flag tells android if the event was consumed or not.
Suppose, you touch tblRthree, the case R.id.tblLThree executes, but then since you return false, it appears to android that the event was not consumed and this event bubbles up to the tblRTwo view which is just behind tblRthree view, which executes the same listener for the case R.id.tblLTwo but then again you return false so, it bubbles up to view tblROne and all three cases execute.
You should return true whenever you consume the event, and false when you don't.
onTouch method will be called in multiple events, all you need is to check whether it is MotionEvent.ACTION_DOWN or not.
So, it will look something like this:
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()!=MotionEvent.ACTION_DOWN)
{
return false;//we are not going to handle it
}
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
}
return true;//we have handled it
}
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 }
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;
}
}
Ok... in my app i update the layout on MotionEvent.ACTION_DOWN and then i check the motion event coordinates to locate my buttons. I can show a toast when finger is released on different buttons. The problem is i need a long touch on my buttons to call another action without conflicting with the MotionEvent.ACTION_UP. Implemented a long click handler but since i don't 'click' its not working. Hope you guys understand my problem.
Whats the best way to get my app working as intended?
My class implements OnTouchListener, OnGestureListener
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
// UPDATE LAYOUT
break;
case MotionEvent.ACTION_UP:
// GET BUTTON X Y
if (x and y match the button location){
// DO ACTION
}else{
// DO NOTHING
}
// CHANGE LAYOUT TO INITIAL STATE
break;
case MotionEvent.ACTION_MOVE:
break;
}
return false;
mybutton.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// DO STUFF
return true;
}
});
}
just try to return false in your onTouch(...) method and use onLongClickListener(...) as usual
I need to be able to tell when the user is holding a button down and when the user lets go. This is different from onClickListener and onLongClickListener. How would i go about doing something like this?
For example I press a button that starts a chronometer.(pseudo code)
if ButtonIsBeingPressed
{
chronometer start(); //and keep going
}
else chronometer stop();
//or on release or something
}
Look into the OnTouchListener it has MotionEvents for Down (press) and Up (release):
view.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Start
break;
case MotionEvent.ACTION_UP:
// End
break;
}
return false;
}
});