How to disable scrolling of AppBarLayout in CoordinatorLayout?

36,030

Solution 1

I'm not sure I got it, but I think you are looking for a DragCallback.

The DragCallback interface allows to choose whether the sibling scrolling view should be controlled by scrolls onto the AppBarLayout.

You can define one by calling:

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
    @Override
    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
        return false;
    }
});

By always returning false, your scrolling view will not be controlled by the ABL any longer.

Note: before calling this you should check that ViewCompat.isLaidOut(appBarLayout), otherwise params.getBehavior() will return null.

Solution 2

Problem

  1. AppBarLayout scrolls even if the scroll content fits the screen.
  2. It is because by default we can drag AppBarLayout by touching & dragging AppBarLayout.

Solution

  1. We will disable "Dragging" behaviour for AppBarLayout.

    // Disable "Drag" for AppBarLayout (i.e. User can't scroll appBarLayout by directly touching appBarLayout - User can only scroll appBarLayout by only using scrollContent)
    if (appBarLayout.getLayoutParams() != null) {
        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        AppBarLayout.Behavior appBarLayoutBehaviour = new AppBarLayout.Behavior();
        appBarLayoutBehaviour.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
            @Override
            public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                return false;
            }
        });
        layoutParams.setBehavior(appBarLayoutBehaviour);
    }
    

Reference

  1. This is just extension of "natario's" accepted answer above.

  2. https://developer.android.com/reference/android/support/design/widget/AppBarLayout.Behavior.DragCallback.html

Solution 3

You can accomplish this by defining a custom app:layout_behavior in xml. With this approach you don't have to worry about getting a reference to the LayoutParams and doing null checks.

  <android.support.design.widget.AppBarLayout
      android:id="@+id/app_bar_layout"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:layout_behavior="com.yourcompany.FixedAppBarLayoutBehavior"
      >

Then create a custom class that extends from AppBarLayout.Behavior.

public class FixedAppBarLayoutBehavior extends AppBarLayout.Behavior {

  public FixedAppBarLayoutBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);

    setDragCallback(new DragCallback() {
      @Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
        return false;
      }
    });
  }
}

Updated with Kotlin version:

class FixedAppBarLayoutBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
  init {
    setDragCallback(object : DragCallback() {
      override fun canDrag(appBarLayout: AppBarLayout): Boolean = false
    })
  }
}

Solution 4

So after two hours of trying I have found a solution, which is pretty simple. I just needed to extend CoordinatorLayout and override OnInterceptTouchEvent method so the class looks like this:

public class NonTouchableCoordinatorLayout extends CoordinatorLayout {
public NonTouchableCoordinatorLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
}

}

Solution 5

you can use the NestedScrollView.setNestedScrollingEnabled(false) to disable the AppBarLayout nestScroll envent

Share:
36,030
janox1x2x3
Author by

janox1x2x3

Updated on October 22, 2020

Comments

  • janox1x2x3
    janox1x2x3 over 3 years

    I have MapFragment with parallax effect inside AppBarLayout:

    enter image description here

    I want to disable scrolling on AppBarLayout, because it is not possible to move across map, since touch evenys on the map are always handled as scroll events. I would like to handle collapsing of AppBarLayout by scrolling RecyclerView only, which is on the bottom of the screen.

    This is my xml:

    <?xml version="1.0" encoding="utf-8"?>
    

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true"
            app:contentScrim="@color/white"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
            app:titleEnabled="false">
    
            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_collapseMode="parallax"
                android:fitsSystemWindows="true">
    
                <fragment
                    android:id="@+id/map"
                    android:name="com.androidmapsextensions.SupportMapFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </FrameLayout>
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="73dp"
                app:contentInsetLeft="0dp"
                app:contentInsetStart="0dp"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
    
                <include
                    android:id="@+id/search_bar"
                    layout="@layout/layout_searchbar" />
            </android.support.v7.widget.Toolbar>
    
            <View
                android:id="@+id/toolbar_shadow"
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:layout_below="@id/search_bar"
                android:layout_gravity="bottom"
                android:background="@drawable/toolbar_dropshadow"
                android:visibility="gone" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
    
    
    <RecyclerView
        android:id="@+id/farm_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    

    Thank you for the response.