Need to disable expand on CollapsingToolbarLayout for certain fragments

AndroidAndroid Support-LibraryAndroid ToolbarCoordinator Layout

Android Problem Overview


I have a AppCompatActivity that controls replacing many fragments. Here is my layout for it.

activity_main.xml

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">

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

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    android:background="@color/white"
    app:headerLayout="@layout/drawer_header"
    app:menu="@menu/drawer"/>

</android.support.v4.widget.DrawerLayout>

activity_main_frame.xml

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="256dp"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

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

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

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:layout_gravity="bottom"/>

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

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

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" >
    </FrameLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        app:borderWidth="0dp"
        android:src="@drawable/app_ic_slide_wallpaper_dark"
        android:layout_margin="@dimen/big_padding"
        android:clickable="true"/>

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

My home fragment is set initially and that is where i want the collapsing toolbar expanded and that works fine. However when i change fragments from side drawer i want to disable the expanding toolbar.

I have figured out how to collapse it when a drawer item is selected but i also need to make sure it doesn't expand unless the home fragment is displayed. is this possible?

public void collapseToolbar(){
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
        behavior = (AppBarLayout.Behavior) params.getBehavior();
        if(behavior!=null) {
            behavior.onNestedFling(coordinator, appbar, null, 0, 10000, true);
        }
    }

Android Solutions


Solution 1 - Android

Disable nested scrolling on the scrolling fragment content:

recyclerView.setNestedScrollingEnabled(false);

Use this if you're using the support library:

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

Solution 2 - Android

This class will let you disable/re-enable the expansion behavior.

public class DisableableAppBarLayoutBehavior extends AppBarLayout.Behavior {
    private boolean mEnabled;

    public DisableableAppBarLayoutBehavior() {
        super();
    }

    public DisableableAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setEnabled(boolean enabled) {
        mEnabled = enabled;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        return mEnabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    public boolean isEnabled() {
        return mEnabled;
    }
}

Use it in your layout like so:

<android.support.design.widget.AppBarLayout
    ... other attributes ...
    app:layout_behavior="com.yourpackage.DisableableAppBarLayoutBehavior"
    >
    <!-- your app bar contents -->
</android.support.design.widget.AppBarLayout>

Then, when you want to disable the behavior:

AppBarLayout myAppBar = ....;
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) myAppBar.getLayoutParams();
((DisableableAppBarLayoutBehavior) layoutParams.getBehavior()).setEnabled(false);

Solution 3 - Android

Now, in v23 of support library you can easily control your appbar visibility.

Just get a reference to your AppBarLayout and hide/show it depending on the fragment you want to load:

private AppBarLayout appBarLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
[...]
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
[...]
}

public void switchToFragment(Fragment fragment, String tag, boolean expandToolbar){
        FragmentManager fragmentManager = getSupportFragmentManager();

        Fragment currentFragment = fragmentManager.findFragmentByTag(currentFragmentTag);

        if(currentFragment == null || !TextUtils.equals(tag, currentFragmentTag) ){
            currentFragmentTag = tag;
            fragmentManager
                    .beginTransaction()
                    .replace(R.id.flContent, fragment, currentFragmentTag)
                    .commit();

            if(expandToolbar){
                appBarLayout.setExpanded(true,true);
            }else{
                appBarLayout.setExpanded(false,true);
            }
        }
    }

P.S. don't forget to add the required dependencies in your build.gradle:

dependencies {  
    compile 'com.android.support:design:23.2.1'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:recyclerview-v7:23.2.1' 
}

EDIT: If you also want to lock your toolbar in certain fragments (apart from collapsing) you have to resort to workarounds as this feature is not provided by CollapsingToolbarLayout until now (v23.2.1 of support design). Here you can find my proposed workaround.

Solution 4 - Android

All you have to do is replace CoordinatorLayout with custom implementation of CoordinatorLayout which will cheat that nested scrolling has been handled.

MyCoordinatorLayout implementation:

public class MyCoordinatorLayout extends CoordinatorLayout {

    private boolean allowForScroll = false;

    public MyCoordinatorLayout(Context context) {
	    super(context);
    }

    public MyCoordinatorLayout(Context context, AttributeSet attrs) {
	    super(context, attrs);
    }

    @Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
	    return allowForScroll && super.onStartNestedScroll(child, target, nestedScrollAxes);
    }

    public boolean isAllowForScroll() {
	    return allowForScroll;
    }

    public void setAllowForScroll(boolean allowForScroll) {
	    this.allowForScroll = allowForScroll;
    }
}

