Click events doesn't bubble up in RecyclerView - android

I'm wondering why click events doesn't bubble up if I click inside a RecyclerView.
My scenario uses a simple RecyclerView to show some TextViews, while its parent View has an OnClickListener registered to perform some action if someone clicks into the view.
If I click on e.g. a TextView the click event bubbles properly up to the parent. But if I click onto the RecyclerView the click doesn't bubble up.
The weird thing is, that if I set an OnClickListener directly on the RecyclerView it is also never fired. I assume that is the root of all evil.
So, why does my RecyclerView don't receive any click events? Why doesn't its parent receive any click events?
Hierarchy looks like this:
- View (has an OnClickListener) <- Why no clicks?
- RecyclerView (clickable=false)
- TextView
- TextView
....
I experimented with setFocusable() and setClickable(), but without luck.
PS: My current solution sets an OnClickListener on each TextView inside the RecyclerView and uses getParent() to propagate the click to the parent view using performClick() manually.

I use the special class handler for RecyclerView, the RecyclerView.OnItemTouchListener. I can be added from the consuming class. Here is the default implementation of the handler class:
recyclerView.addOnItemTouchListener( new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
//Put your code here.
//Called 2 times per touch, on pressdown and on release.
return false; //true will disable scroll view.
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
setDefaultBottomBar();
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});

Related

Is there a way to enable RecyclerView Touch Events back?

I'm disabling RecyclerView Touch Events by:
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
return true;
}
});
When I want to enable it back I'm just changing return statement to false, I'm adding OnItemTouchListener to RecyclerView again which returns false this time, like I've found on Stackoverflow. Unfortunately after doing this I can't swipe recycler items or scroll RecyclerView. How to enable Touch Events back?

Combine onTouch onClick and onLongClick listeners

I have a recyclerview with items inside, I would like to distinguish between swipe (I am moving the element horizontaly making some action and setting it back to its original place) singleTouch and longClick, what is the best Practice of achieving it?
I seen a lot of implementations here, but none that work\super messy(and also dont work properly), if i implement custom gestureDetector and switchcase inside it works but it takes the phone about a second to react, if i implement onTouch in only catches onTouch, if I dont the onClick and onLong work but not the swipe
currently only the swipe works:
item.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
logd("TAG","2");
return false;
}
});
}
item.setOnClickListener(v -> {
logd("TAG","1");
});
item.setOnLongClickListener(v -> {
logd("TAG","2");
});
any advice would be appreciated,
Thanks

Android - Drag and Drop Between 2 Activities

Let's say:
Activity1 contains some items which will be dragged
Activity2 contains some "boxes" which will be filled with Activity1's item. The boxes already have drag listener.
I want to drag item from Activity1 into Activity2
I tried these method:
I implement onLongClickListener() on Activity1 items and use startDrag() there. Then I open Activity2. I could make the drag shadow appear but the boxes cannot receive the item. In fact, they doesn't respond to any DragEvent.
I implement onLongClickListener() on Activity1 items, but only to pass the data into Activity2. Then I use startDrag() when Activity2 start(specifically in onResume()). Here, the shadow not appear and the boxes doesn't respond to any DragEvent.
Is there any way to make this possible?
its possible using two fragment of view pager instead of 2 activity and you can set logic of drag and drop in onTouch() or dispatchTouch().
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
using dispatchTouch() in activity of fragment or
viewPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
using touch event of view pager you can set drag and drop logic within inside.
I hope this idea can help you.

Programmatically generated views

I'm adding a view at the top of the current view programmatically by inflating it from an XML.
The problem is that after the view is added and showed, I'm still able to press button from the underlying view. How can I prevent this?
Your new view needs to handle the touch event instead. Just create a new, empty touch listener for this purpose:
myTopView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;//true to specify that the event was consumed by the top view
}
});
Try to set an empty click listener for the view at the top.
For example:
myTopView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// empty, just to consume the event.
}
});
It will do nothing except to consume the event and not let pass it to underlying view.

OnTouchEvent not working on child views

I have a Linear Layout that has a Button and a TextView on it. I have written a OnTouchEvent for the activity. The code works fine if I touch on the screen, but if I touch the button the code does not work. What is the possible solution for this?
public boolean onTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction)
{
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
}
return true;
}
The problem is the order of operations for how Android handles touch events. Each touch event follows the pattern of (simplified example):
Activity.dispatchTouchEvent()
ViewGroup.dispatchTouchEvent()
View.dispatchTouchEvent()
View.onTouchEvent()
ViewGroup.onTouchEvent()
Activity.onTouchEvent()
But events only follow the chain until they are consumed (meaning somebody returns true from onTouchEvent() or a listener). In the case where you just touch somewhere on the screen, nobody is interested in the event, so it flows all the way down to your code. However, in the case of a button (or other clickable View) it consumes the touch event because it is interested in it, so the flow stops at Line 4.
If you want to monitor all touches that go into your Activity, you need to override dispatchTouchEvent() since that what always gets called first, onTouchEvent() for an Activity gets called last, and only if nobody else captured the event. Be careful to not consume events here, though, or the child views will never get them and your buttons won't be clickable.
public boolean dispatchTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction) {
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
Another option would be to put your touch handling code into a custom ViewGroup (like LinearLayout) and use its onInterceptTouchEvent() method to allow the parent view to steal away and handle touch events when necessary. Be careful though, as this interaction is one that cannot be undone until a new touch event begins (once you steal one event, you steal them all).
HTH
Let me add one more comment to this excellent post by #Devunwired.
If you've also set an onTouchListener on your View, then its onTouch() method will be called AFTER the dispatch methods, but BEFORE any onTouchEvent() method, i.e. in between no.3 and no.4 on #Devunwired's answer.
Try to set the descendantFocusability attribute of your layout to blocksDescendants
Activity::onTouchEvent will be called only when non of the views in the Activity WIndow consumes/handles the event. If you touch the Button, the Button will consume the events, so the Activity won't be able to handle it.
Check out following articles for more about Android Touch Event handling pipeline.
http://pierrchen.blogspot.jp/2014/03/pipeline-of-android-touch-event-handling.html
you can also try onUserInteraction():
#Override
public void onUserInteraction(){
//your code here
super.onUserInteraction();
}
works well for me!
RecyclerView list_view = findViewById(R.id.list_view);
list_view.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener(){
#Override
public boolean onInterceptTouchEvent(#NonNull RecyclerView rv, #NonNull MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
Log.i("Hello", "World");
return false;
}
});
use public boolean dispatchTouchEvent(MotionEvent event) instead on onTouchEvent()

Categories

Resources