I am using a RecyclerView inside a RecyclerView. I want to be able to scroll through both. Therefore I included this answer to my child RecyclerView, which worked... kind of. I can scroll the child, but when I stop scrolling and want to scroll the child again, I have to tap on the parent first before being able to scroll the child or the parent again. See the video. Also interesting is the fact that the parent is moved immediately like in the video. I usually have to long-press to move an item. And when I raise my finger to stop scrolling the child but continue scrolling immediately, I can scroll the child without touching the parent first. But I have to continue very fast (before the tap animation is finished). I am very confused about this behavior. Can someone fix this?
I tried to set requestDisallowInterceptTouchEvent to false too, but it didn't fix the problem.
RecyclerView.OnItemTouchListener scrollTouchListener = new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, MotionEvent e) {
int action = e.getAction();
Log.d("Output> ", "" + action);
switch (action) {
case MotionEvent.ACTION_DOWN:
recyclerView.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
recyclerView.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
@Override
public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
};
Edit
With the help of @Zain, I managed to get rid of my RecyclerView.OnItemTouchListener above. But my current situation is still buggy, as you see in the GIF below. In the beginning, I was scrolling very fast - it worked. Then I scrolled through with long breaks - worked. But when I scroll through with medium speed, you can see what happens. The parent recycler view is moving instead of scrolling the child recycler view.
I am sure that I am missing something — That's why I want to provide more of my current code.
My parent recycler view touch listener. (Code taken from @Zain)
recyclerViewParent.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
ViewGroup touchedView = (ViewGroup) recyclerViewParent.findChildViewUnder(event.getX(), event.getY());
if (touchedView != null) {
Log.d("parent>", touchedView.toString());
for (int i = 0; i < touchedView.getChildCount(); i++) {
if (touchedView.getChildAt(i) instanceof RecyclerView) {
if (BiotopesFragment.this.isViewInBounds(touchedView, (int) event.getX(), (int) event.getY())) {
touchedView.onTouchEvent(event);
return true;
}
}
}
}
return false;
}
});
private boolean isViewInBounds(View view, int x, int y) {
Rect outRect = new Rect();
int[] location = new int[2];
view.getDrawingRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect.contains(x, y);
}
In my parents RecyclerView Adapter, I set a touch listener for my child recyclerView
holder.recyclerViewChild.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent e) {
//this will disallow the touch request for parent scroll on touch of child view
Log.d("child> ", "" + view.toString());
view.getParent().getParent().getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
My parent recycler view inside a fragment
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewFreshwater" />
This is my list item used by the parent recycler view
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="280dp"
android:layout_height="156dp"
android:layout_margin="8dp"
android:clickable="true"
android:focusable="true"
app:layout_flexGrow="1"
app:cardCornerRadius="20dp"
style="?attr/materialCardViewFilledStyle">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageViewBiotopeCardview"
android:background="@drawable/shadow"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginTop="-20dp"
android:layout_marginEnd="-20dp"
android:contentDescription="@string/imageViewDescription_biotope_image"
android:scaleType="centerCrop"
android:cropToPadding="true"
android:padding="5dp"
android:elevation="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="5dp"
app:strokeColor="@color/black"
app:shapeAppearanceOverlay="@style/Theme.WaterTestTimer.CircleCorners" />
<TextView
android:id="@+id/textViewBiotopeTitle"
android:layout_width="170dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginTop="8dp"
android:text=""
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="middle"
android:textSize="20sp"
android:textAlignment="center"
app:layout_constraintEnd_toStartOf="@+id/imageViewBiotopeCardview"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.divider.MaterialDivider
android:id="@+id/biotope_divider"
app:dividerColor="?attr/customDividerColor"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
app:layout_constraintEnd_toStartOf="@+id/imageViewBiotopeCardview"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textViewBiotopeTitle" />
<TextView
android:id="@+id/textViewLastValuesDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/biotopeCardView_lastValues"
android:textAlignment="center"
android:textSize="14sp"
app:layout_constraintEnd_toStartOf="@+id/imageViewBiotopeCardview"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/biotope_divider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageViewBiotopeCardview" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
And finally the list item of the child
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="2dp"
android:clickable="true"
android:focusable="true"
app:layout_flexGrow="1"
app:cardCornerRadius="10dp"
style="?attr/materialCardViewFilledStyle">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/backgroundTestValue"
android:background="@color/potassium"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textViewTestValueTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textSize="14sp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>