activity view xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <!--CONTENT-->

        <com.example.views.MyCoordinatorLayout
            android:id="@+id/coordinator"
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            >

        <com.example.views.ControllableAppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="192dp"
            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="match_parent"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginBottom="32dp"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <ImageView
                    android:id="@+id/header"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/primary"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    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/ThemeOverlay.AppCompat.Light" />

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

        </com.example.views.ControllableAppBarLayout>

        <FrameLayout
            android:id="@+id/flContent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            />

        </com.example.views.MyCoordinatorLayout>


        <!-- DRAWER -->

        <fragment
            android:id="@+id/fDrawer"
            android:name="com.example.fragment.DrawerFragment"
            android:layout_width="@dimen/drawer_width"
            android:layout_height="match_parent"
            android:layout_gravity="left|start"
            android:fitsSystemWindows="true"
            android:clickable="true"
            />

    </android.support.v4.widget.DrawerLayout>

</LinearLayout>

I encourage you to use custom AppBarLayout implementation with helper methods to collapse/expand toolbar. On this gist you can find one.

Ok, now it's time to configure our toolbar in activity.

public class ToolbarAppcompatActivity extends AppCompatActivity
        implements AppBarLayout.OnOffsetChangedListener {

    protected Toolbar toolbar;
    protected MyCoordinatorLayout coordinator;
    protected ControllableAppBarLayout appbar;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        configureToolbar();
	switchFragment(new FooFragment(), "FOO", true);
    }

    protected void configureToolbar() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        coordinator = (MyCoordinatorLayout) findViewById(R.id.coordinator);
        appbar = (ControllableAppBarLayout) findViewById(R.id.appbar);
        appbar.addOnOffsetChangedListener(this);
        getDelegate().setSupportActionBar(toolbar);
    }

    public void switchToFragment(Fragment fragment, String tag, boolean expandToolbar){
        FragmentManager fragmentManager = getSupportFragmentManager();

        Fragment currentFragment = fragmentManager.findFragmentByTag(currentFragmentTag);

        if(currentFragment == null || !TextUtils.equals(tag, currentFragmentTag) ){
            currentFragmentTag = tag;
            fragmentManager
                    .beginTransaction()
                    .replace(R.id.flContent, fragment, currentFragmentTag)
                    .commit();

            if(expandToolbar){
                expandToolbar();
            }else{
                collapseToolbar();
            }
        }
    }

    protected void addFragment(Fragment fragment, String tag, boolean expandToolbar) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        currentFragmentTag = tag;
        fragmentManager
                .beginTransaction()
                .add(R.id.flContent, fragment, currentFragmentTag)
                .addToBackStack(tag)
                .commit();

        if(expandToolbar){
            expandToolbar();
        }else{
            collapseToolbar();
        }
    }

   protected void collapseToolbar(){
        appbar.collapseToolbar();
        coordinator.setAllowForScroll(false);
    }

    public void expandToolbar(){
        appbar.expandToolbar();
        coordinator.setAllowForScroll(true);
    }

}

Every time you want to switch fragment and collapse/expand toolbar just call method switchFragment/addFragment with proper boolean parameter.

Just one last note. Make sure you use latest support libraries.

dependencies {

    // android support
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.android.support:recyclerview-v7:22.2.1'
    compile 'com.android.support:design:22.2.1'

}

Do not use include tag in AppBarLayout. It does not work

Solution 5 - Android

The following code achieves 3 objectives:

Disable CollapsingToolbarLayout expand or collapse by the user, but still allow AppBarLayout.setExpanded.

Prevent scrolling of RecyclerView or NestedScrollView from expanding or collapsing the CollapsingToolbarLayout.

// scrollView can be RecyclerView or NestedScrollView
ViewCompat.setNestedScrollingEnabled(scrollView, false)

Prevent the user from expanding or collapsing the CollapsingToolbarLayout by flicking the AppBar.

val params = appBar.layoutParams as CoordinatorLayout.LayoutParams
if (params.behavior == null)
    params.behavior = AppBarLayout.Behavior()
val behaviour = params.behavior as AppBarLayout.Behavior
behaviour.setDragCallback(object : AppBarLayout.Behavior.DragCallback() {
    override fun canDrag(appBarLayout: AppBarLayout): Boolean {
        return false
    }
})

https://code.luasoftware.com/tutorials/android/how-to-disable-or-lock-collapsingtoolbarlayout-collapse-or-expand/

Solution 6 - Android

With Android Design Library v23.1.1, the method described by @LucyFair does not work. I managed to get it to work by setting the app:layout_scrollFlags to enterAlwaysCollapsed only, and the appbar stays "locked".

Hope this helps. :)

Solution 7 - Android

I have used @JasonWyatt's solution and added DragCallback to behavior class to prevent touch and drag CollapsingToolbarLayout to expand it

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

