Swapnil Chaudhari
Swapnil Chaudhari

Reputation: 542

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.

Upvotes: 0

Views: 666

Answers (1)

Swapnil Chaudhari
Swapnil Chaudhari

Reputation: 542

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();
    }
}

Upvotes: 2

Related Questions