androidandroid-fragmentsandroid-coordinatorlayout

Scrolling fragment comes on top of Activity cause below activity view to scroll


I have an activity which has CoordinatorLayout as a root layout. Inside that, there's a FrameLayout layout which is hidden and programmatically has been set a fragment which is revealed from the bottom on a button click. That fragment consists of a grid RecyclerView which is scrollable.

refer to this

If you focus on the toolbar you can see behind view gets scroll down and shows the behind view image when the grid view scroll content is over.

This is the layout of my activity

Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:focusableInTouchMode="true"
    tools:context=".activities.hotels.HotelDetailActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:layout_behavior="android.support.design.widget.AppBarLayout$Behavior">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:toolbarId="@+id/toolbar"
            app:expandedTitleTextAppearance="@style/TransparentText"
            app:collapsedTitleTextAppearance="@style/ExpandedAppBar"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:titleEnabled="true">

            <ImageView
                android:id="@+id/main_hotel_image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:src="@drawable/temp_hotel"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay"
                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

                <android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <TextView
                        android:id="@+id/tool_bar_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:fontFamily="@font/roboto_medium"
                        android:text="Hotel Name"
                        android:singleLine="true"
                        android:textColor="@android:color/white"
                        android:textSize="16sp"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <TextView
                        android:id="@+id/tool_bar_sub_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Thu, 10 Jan 2019 - Sat, 12 Jan 2019"
                        android:textColor="@color/white"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@+id/tool_bar_title" />

                </android.support.constraint.ConstraintLayout>

            </android.support.v7.widget.Toolbar>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_scrolling" />

    <FrameLayout
        android:id="@+id/more_detail_fragment_holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:visibility="gone"
        android:layout_gravity="center"
        android:gravity="center"
        android:layout_marginTop="56dp"
        android:layout_marginBottom="56dp"
        android:clickable="true"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_photo_library"
        app:backgroundTint="@color/white"
        app:fabSize="mini"
        app:layout_anchor="@id/app_bar"
        app:layout_anchorGravity="bottom|end" />


    <android.support.constraint.ConstraintLayout
        android:id="@+id/bottom_message_container"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@drawable/clickable_bottom_bar_background"
        android:layout_gravity="bottom"
        android:gravity="bottom">

        <android.support.constraint.ConstraintLayout
            android:id="@+id/bottom_message_container_child"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/price_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginBottom="8dp"
                android:fontFamily="@font/roboto_regular"
                android:text="LKR 0"
                android:textColor="@android:color/white"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

            <TextView
                android:id="@+id/detail_titel_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:layout_marginStart="8dp"
                android:fontFamily="@font/roboto_light"
                android:text="Starting From"
                android:textColor="@android:color/white"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toStartOf="parent" />

            <FrameLayout
                android:id="@+id/continue_button"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                android:layout_marginBottom="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginTop="8dp"
                android:background="@drawable/secondary_button_background"
                android:clickable="true"
                android:paddingEnd="8dp"
                android:paddingStart="8dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent">

                <TextView
                    android:id="@+id/button_color"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:fontFamily="@font/roboto_medium"
                    android:text="Continue"
                    android:textColor="@android:color/white"
                    android:textSize="16sp" />

            </FrameLayout>

        </android.support.constraint.ConstraintLayout>

    </android.support.constraint.ConstraintLayout>

</android.support.design.widget.CoordinatorLayout>

Fragment Layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".fragments.hotels.AllHotelAmenitiesFragment"
    android:orientation="vertical"
    android:background="@color/white"
    android:clickable="true">

    <TextView
        android:id="@+id/hotel_amenities_title_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:fontFamily="@font/roboto_medium"
        android:text="Hotel Amenities"
        android:textColor="@color/textColorPrimary"
        android:textSize="14sp"
        android:layout_marginStart="16dp" />

    <View
        android:id="@+id/divider"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="8dp"
        android:background="@color/divider"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/recycler_view_expand_layout"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/main_hotel_amenities_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:clickable="true"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"/>


</LinearLayout>

HotelDetailActivity

public class HotelDetailActivityEdit extends AppCompatActivity{

    @BindView(R.id.toolbar)
    Toolbar toolbar;

    @BindView(R.id.more_detail_fragment_holder)
    FrameLayout allHotelAmenityHolder;

    @BindView(R.id.app_bar)
    AppBarLayout appBarLayout;

    @BindView(R.id.recycler_view_expand_layout)
    FrameLayout recyclerViewExpandLayout;

    private boolean allAmenitiesFragmentIsHidden;

    private Animation revealFromBottom;
    private Animation unRevealFromBottom;
    private AllHotelAmenitiesFragment allHotelAmenitiesFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hotel_detail);
        ButterKnife.bind(this);

        initialization();
        onClickHotelAmenityExpandContainer();
    }

    private void initialization() {

        revealFromBottom = AnimationUtils.loadAnimation(this, R.anim.slide_in_bottom);
        unRevealFromBottom = AnimationUtils.loadAnimation(this, R.anim.slide_out_bottom);

        allAmenitiesFragmentIsHidden = true;

        allHotelAmenitiesFragment = new AllHotelAmenitiesFragment();

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map_fragment);

    }


    private void onClickHotelAmenityExpandContainer() {
        recyclerViewExpandLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (allAmenitiesFragmentIsHidden) {
                    allHotelAmenityHolder.startAnimation(revealFromBottom);
                    allHotelAmenityHolder.setVisibility(View.VISIBLE);
                    appBarLayout.setExpanded(false);
                    allAmenitiesFragmentIsHidden = false;
                    invalidateOptionsMenu();
                }

            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        if (!allAmenitiesFragmentIsHidden)
            getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_close);
        else {
            getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_arrow_back);
        }

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                break;
        }

        return true;
    }

    @Override
    public void onBackPressed() {

        if (!allAmenitiesFragmentIsHidden) {
            allHotelAmenityHolder.startAnimation(unRevealFromBottom);
            allHotelAmenityHolder.setVisibility(View.GONE);
            appBarLayout.setExpanded(true);
            allAmenitiesFragmentIsHidden = true;
            invalidateOptionsMenu();
        } else {
            finish();
        }
    }

}