Solution 8 - Android

I have found a workaround solution that works with activity and various fragments. You implement the CollapsingToolbarLayout with AppBar etc in your activity and then each time you call a new fragment you can call these 2 functions.

  • When I want my appbar to keep collapsed:

      public void lockAppBarClosed() {
          mAppBarLayout.setExpanded(false, false);
          mAppBarLayout.setActivated(false);
          CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
          lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
      }
    
  • When I want my appbar to be expanded and scrollable again

      public void unlockAppBarOpen() {
          mAppBarLayout.setExpanded(true, false);
          mAppBarLayout.setActivated(true);
          CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
          lp.height = (int) getResources().getDimension(R.dimen.toolbar_expand_height);
      }
    

You can call thoses functions from your fragments by implementing an interface. Here's a quick example, for your case (toolbar expands only in homeFragment)

public interface CustomListener() {
    void unlockAppBarOpen();
    void lockAppBarClosed()
}

public class MainActivity extends BaseActivity implements CustomListener {
    
    @Override
    public void unlockAppBarOpen() {
        mAppBarLayout.setExpanded(true, false);
        mAppBarLayout.setActivated(true);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbar_expand_height);
    }

    @Override
    public void lockAppBarClosed() {
        mAppBarLayout.setExpanded(false, false);
        mAppBarLayout.setActivated(false);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
    }
}

public class MainFragment extends BaseFragment {

    @Override
    public void onResume() {
        super.onPause();
        ((MainActivity) getContext()).unlockAppBarOpen();
    }
}

public class SecondFragment extends BaseFragment {

    @Override
    public void onResume() {
        super.onPause();
        ((MainActivity) getContext()).lockAppBarClosed();
    }
}

With this example:

  • each time the MainFragment will be displayed -> it will extends the toolbar and make it collapsable and expandable

  • each time the SecondFragment is displayed -> il will collapsed the toolbar to a standard size and prevent it to expand again

Hope it will help you !

Solution 9 - Android

I found Simple solution to enable/disable collapse in CollapsingToolbarLayout:

    private void setExpandEnabled(boolean enabled) {
        mAppBarLayout.setExpanded(enabled, false);
        mAppBarLayout.setActivated(enabled);
        final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
        if (enabled)
            params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
        else
            params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
        collapsingToolbarLayout.setLayoutParams(params);
    }

Solution 10 - Android

I can't comment, so I will post my additions to JasonWyatt's DisableableAppBarLayoutBehavior solution as independent answer.

public class DisableableAppBarLayoutBehavior extends AppBarLayout.Behavior {
    private boolean mEnabled = true; // enabled by default

    public DisableableAppBarLayoutBehavior() {
        super();
    }

    public DisableableAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setEnabled(boolean enabled) {
        mEnabled = enabled;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
        return mEnabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        if (!isEnabled()) return;
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
        if (!isEnabled()) return;
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
    }

    public boolean isEnabled() {
        return mEnabled;
    }
}

In addition to onStartNestedScroll also lock onNestedPreScroll and onNestedScroll itself to avoid unexpected behaviour. For example, in my case - calling setExpanded(false, true) on my app bar was braking expected behaviour and still was expanding with lags. Now it works:

LayoutParams layoutParams = (LayoutParams) context.appBarLayout.getLayoutParams();
((DisableableAppBarLayoutBehavior)layoutParams.getBehavior()).setEnabled(false);
context.appBarLayout.setLayoutParams(layoutParams);
context.appBarLayout.setExpanded(false, true); // collapse app bar

Solution 11 - Android

None of the provided solutions worked for me except this one. With this solution, i can easily manage the state of collapsing toolbar. This will prevent expanding of collapsing toolbar and set title for it.

public void lockAppBar(boolean locked,String title) {
    if(locked){
        appBarLayout.setExpanded(false, true);
        int px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics());
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
        lp.height = px;
        appBarLayout.setLayoutParams(lp);
        collapsingToolbarLayout.setTitleEnabled(false);
        toolbar.setTitle(title);
    }else{
        appBarLayout.setExpanded(true, false);
        appBarLayout.setActivated(true);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbarExpandHeight);
        collapsingToolbarLayout.setTitleEnabled(true);
        collapsingToolbarLayout.setTitle(title);
    }
}

Solution 12 - Android

Find the AppBarLayout id as like this.

appBarLayout = (AppBarLayout) findViewById(R.id.appbar);

> Disable expand on CollapsingToolbarLayout for certain fragments

appBarLayout.setExpanded(true,true);

> Enable expand on CollapsingToolbarLayout for certain fragments

appBarLayout.setExpanded(false,true);

