Search code examples
androidandroid-coordinatorlayoutbottom-sheet

Scroll coordinatorlayout when inner recyclerview is at first position and is being pulled down


I have following layout for activity.

<android.support.design.widget.CoordinatorLayout>
    <View/>
    <FrameLayout
    android:id="@+id/fragment_container"
    app:layout_behavior="@string/bottom_sheet_behavior"/>
</android.support.design.widget.CoordinatorLayout>

I have fragment containing vertical RecyclerView. This acts as container for another recyclerview scrolling horizontally. Fragment layout is:

<RelativeLayout>
<android.support.v7.widget.RecyclerView
    android:id="@+id/wall_rooms"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="@dimen/app_bar_height"
    android:background="@color/pinkDark"
    android:overScrollMode="never" />
</RelativeLayout>

When RecyclerView is showing first item at top and user scrolls down the recycler view, the coordinator layout should scroll the contents. If RecyclerView is showing other items, scrolling down should scroll the RecyclerView's contents.

I tried using setNestedScrollingEnabled = false but items in the RecyclerView do not scroll.


Solution

  • After spending lot of time on it, and trying different things, finally got it working. Extended the BottomSheetBehavior class and overridden onInterceptTouchEvent method solved it. Posting it with hope that it will help someone.

    public class MyBottomsheetBehaviour extends BottomSheetBehavior {
    
        int lastY = 0;
    
        MyBottomsheetBehaviour() {
            super();
        }
    
        @Keep
        public MyBottomsheetBehaviour(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onInterceptTouchEvent(CoordinatorLayout parent, View view, MotionEvent event) {
    
            int dy = 0;
            boolean shouldWeConsumeIt = false;
    
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                lastY = (int) event.getY();
            } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
                lastY = 0;
            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                dy = (int) event.getY() - lastY;
            }
            Log.d("Swapnil", "onInterceptTouchEvent() event Y=" + event.getY() + " x=" + event.getX() + getActionType(event.getActionMasked()) + view.getClass().getSimpleName() + "dy=" + dy);
            if (view instanceof FrameLayout) {
    
                View child = ((ViewGroup) ((FrameLayout) view).getChildAt(0)).getChildAt(0);
                LinearLayoutManager manager = (LinearLayoutManager) ((RecyclerView) child).getLayoutManager();
    
                if (manager.findFirstCompletelyVisibleItemPosition() == 0 && dy > 0) {
    
                    shouldWeConsumeIt = true;
                    int parentHeight = view.getHeight();
    
                    ViewCompat.offsetTopAndBottom(view, dy);
                } else if (manager.findFirstCompletelyVisibleItemPosition() == 0) {
                    int height = ((View) view.getParent()).getHeight();
                    int top = view.getTop();
                    if ((event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) && top < (height >> 2)) {
                        view.setTop(0);
                        setState(BottomSheetBehavior.STATE_EXPANDED);
                    } else if ((event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)) {
                        setState(BottomSheetBehavior.STATE_COLLAPSED);
                    }
                }
            }
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                lastY = (int) event.getY();
            }
            if (!shouldWeConsumeIt)
                return super.onInterceptTouchEvent(parent, view, event);
    
            return true;
        }
    
        @Override
        public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
            return super.onTouchEvent(parent, child, event);
        }
    
        private String getActionType(int eventType) {
    
            StringBuilder builder = new StringBuilder();
            if (eventType == MotionEvent.ACTION_DOWN)
                builder.append(" DOWN");
            else if ((eventType & MotionEvent.ACTION_UP) == MotionEvent.ACTION_UP)
                builder.append(" UP");
            else if ((eventType & MotionEvent.ACTION_CANCEL) == MotionEvent.ACTION_CANCEL)
                builder.append(" CANCEL");
            else if ((eventType & MotionEvent.ACTION_MOVE) == MotionEvent.ACTION_MOVE)
                builder.append(" MOVE");
    
            return builder.toString();
        }
    }