46

I need to know when CollapsingToolbar from material design library is collapsed.

peterh
  • 11,875
  • 18
  • 85
  • 108
d0pestar
  • 565
  • 1
  • 5
  • 10

5 Answers5

101

As Marko said, this can be achieved using your own implementation of a OnOffsetChangedListener.

AppBarLayout appBarLayout = (AppBarLayout) view.findViewById(R.id.app_bar_layout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) {
                // Collapsed
            } else if (verticalOffset == 0) {
                // Expanded
            } else {
                // Somewhere in between
            }
        }
    }););
chrlaura
  • 1,307
  • 1
  • 9
  • 11
  • This solution seems to be the most popular one. However, in my case, the problem is that the `addOnOffsetChangedListener` are called every time while collapsing/expanding unless you stop moving your finger. Is it possible to detect the state only than when it is either expanded or closed and only after one of those state execute some code? – Mark Delphi Oct 09 '20 at 15:18
  • This solution works like a charm.. Just one thing - that since I had disabled collapsable toolbar's scroll flags in certain conditions so getTotalScrollRange() for me was 0 and hence it was always showing me "collapsed" state. Interchanging the 'if" and "else if" serves best in that case. – Damanpreet Singh Nov 23 '20 at 13:23
81

UPDATE: Since support versions of 23.1.1+ the issue is no longer there, no need to use the listener and disable the swipe refresh layout, it will work as it should (link).


Implement AppBarLayout.OnOffsetChangedListener listener on your AppBarLayout

AppBarLayout appBarLayout = (AppBarLayout) view.findViewById(R.id.app_bar_layout);
appBarLayout.addOnOffsetChangedListener(this);

And check if offset is 0, meaning the toolbar is fully expanded.

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset)
{
    if (offset == 0)
    {
        // Fully expanded
    }
    else
    {
        // Not fully expanded or collapsed
    }
}
Ognian Gloushkov
  • 2,669
  • 1
  • 20
  • 35
Marko
  • 20,385
  • 13
  • 48
  • 64
  • 1
    @Atieh to further explain it, when the collapsing toolbar is fully expanded the offset value is equal to zero (offset == 0) – ponnex Feb 20 '16 at 17:00
  • 1
    I changed the if condition to `verticalOffset < -710` then the problem solved. not elegant but it works – Logan Guo Apr 20 '16 at 15:36
  • To detect if fully collapsed check if Math.abs(offset) == appBarLayout – user1840378 Dec 13 '16 at 22:10
  • As @Atieh said this is NOT the right answer, Upvotes are missleading, Maybe users should try it first then upvote ! – Farshad Aug 22 '17 at 06:20
  • I will re-test this and correct it if there is a mistake. – Marko Aug 22 '17 at 08:27
  • And how would it be when Scrool returns but only the Toolbar is visible and fixed at the top?Like this:https://stackoverflow.com/questions/46981038/transparent-statusbar-when-collapsed/46986273 @Marko – TiagoIB Oct 28 '17 at 13:11
19

Take a look over this github gist

public class MyAppBarLayout extends AppBarLayout
        implements AppBarLayout.OnOffsetChangedListener {

    private State state;
    private OnStateChangeListener onStateChangeListener;

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

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

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (!(getLayoutParams() instanceof CoordinatorLayout.LayoutParams)
                || !(getParent() instanceof CoordinatorLayout)) {
            throw new IllegalStateException(
                    "MyAppBarLayout must be a direct child of CoordinatorLayout.");
        }
        addOnOffsetChangedListener(this);
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
        if (verticalOffset == 0) {
            if (onStateChangeListener != null && state != State.EXPANDED) {
                onStateChangeListener.onStateChange(State.EXPANDED);
            }
            state = State.EXPANDED;
        } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) {
            if (onStateChangeListener != null && state != State.COLLAPSED) {
                onStateChangeListener.onStateChange(State.COLLAPSED);
            }
            state = State.COLLAPSED;
        } else {
            if (onStateChangeListener != null && state != State.IDLE) {
                onStateChangeListener.onStateChange(State.IDLE);
            }
            state = State.IDLE;
        }
    }

    public void setOnStateChangeListener(OnStateChangeListener listener) {
        this.onStateChangeListener = listener;
    }

    public interface OnStateChangeListener {
        void onStateChange(State toolbarChange);
    }

    public enum State {
        COLLAPSED,
        EXPANDED,
        IDLE
    }
}
Eduard B.
  • 6,735
  • 4
  • 27
  • 38
2
 appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->

        if (Math.abs(verticalOffset)  >= appBarLayout.totalScrollRange) { // collapse
        } else if (verticalOffset == 0) { // fully expand

        } else { // scolling

        }
    })

appBarLayout.totalScrollRange is not always equal to verticalOffset in some case, better check verticalOffset larger than totoalScrollRange

qianlv
  • 502
  • 5
  • 15
0
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() 
{
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
 {

            if (Math.abs(verticalOffset)-appBarLayout.getTotalScrollRange() == 0)
            {
                //  on Collapse
            }
            else
            {
               //  on expand
            }
        }
    });
dileep krishnan
  • 326
  • 4
  • 7