Hope it will help you !!

Solution 13 - Android

Locking and unlocking was not enough, simple lockings keeps the image shrinked; here my solution

Call this on resume that requires toolbar in collapsed mode.


private void lockAppBarClosed() {

    appBarLayout.setExpanded(false,true);
    CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
    ((CustomAppBarLayoutBehavior)layoutParams.getBehavior()).setScrollBehavior(false);

    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
    params.setScrollFlags(0);
    params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);

}

This is for a fragment that requires Snap

public void unlockAppBarOpen() {

    appBarLayout.setExpanded(true,true);
    CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
    ((CustomAppBarLayoutBehavior)layoutParams.getBehavior()).setScrollBehavior(true);


    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
    params.setScrollFlags(0);
    params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);

}

This is for a fragment requires scroll with SCROLL_FLAG_EXIT_UNTIL_COLLAPSED mode.


public void unlockAppBarOpen() {

    appBarLayout.setExpanded(true,true);
    CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
    ((CustomAppBarLayoutBehavior)layoutParams.getBehavior()).setScrollBehavior(true);


    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
    params.setScrollFlags(0);
    params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);

}

And the CustomAppBarLayoutBehavior.java

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

    private boolean shouldScroll = false;

    public CustomAppBarLayoutBehavior() {
        super();
    }

    public CustomAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
        return shouldScroll;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        if(shouldScroll){
            return super.onTouchEvent(parent, child, ev);
        }else{
            return false;
        }
    }

    public void setScrollBehavior(boolean shouldScroll){
        this.shouldScroll = shouldScroll;
    }

    public boolean isShouldScroll(){
        return shouldScroll;
    }
}

provide this behavior to AppBarLayout

 <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="210dp"
        app:layout_behavior=".behaviors.CustomAppBarLayoutBehavior"
        android:theme="@style/ThemeOverlay.MaterialComponents.ActionBar.Primary">

Solution 14 - Android

Thanks to @Desmond Lua's great answer I was finally able to fix this problem in my code. Here is my adapted solution using Java and Data Binding.

<com.google.android.material.appbar.AppBarLayout
    android:id="@+id/app_bar"
    bind:expanded="@{myCondition? false : true}"
    app:disableCollapsingScroll="@{myCondition? false : true}"
    ... >

        <com.google.android.material.appbar.CollapsingToolbarLayout
            ... >

            ...

        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView 
   android:nestedScrollingEnabled="@{myCondition? false : true}"
   ... >

   ...

</NestedScrollView>
@BindingAdapter("disableCollapsingScroll")
public static void bindDisableCollapsingScroll(AppBarLayout appBarLayout, boolean disabled) {
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();

    if (params.getBehavior() == null) {
        params.setBehavior(new AppBarLayout.Behavior());
    }

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

Solution 15 - Android

You can lock appbarlayout expansion by resetting collapsing toolbar height to toolbar height

toolbarHeight = toolbar.getLayoutParams().height;

if (expand) {
    collapsingToolbar.getLayoutParams().height = getResources().getDimensionPixelOffset(R.dimen.collapsingToolbarDefaultHeight);
    appBarLayout.setExpanded(true, true);
} else {
    //collapse
    //** it is important you do this before resetting **
    appBarLayout.setExpanded(false, true);
    appBarLayout.postDelayed(new Runnable() {
        @Override
        public void run() {
            collapsingToolbar.getLayoutParams().height = toolbarHeight;
        }
     }, 700/* 600 is default animation time to collapse */);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBigDXView Question on Stackoverflow
Solution 1 - AndroidtachyonfluxView Answer on Stackoverflow
Solution 2 - AndroidJasonWyattView Answer on Stackoverflow
Solution 3 - AndroidSevleView Answer on Stackoverflow
Solution 4 - AndroidLucy FairView Answer on Stackoverflow
Solution 5 - AndroidDesmond LuaView Answer on Stackoverflow
Solution 6 - AndroidStrangeCodeView Answer on Stackoverflow
Solution 7 - AndroidDuev S.View Answer on Stackoverflow
Solution 8 - AndroidAnne-ClaireView Answer on Stackoverflow
Solution 9 - AndroidDmitry VelychkoView Answer on Stackoverflow
Solution 10 - AndroidekarView Answer on Stackoverflow
Solution 11 - AndroidKemalView Answer on Stackoverflow
Solution 12 - AndroidPraveen Kumar VermaView Answer on Stackoverflow
Solution 13 - AndroidkelalakaView Answer on Stackoverflow
Solution 14 - AndroidflauschtrudView Answer on Stackoverflow
Solution 15 - AndroidPushanView Answer on Stackoverflow