AllHotelAmenitiesFragment

public class AllHotelAmenitiesFragment extends Fragment {


    @BindView(R.id.main_hotel_amenities_recycler_view)
    RecyclerView mainHotelAmenitiesRecyclerView;


    private MainHotelAmenitiesListAdapter mainHotelAmenitiesListAdapter;

    public AllHotelAmenitiesFragment() {
        // Required empty public constructor
    }

    public void setArguments(ArrayList<HotelAmenitiesImageObject> hotelAmenitiesWithImages) {

        Bundle args = new Bundle();
        args.putParcelableArrayList("hotel_amenities", hotelAmenitiesWithImages);
        this.setArguments(args);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_all_hotel_amenities, container, false);
        ButterKnife.bind(this, view);

        initialization();

        return view;
    }

    private void initialization() {

        ArrayList<HotelAmenitiesImageObject> mainHotelAmenities = getArguments().getParcelableArrayList("hotel_amenities");

        mainHotelAmenitiesListAdapter = new MainHotelAmenitiesListAdapter(mainHotelAmenities);

        GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 4);
        GridRecyclerViewDivider gridRecyclerItemDecorator = new GridRecyclerViewDivider(4, 16, true, 0);
        mainHotelAmenitiesRecyclerView.addItemDecoration(gridRecyclerItemDecorator);
        mainHotelAmenitiesRecyclerView.setLayoutManager(gridLayoutManager);
        mainHotelAmenitiesRecyclerView.setAdapter(mainHotelAmenitiesListAdapter);

    }

}

As you can see I have set android:clickable="true" to the root layout of the fragment which is what usually do to stop registering clicks on behind layout. It seems when it's come to scroll it does not work like that.

I don't want my activity view behind my fragment to react to the scroll when my fragment visible. Please give me a suggestion to fix this bug.


Solution

  • I have run a demo, this works! It is the Gif links

    disable the AppBarLayout scroll event to expand or collapse

    disable the recyclerview scroll event to expand or collapse AppBarLayout

    you can use scroll flag to disable it too, which i have comment, but this way will expand the AppBarLayout first

    You can use these two code block to get what you want.

    You should modified these code for your project

    when fragment visible, ViewCompat.setNestedScrollingEnabled(mRecyclerView, false) to disable your fragment's recyclerview not your content_scrolling layout recyclerview.

    private int state = STATE_APPBAR;
    private static final int STATE_APPBAR = 1;
    private static final int STATE_CONTENT = 2;
    
    
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
    params.setBehavior(new AppBarLayout.Behavior());
    AppBarLayout.Behavior appBarBehavior = (AppBarLayout.Behavior) params.getBehavior();
    //code block one
    if (appBarBehavior != null) {
        appBarBehavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
            @Override
            public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                return state == STATE_APPBAR;
            }
        });
    }
    
    //code block two
    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (state == STATE_APPBAR) {
                state = STATE_CONTENT;
                //setAppbarLayoutScrollFlag(AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
                ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);
            } else {
                state = STATE_APPBAR;
                //setAppbarLayoutScrollFlag(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
                ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);
            }
        }
    });
    
    
    private void setAppbarLayoutScrollFlag(int flags) {
        AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) mToolbarLayout.getLayoutParams();
        lp.setScrollFlags(flags);
        mToolbarLayout.setLayoutParams(lp);
    }
    

    Apply the code in your project

    1. add a method in AllHotelAmenitiesFragment to get recyclerview
    public class AllHotelAmenitiesFragment extends Fragment {
    
    
        @BindView(R.id.main_hotel_amenities_recycler_view)
        RecyclerView mainHotelAmenitiesRecyclerView;
    
    
        private MainHotelAmenitiesListAdapter mainHotelAmenitiesListAdapter;
    
        public AllHotelAmenitiesFragment() {
            // Required empty public constructor
        }
        
        public RecyclerView getRecyclerView() {
           return mainHotelAmenitiesRecyclerView;
        }
    
    
    1. In your HotelDetailActivityEdit add block logic
    private void onClickHotelAmenityExpandContainer() {
            recyclerViewExpandLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    if (allAmenitiesFragmentIsHidden) {
                        allHotelAmenityHolder.startAnimation(revealFromBottom);
                        allHotelAmenityHolder.setVisibility(View.VISIBLE);
                        appBarLayout.setExpanded(false);
                        allAmenitiesFragmentIsHidden = false;
                        invalidateOptionsMenu();
    
                        //add block logic
                        RecyclerView recyclerview = allHotelAmenitiesFragment.getRecyclerView();
                        ViewCompat.setNestedScrollingEnabled(recyclerview, false);
                    }
    
                }
            });
        }