Search code examples
androidandroid-layoutandroid-toolbarandroid-design-libraryandroiddesignsupport

FloatingActionButton should be visible without scrolling (in CollapsingToolbarlayout)


How to have a FloatingActionButton visible when initially entering displaying a screen and without scrolling/collapsing the toolbar with a CollapsingToolbarLayout?

This screenshot shows the default behavior with the collapsing toolbar and fab which I want to change to have the fab initially visible regardless of the scroll state.

The Fab is in a Fragment which is attached to an Activity.

default behavior Layout Code of the Activity:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:fitsSystemWindows="true">

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/app_bar_height"
    android:fitsSystemWindows="true"
    android:theme="@style/AppTheme.AppBarOverlay">
    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/toolbar_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleTextAppearance="@style/ActivityTitle"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        app:toolbarId="@+id/toolbar">

        <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/AppTheme.PopupOverlay"/>

    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
    android:id="@+id/default_fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:layout="@layout/fragment_swipe_refresh_list"/></android.support.design.widget.CoordinatorLayout>

Layout Code of the Fragment:

<android.support.design.widget.CoordinatorLayout
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:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent">


<de.aposync.team.widget.view.ContainerSwipeRefreshLayout
    android:id="@+id/layout_container_swipe_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="0dp"
    android:paddingRight="0dp">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/view_recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingBottom="96dp"/>

</de.aposync.team.widget.view.ContainerSwipeRefreshLayout>

<include
    layout="@layout/view_progress_bar_group"
    android:visibility="gone"
    tools:visibility="visible"/>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/fab_margin"
    app:fabSize="normal"
    tools:src="@android:drawable/ic_dialog_alert""/></android.support.design.widget.CoordinatorLayout>

Edit The answer from Jantzilla provides a working solution, but requires the FAB to be moved from the fragment to the activity. Is there any solution which doesn't require the fab to be moved?


Solution

  • There is an example of this on Github. The app can also be sampled on the Play store. I recently used this as a reference for a project of my own.

    The Code

    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.design.widget.CollapsingToolbarLayout;
    import android.support.design.widget.CoordinatorLayout;
    import android.support.v4.widget.NestedScrollView;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.MenuItem;
    import android.view.View;
    
    /**
    * Created by romain on 15/10/15.
    */
    public class ScrollCollapseLargeToolbarActivity extends AppCompatActivity {
    
    private View mFab;
    private int mFabTranslationSize = 0;
    private boolean mFabIsVisible = true;
    
    public static void start(Context context) {
        Intent intent = new Intent(context, ScrollCollapseLargeToolbarActivity.class);
        context.startActivity(intent);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroll_collapse_large_toolbar);
    
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    
        String toolbarTitle = getResources().getString(R.string.sample_collapse_scroll_toolbar);
        CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(toolbarTitle);
    
        mFab = findViewById(R.id.fab);
    
        NestedScrollView scrollView = (NestedScrollView) findViewById(R.id.nested_scrollview);
        scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if (scrollY > oldScrollY) {
                    animateFab(false);
                } else {
                    animateFab(true);
                }
            }
        });
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private void animateFab(boolean show) {
        if (show && !mFabIsVisible) {
            //Show
            mFabIsVisible = true;
            mFab.animate().translationY(0);
        } else if (!show && mFabIsVisible) {
            //Hide
            mFabIsVisible = false;
            if (mFabTranslationSize == 0) {
                int margin = ((CoordinatorLayout.LayoutParams) mFab.getLayoutParams()).bottomMargin;
                mFabTranslationSize = mFab.getHeight() + margin * 2;
            }
            mFab.animate().translationY(mFabTranslationSize);
        }
    }
    }
    

    The XML

    <?xml version="1.0" encoding="utf-8"?>
    
    <android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    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.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/toolbar_expanded_height"
        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"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/>
    
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
    
    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nested_scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:text="@string/large_text"/>
    
    </android.support.v4.widget.NestedScrollView>
    
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_share_white"
        />
    
    </android.support.design.widget.CoordinatorLayout>