Search code examples
androidandroid-coordinatorlayoutandroid-appbarlayout

Create custom AppBarLayout child with minimum height?


I want to create a custom view that will be a child of an AppBarLayout. I need this view to collapse partially as I scroll up, but not completely. It will have a minimum height and stay fixed to the top of the AppBarLayout in it's small size mode and then expand back to it's large size mode when the view is scrolled back down.

I've spent a lot of time looking through the source of the AppBarLayout and CoordinatorLayout, and so far I don't see a way to do what I want. It looks like children of AppBarLayout must either stay visible or disappear completely when the view is scrolled up.

Can anyone suggest a way to create a child of an AppBarLayout that will behave this way?

Thank you


Solution

  • Here's the recipe:

    If you set android:minHeight, the AppBarLayout will respect that value by not scrolling beyond the point that would make your component smaller. So your XML layout might be something like this:

        <com.example.CustomCollapsingLayout
            android:layout_width="match_parent"
            android:layout_height="320dp"
            android:minHeight="108dp"
            android:fitsSystemWindows="true"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
    

    Next you want to have your class register an OnOffsetChangedListener with the parent AppBarLayout. Your component will get events as the app bar is scrolled so that you know how to configure your view.

    class OnOffsetChangedListener implements AppBarLayout.OnOffsetChangedListener {
    
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    
                final int scrollRange = appBarLayout.getTotalScrollRange();
                float offsetFactor = (float) (-verticalOffset) / (float) scrollRange;
                ...
    

    This shows you how to find the total scroll range and then find the ratio between the total scroll range and the current scroll position i.e. where the app bar is in its scroll.

    You should do what CollapsingToolbarLayout does; override onAttachedToWindow and add the listener there:

            // Add an OnOffsetChangedListener if possible
            final ViewParent parent = getParent();
            if (parent instanceof AppBarLayout) {
                if (mOnOffsetChangedListener == null) {
                    mOnOffsetChangedListener = new OnOffsetChangedListener();
                }
                ((AppBarLayout) parent).addOnOffsetChangedListener(mOnOffsetChangedListener);
            }
    

    Take a look at the source code for CollapsingToolbarLayout as it will give you some ideas. Your view needs to do a lot of the same things.

    You can also look at my sample project that has an image that scales and moves as the toolbar is scrolled: https://github.com/klarson2/Collapsing-Image