Disable onClicklistner while other touch listner is active - android

I am trying to implement UI like google keep.
In the main layout there is frame layout in which there is a FAM(Floating Actions Menu) and a blackshadow view which is visible when FAM is expanded.
What i want is that when i touch the shadow view it should Collapse the FAM. To do that i have implemented onTouchlistner on shadowview.
shadowview.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(fam.isExpanded()){
fam.collapse();
}
return false;
}
});
But what happens is that when i touch the area with MyCardGridView's card (Which open's another activity) open's another activity. Which should not happen.

You should try to use return true; instead of return false;, because as the documentation says :
Returns:
True if the listener has consumed the event, false otherwise.
Maybe the issue here is caused by return false

Related

Why RecyclerView still scrolls even after custom OnTouchListener implemented?

I know it might be a silly question but I need to know after I implement this code:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
Why the recyclerView is still scrolling when the listener returns false? Or more precisely where is the scrolling behavior processed and handled?
I know that return true means the touch event is consumed and false means the touch event should get passed to the next view in view hierarchy. In my mind (which is possibly wrong), the return type shouldn't change the view behavior. Because when you don't process the onTouchListener, it means no touch event (including scrolling behavior) is processed so the recyclerView shouldn't be scrolling no matter the return type is true or false. What is wrong in my perception? I hope I'm clear enough.
I know that return true means the touch event is consumed and false means the touch event should get passed to the next view in view hierarchy
This is not true, the correct order when a View handle a touch event is:
View.dispatchTouchEvent() will be called first
Sends event to View.OnTouchListener.onTouch() if exits
If not consumed, process View.onTouchEvent()
In your case because your return false in View.OnTouchListener.onTouch(), it means you do not consume the event, so the event will be routed to View.onTouchEvent() of RecyclerView, which explains why the RecyclerView is still scrolling.
Solution 1
Return true in View.onTouchListener.onTouch() to show that the RecyclerView will consume all touch events.
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// I will consume all touch events,
// so View.onTouchEvent() will not be called.
return true;
}
});
Solution 2
Create a sub-class that extends from RecyclerView and return false in View.onTouchEvent() to show that the RecyclerView don't show interested in any touch event.
public class MyRecyclerView extends RecyclerView {
public MyRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent e) {
// I don't show interested in any touch event.
return false;
}
}
This is a great presentation about Android Touch System, you should take a look.

Pass touch event to Parent View's onTouchListener in Android

I have a list view whose item is a linearlayout which has a button as it's child view. I want the ontouchLIstener of the linearlayout to work. I don't want to use onInterceptTouchEvent. Is there a way a I can pass on the touch form the button to the parent listview. I tried this
- returning true from the button's onTouchListener
private View.OnTouchListener buttonListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i(TAG, "Button On Touch");
return true;
}
};
But this does not work. It does not pass on the touch event to the linearlayout's onTouchListener.
There must be someway it should work.
The chain of events for a View group works like this - The dispatchEvent is called. Then dispatchEvent calls onInterceptTouchEvent. if it returns false, then the touch events are passed on to the children of the ViewGroup. If any of the children consume the event (in this case the button consumes the event) i.e if they return true then the motionevent is not passed on to other methods. Since the button is clickable it returns true in this case. If the onInterceptTouchEvent method returns true then the child views are not given the motion event and instead that ViewGroup's onTouchListener or onTouch method are called. Hence to pass on the touch event to the parent's (View Group) onTouchListener make sure to return true in the onInterceptTouchEvent method of the Parent (ViewGroup). You don't have to override onDispatchTouchEvent()
#Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
Log.i(TAG,"PARENT.onInterceptTouchEvent");
return true;
}
For more details about how the touch navigation is done, please see this stack post
Set your button clickable property to false, using:
button.setClickable(false);
Then in onTouch of button:
return false;
Note: This behavior is specific to button (and any other view that has clickable property set to true) that even if you return false from onTouch it will not propagate event to the parent and onClick method of the button will be called anyway.
EDIT: Another way is extending ListView class and overriding onInterceptTouch:
public class CustomListView extends ListView {
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// here you can listen for button touch events
}
}

Pass ontouchlistener to parent

I have 4 buttons in my activity and each of these buttons have a onTouchListener. I want to pass that event to the button's parent which is a Linear Layout. To achieve that, I have used
THIS :
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return true;
}
});
but it doesn't work. What could be the problem?
OnTouchListener documentation indicates that onTouch() returns
True if the listener has consumed the event, false otherwise.
So since you return true, you indicate that the touch listener of your button consumed the event, and the even doesn't get propagated any further.
Returning false instead will make the event be propagated further up the view hierarchy.
Note though, that a button which unconditionally doesn't listen to touch events isn't a button. I would make sure whether a TextView for example isn't enough.
Although this would be true and sufficient for a simple TextView (or any View for that matter), you should note that Button is a clickable view and by default behaves as such. This means that whatever you return as a result of onTouch(), the touch event won't be propagated further and the Button's onClick() method will be called.
To disable this behavior and have it behave as you expect, just make it non-clickable:
button.setClickable(false);
Again, using a button doesn't make much sense anymore though.

Android remove onInterceptTouchEvent when tapping

Hello right now I'm developing a custom view where there'll be 2 listview that the header can be stacked each other like this picture :
||
||
\/
I already succeed to create this view, by overriding overscrolled and intercept all touch and playing with the margin of the header contents. but the problem now is because I intercept all touch now I can't tap the content of the listview, I know the flow of the touch is from ACTION_DOWN -> ACTION_MOVE -> ACTION_UP, and then when I dispatch the event to the child the tap is working but the scroll isn't working at all.
So for now the flow for my view is like this onInterceptTouchEvent -> onTouch -> gestureListener (or with overscroll)
this is some part of my code
#Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return true;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
topListViewHeight = lvFirstListView.getTotalHeight() - rlFirstHeader.getHeight();
if(isBottomScrollable) {
listGestureDetector.onTouchEvent(event);
lvSecondListView.dispatchTouchEvent(event);
} else {
gestureDetector.onTouchEvent(event);
}
return true;
}
Is there anybody here have an idea about this? Any suggestion is very appreciated and if you need more question about this question please ask me.
Thanks before

Why getAction method always return ACTION_DOWN?

I am using onTouchListener for a layout. I want to take the click outside the layout. I set onTouchListetener for the layout. But motion event always shows ACTION_DOWN. Even i touchOutside the view, It is not showing ACTION_OUTSIDE. Could anyone help me to find out why it is not showing constant ACTION_OUTSIDE. Here is the code i am using
Layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("action",event.getAction()+"");
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
Toast.makeText(getApplicationContext(), "check", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
If you return false, then you're signifying that you do not wish to receive further touch events. You need to return true to continue getting motion events.
Very simple to fix by adding this:
override fun onTouchEvent(event: MotionEvent): Boolean {
return true
}
The event listener itself listens to one event action at a time. The first of course is the ACTION.DOWN, in which your toast shows.
Just like what Jason Robinson and user936414, you have to return it to true so that the object or the listener could here the second event action, ACTION.OUTSIDE.
You will get ACTION_OUTSIDE when the touch is outside the activity and the flag FLAG_WATCH_OUTSIDE_TOUCH is set. Refer http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_WATCH_OUTSIDE_TOUCH

Categories

Resources