How to reset the Toolbar position controlled by the CoordinatorLayout?

22,653

Solution 1

To reset the scroll state, just get the AppBarLayout.Behavior object

CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator);
AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();       

and call onNestedPreScroll method manually:

int[] consumed = new int[2];
behavior.onNestedPreScroll(coordinator, appbar, null, 0, -1000, consumed);

If you would like to reset smoothly with an animation, you can try calling onNestedFling instead:

behavior.onNestedFling(coordinator, appbar, null, 0, -1000, true);

Solution 2

First get a AppBarLayout refrence in you MainActivity, then in the pause state of the fragment that is being replaced, use the method below to expand toolbar :

MainActivity.appbar.setExpanded(true,true);

And or to close the toolbar :

MainActivity.appbar.setExpanded(false,true);

The second parameter is used to scroll the toolbar smoothly.

Solution 3

Update your support lib to v23 then you can use:

appBarLayout.setExpanded(true/false);

public void setExpanded (boolean expanded)

Sets whether this AppBarLayout is expanded or not, animating if it has already been laid out.

As with AppBarLayout's scrolling, this method relies on this layout being a direct child of a CoordinatorLayout.

expanded true if the layout should be fully expanded, false if it should be fully collapsed

Solution 4

@razzledazzle The AppBarLayout stores onOffsetChangedListeners as WeakReferences, which means they are garbage collected when needed, for instance when you do a intense fling. See solution here:

https://code.google.com/p/android/issues/detail?id=176328

Solution 5

I'm using this codes before fragment changes.

scrollingElement.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
scrollingElement.dispatchNestedPreScroll(0, -Integer.MAX_VALUE, null, null);
scrollingElement.stopNestedScroll();
Share:
22,653
razzledazzle
Author by

razzledazzle

Ah yes, the air of mystery!

Updated on July 09, 2022

Comments

  • razzledazzle
    razzledazzle almost 2 years

    The app I'm working on consists of a Navigation Drawer which is implemented in an Activity. The activity layout is as follows:

    <FrameLayout 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.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.design.widget.CoordinatorLayout
            android:id="@+id/coordinator"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <FrameLayout
                android:id="@+id/container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
            <include
                android:id="@+id/appbar"
                layout="@layout/appbar" />
    
        </android.support.design.widget.CoordinatorLayout>
    
        <android.support.design.widget.NavigationView
            android:id="@+id/navigation_drawer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/header_drawer"
            app:menu="@menu/menu_nav">
        </android.support.design.widget.NavigationView>
    
    </android.support.v4.widget.DrawerLayout>
    
    </FrameLayout>
    

    This is a very common pattern, only thing that changes frequently is the Fragment inside the container layout.

    If any of the Fragment has a scrolling element, upon scrolling, the CoordinatorLayout will happily make position translations, including the Toolbar/AppBarLayout.

    The real problem here is, when the Fragment gets replaced, the position for the Toolbar remains the same, i.e., if the Toolbar is hidden, it will stay so which isn't intended.

    Result is this:

    This:

    After scroll

    Gets stuck:

    Then change

    How can one reset the Toolbar position for this case?

    EDIT: A bug is probable, the AppBarLayout offset change listener gets called only when relaunching the app (press back button and open the app), and stops getting called again after an intense fling.

  • Peanut
    Peanut almost 9 years
    Can you add some explanations?
  • theb1uro
    theb1uro almost 9 years
    For me it only works for collapsing AppBarLayout by setting positive 'velocityY' value. Above code with negative 'velocityY' value has no effect. I'm calling it from NestedScrollView's onTouchListener after ACTION_UP action. I want to implement snap behavior - to always collapse or expand AppBarLayout.
  • razzledazzle
    razzledazzle almost 9 years
    Thanks for the answer, this is a good solution, I used the onNestedFling() inside the drawer open callback and it works pretty nicely.
  • razzledazzle
    razzledazzle almost 9 years
    Ah, this was definitely the case, I did see WeakReferences in the source but never thought how easily they could get GCed. This also explains why referencing the listeners as field under onResume() worked better as opposed to initializing anonymous classed during onCreate(). Implementing the listener as a class is a guaranteed solution as mentioned in the link. Thank you very much for your input!
  • Tomas
    Tomas almost 9 years
    I have exactly the same experience like @theb1uro. Only work for collapse with positive 'velocityY' value. Expand with negative 'velocityY' value has no effect...
  • Tomas
    Tomas almost 9 years
    I tested it also on cheesesquare and the same result, any idea why this work only when collapsing AppBarLayout?
  • User31689
    User31689 almost 9 years
    params.getBehavior() is returning null. In xml, layout_behaviour tag is set on sibling NestedScrollView, not the AppBarLayout. Please help!
  • Nati Dykstein
    Nati Dykstein over 8 years
    Works nicely with ViewPager+TabLayout inside CoordinatorLayout
  • Dan Dar3
    Dan Dar3 over 8 years
    Idea appears to be coming from the doc for startNestedScroll(), see developer.android.com/reference/android/view/…
  • razzledazzle
    razzledazzle over 8 years
    This does not cover the use case when you would want to lock the AppBarLayout.
  • razzledazzle
    razzledazzle over 8 years
    This fails to lock the AppBarLayout in place. It however does work for regular cases.
  • Michael
    Michael over 8 years
    According to that post is has been fixed.
  • xiaoyee
    xiaoyee over 8 years
    negative 'velocityY' value will have effect, when you set app:layout_scrollFlags="scroll|enterAlways" ,
  • Muhammad Babar
    Muhammad Babar over 8 years
    AppBarLayout has no such method setExpanded?
  • Pkmmte
    Pkmmte over 8 years
    @MuhammadBabar Update your dependencies, bro.