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?
Related
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.
I am trying to implement a use-case where I need to scroll RecyclerView normally (Android LayoutManager scroll) when the user scrolls with a low velocity and scroll by a certain extra amount when the user scrolls above a certain velocity.
I have implemented a LinearLayoutManager as follows:
public class ScrollLayoutManager extends LinearLayoutManager {
// constructors
#Override
public void onAttachedToWindow(RecyclerView recyclerView) {
Log.d(TAG, "onAttachedToWindow");
super.onAttachedToWindow(recyclerView);
mRecyclerView = recyclerView;
mRecyclerView.addOnItemTouchListener(new ThresholdDetector());
}
private final class ThresholdDetector implements RecyclerView.OnItemTouchListener {
#Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent e) {
// some calculations
return true;
}
#Override
public void onTouchEvent(final RecyclerView view, final MotionEvent e) {
final int action = e.getActionMasked();
mVelocityTracker.addMovement(e);
if(action == MotionEvent.ACTION_MOVE) {
if (thresholdMet) {
// Custom scroll
mRecyclerView.scrollBy(calculatedAmount)
} else {
// Scroll normally as per Android LinearLayoutManager
}
}
}
}
}
If threshold is not met, I need Android to handle the scroll, otherwise I am not able to smooth scroll. I tried the following in else (when threshold is not met), but it does not quite work.
mRecyclerView.post(new Runnable() {
#Override
public void run() {
mRecyclerView.smoothScrollBy(-(int)getDeltaX(motionEvent), 0);
}
});
Without seeing the entirety of the ThresholdDetector class, it will be impossible to know for sure what the best solution is. That said, I believe the problem is that you are always returning true from onInterceptTouchEvent().
In the documentation for the return value of onInterceptTouchEvent():
Returns: true if this OnItemTouchListener wishes to begin intercepting touch events, false to continue with the current behavior and continue observing future events in the gesture.
And in the description for onTouchEvent():
Process a touch event as part of a gesture that was claimed by returning true from a previous call to onInterceptTouchEvent().
In other words, onTouchEvent() will only be invoked whenever you return true for a given event from onInterceptTouchEvent(). If you want the RecyclerView to perform its default behavior, simply return false from onInterceptTouchEvent() when the scroll velocity is below your threshold.
movieListRecyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// true: consume touch event
// false: dispatch touch event
return false;
}
});
but once disabled I am not able to enable it back ,is there any way to make it work like toggle which will enable and disable RecyclerView
also recyclerview.setEnabled(false) is not working
This will work:
Use boolean variable and setting default value to false and change value on button click.
boolean touch = false;
movieListRecyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// true: consume touch event
// false: dispatch touch event
return touch;
}
});
and on your button click or whatever click change boolean value;
onClick(){
touch = !touch;
}
If you want to disable click on whole items of recyclerview then add below lines in parent view of row item.
android:clickable="false"
android:focusable="false"
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
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) {
}
});