FloatingActionButton doesn't hide

AndroidMaterial DesignAndroid Design-LibraryFloating Action-Button

Android Problem Overview


I am trying to hide my FloatingActionButton fabLocation programmatically with :

fabLocation.setVisibility(View.GONE)

but it does not work.

If I add android:visibility="gone" in my XML layout, fabLocation is hidden when I run my activity but it reappears when I scroll.

Here is my layout:

<?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"
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: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="@color/colorOverlay"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:id="@+id/img_couverture"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            android:scaleType="centerCrop"
            android:src="@drawable/bg_navigation_drawer_header"
            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>

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

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.v7.widget.CardView
            android:layout_marginTop="8dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="16dp">

                <TextView
                    android:id="@+id/tv_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textSize="18sp" />

                <View
                    android:background="@drawable/separator_orange_gradient"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="16dp"
                    android:layout_width="match_parent"
                    android:layout_height="2dp"/>

                <TextView
                    android:id="@+id/tv_history"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/TextAppearance.RobotoLight" />

            </LinearLayout>

        </android.support.v7.widget.CardView>

    </LinearLayout>

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

<android.support.design.widget.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="16dp"
    android:clickable="true"
    android:id="@+id/fab_location"
    android:src="@drawable/ic_fab_location_24dp"
    app:backgroundTint="@color/colorOrange"
    app:layout_anchor="@id/appbar"
    app:layout_anchorGravity="bottom|right|end" />

Android Solutions


Solution 1 - Android

It is due to the app:layout_anchor attribute. You must get rid of the anchor before changing visibility:

CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
p.setAnchorId(View.NO_ID);
fab.setLayoutParams(p);
fab.setVisibility(View.GONE);

Solution 2 - Android

FloatingActionButtons anchored to AppBarLayouts have a special relationship where their visibility is controlled by the scroll position of the AppBarLayout.

You can turn this off via the behavior_autoHide attribute:

<android.support.design.widget.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_anchor="..."
    app:behavior_autoHide="false"/>

You can also do this programmatically if you wish:

EDIT:

fab.getBehavior() was not correct, use getBehavior() from its LayoutParams

CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
FloatingActionButton.Behavior behavior = (FloatingActionButton.Behavior) lp.getBehavior();
if (behavior != null) {
    behavior.setAutoHideEnabled(false);
} else {
    behavior = new FloatingActionButton.Behavior();
    behavior.setAutoHideEnabled(false);
    lp.setBehavior(behavior);
}

Solution 3 - Android

The most simplistic way to hide and show a floating action button would be to call this in your activity. This will also properly animate your FAB automatically.

Hide:

nameOfYourFAB.Hide();

Show:

nameOfYourFAB.Show();

Solution 4 - Android

I wasn't completely happy with any of the solutions posted. Some only worked part of the time, while others only worked for fab.setVisibility(). While I know this is technically what the original question asked, a few responses expressed interest in using fab.hide(), and messing with the layout parameters doesn't exactly get to the root of the issue.

As pointed out by @ChrisBanes, the FloatingActionButton.Behavior being tied to the AppBarLayout is what causes the issue. So, as with his answer, you have to setAutoHideEnabled(false) to disable that functionality. But this solution doesn't help if you actually want the FloatingActionButton to hide automatically and when you call hide() manually.

So in order to do this; I simply disable the auto-hide functionality before I manually hide the Button, then re-enable the functionality after I manually show the Button:

private void hideFloatingActionButton(FloatingActionButton fab) {
    CoordinatorLayout.LayoutParams params =
            (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
    FloatingActionButton.Behavior behavior =
            (FloatingActionButton.Behavior) params.getBehavior();

    if (behavior != null) {
        behavior.setAutoHideEnabled(false);
    }

    fab.hide();
}

private void showFloatingActionButton(FloatingActionButton fab) {
    fab.show();
    CoordinatorLayout.LayoutParams params =
            (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
    FloatingActionButton.Behavior behavior =
            (FloatingActionButton.Behavior) params.getBehavior();

    if (behavior != null) {
        behavior.setAutoHideEnabled(true);
    }
}

Solution 5 - Android

FloatingActionButton layers = (FloatingActionButton) findViewById(R.id.layers);
layers.hide();

It works for me, setVisibility doesn't work for FloatingActionButton as it belongs to another viewGroup that doesn't have setVisibility method.

Solution 6 - Android

If you want to show hidden FAB

    <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/coordinator"
        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.AppBarLayout>

    ...

    <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:visibility="gone"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:clickable="true"/>

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

and

    CoordinatorLayout.LayoutParams p = new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.WRAP_CONTENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT);
    p.anchorGravity = Gravity.BOTTOM | Gravity.END;
    p.setAnchorId(R.id.appbar);
    p.setMargins(...);
    fab.setLayoutParams(p);
    fab.setVisibility(View.VISIBLE);

Solution 7 - Android

After some answers around, I founded the solution for my problem(also when the fab is hidden it can handle action!).

First of all I suggest you to replace .setVisibility(View.GONE) and .setVisibility(View.VISIBLE) with the methods .show() and .hide(). These last handle also actionMode.

The second problem for me was the action also handled when the fab was hidden, for resolve this I made it:

final CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams)floatingActionButton.getLayoutParams();
    if (show){
        p.setAnchorId(R.id.appBarLayout);
        p.width = CoordinatorLayout.LayoutParams.WRAP_CONTENT;
        p.height = CoordinatorLayout.LayoutParams.WRAP_CONTENT;
        floatingActionButton.setLayoutParams(p);
        floatingActionButton.show();
    }else{
        p.setAnchorId(View.NO_ID);
        p.width = 0;
        p.height = 0;
        floatingActionButton.setLayoutParams(p);
        floatingActionButton.hide();
    }

Solution 8 - Android

The real solution for your problem is to subclass default FloatingActionButton.Behavior to call setAutoHide(false) in their constructors, so you can control it yourself.

Note that I talk about bottom sheets below, but it is exactly the same problem for all anchored Floating Action Buttons, and it does respond to the question and should solve the problem as expected.

Alternatively, you can override the boolean onDependentViewChanged(…) method from your custom Behavior, copy the isBottomSheet(…) static method present in the FloatingActionButton.Behavior class, and only call & return the value of the super method if it's not a bottom sheet.

You can further customize the default behavior this way, or by extending the vanilla CoordinatorLayout.Behavior class directly, and you can cherry pick code to copy paste from the FloatingActionButton.Behavior class if needed.

Here's the code I used to control back the FAB visibility:

/**
 * Allows controlling the FAB visibility manually.
 */
@SuppressWarnings("unused")
public class FabManualHideBehavior extends FloatingActionButton.Behavior {

    public FabManualHideBehavior() {
        super();
        setAutoHideEnabled(false);
    }

    public FabManualHideBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAutoHideEnabled(false);
    }
}

And I applied it to my FAB in xml this way:

<android.support.design.widget.CoordinatorLayout
    ...>
    ...
    <android.support.design.widget.FloatingActionButton
        ...
        app:layout_anchor="@+id/bottom_sheet"
        app:layout_anchorGravity="top|end"
        app:layout_behavior="your.package.name.ui.behavior.FabManualHideBehavior"/>

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

Solution 9 - Android

here is simple solution

private var fabAnchorId: Int = View.NO_ID
private val fabParams: CoordinatorLayout.LayoutParams
        get() = (fab.layoutParams as CoordinatorLayout.LayoutParams)

fun showFab() {
    fabParams.anchorId = fabAnchorId
    fabParams.gravity = Gravity.NO_GRAVITY
    fab.show()
}

fun hideFab() {
    fabParams.anchorId = View.NO_ID
    fabParams.gravity = Gravity.END.or(Gravity.BOTTOM)
    fab.hide()
}

before show/hide we have to change anchor and gravity

Solution 10 - Android

None of these other solutions helped me 100%. I needed repeated, animated show and hide (like FAB.show() and hide()) all while anchored to the app bar when visible.

I ended up creating the FAB new every time I showed it, manually inserting and anchoring it, and animating it based on the support library implementation. It's gross, but it works perfectly.

private void hidePlayButton(final FloatingActionButton fab) {
    // Cancel any animation from the default behavior
    fab.animate().cancel();
    fab.animate()
               .scaleX(0f)
               .scaleY(0f)
               .alpha(0f)
               .setDuration(200)
               .setInterpolator(new FastOutLinearInInterpolator())
               .setListener(new Animator.AnimatorListener() {
                   @Override public void onAnimationStart(Animator animation) {}

                   @Override public void onAnimationEnd(Animator animation) {
                      coordinatorLayout.removeView(fab);
                   }

                   @Override public void onAnimationCancel(Animator animation) {}

                   @Override public void onAnimationRepeat(Animator animation) {}
               });
}

private void showPlayButton() {
    int fabSize = getResources().getDimensionPixelSize(R.dimen.fab_size);
    int margin = getResources().getDimensionPixelSize(R.dimen.fab_margin);
    final FloatingActionButton fab = new FloatingActionButton(getActivity());
    fab.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(getActivity(), R.color.tint)));
    fab.setImageDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.play));
    CoordinatorLayout.LayoutParams p = new CoordinatorLayout.LayoutParams(fabSize, fabSize);
    p.rightMargin = p.leftMargin = p.bottomMargin = p.topMargin = margin;
    p.anchorGravity = Gravity.BOTTOM | Gravity.END;
    p.setAnchorId(R.id.appbar);
    fab.setLayoutParams(p);
    // Start from 1 pixel
    fab.setAlpha(0f);
    fab.setScaleX(0f);
    fab.setScaleY(0f);
    binding.coordinatorLayout.addView(fab);
    fab.animate()
       .alpha(1f)
       .scaleX(1f)
       .scaleY(1f)
       .setDuration(200)
       .setInterpolator(new FastOutLinearInInterpolator());

    fab.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            hidePlayButton(fab);
            // do action
        }
    });
}

Solution 11 - Android

Simple code :

   public static void setVisibilityFab(FloatingActionButton fab, int visibility)
  {

        CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
        p.setAnchorId(View.NO_ID);
        fab.setLayoutParams(p);
        if(visibility==View.GONE || visibility==View.INVISIBLE)
            fab.setVisibility(View.GONE);
        else
            fab.setVisibility(View.VISIBLE);
    }

Solution 12 - Android

I know that you answer is about how to make it work for gone visibility but if you use invisible instead you will have no worries about that and is less code.

Solution 13 - Android

I worked around the show()/hide() shortcoming by placing the FAB in or out of the screen using layout margins. example:

CoordinatorLayout.LayoutParams p =
   new CoordinatorLayout.LayoutParams(
      CoordinatorLayout.LayoutParams.WRAP_CONTENT,
      CoordinatorLayout.LayoutParams.WRAP_CONTENT);

p.gravity = Gravity.BOTTOM | Gravity.LEFT;
int fabMargin = (int)res.getDimension(R.dimen.fab_margin);

if( enabled ) {
   p.setMargins(fabMargin,0,0,fabMargin);
}
else {
   p.setMargins(-200,0,0,fabMargin);
}
mFab.setLayoutParams(p);

Solution 14 - Android

I you use this code:

boolean mFabShouldBeShown;
FloatingActionButton.OnVisibilityChangedListener fabListener = new FloatingActionButton.OnVisibilityChangedListener() {
        @Override
        public void onShown(FloatingActionButton fab) {
            super.onShown(fab);
            if(!mFabShouldBeShown){
                fab.hide();
            }
        }

        @Override
        public void onHidden(FloatingActionButton fab) {
            super.onHidden(fab);
            if(mFabShouldBeShown){
                fab.show();
            }
        }
};

public void methodWhereFabIsHidden() {
    mFabShouldBeShown = false;
    mFloatingActionButton.hide(fabListener);
}

public void methodWhereFabIsShown() {
    mFabShouldBeShown = true;
    mFloatingActionButton.show(fabListener);
}

Solution 15 - Android

If you want to hide the fab, you can try this: fab.hide();

else try fab.show();

enjoy.

Solution 16 - Android

To hide the floating button

fab = (FloatingActionButton) findViewById(R.id.fab);
CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
p.setAnchorId(View.NO_ID);
fab.setLayoutParams(p);
fab.hide;

and to re-show

fab = (FloatingActionButton) findViewById(R.id.fab);
CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
p.setAnchorId(View.NO_ID);
fab.setLayoutParams(p);
fab.show;

Solution 17 - Android

you can do it using this:

fab.setEnabled(false);
fab.setClickable(false);
fab.setAlpha(0.0f);

This is similar behavior as View.Gone

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
Questionfrenchdev20View Question on Stackoverflow
Solution 1 - AndroidnatarioView Answer on Stackoverflow
Solution 2 - AndroidChris BanesView Answer on Stackoverflow
Solution 3 - AndroidAlex CarringtonView Answer on Stackoverflow
Solution 4 - AndroidBryanView Answer on Stackoverflow
Solution 5 - AndroidSatendra BehreView Answer on Stackoverflow
Solution 6 - AndroidGeorgy GobozovView Answer on Stackoverflow
Solution 7 - AndroidciccioskaView Answer on Stackoverflow
Solution 8 - AndroidLouis CADView Answer on Stackoverflow
Solution 9 - AndroidprzebarView Answer on Stackoverflow
Solution 10 - AndroidLisa WrayView Answer on Stackoverflow
Solution 11 - AndroidAhmad AghazadehView Answer on Stackoverflow
Solution 12 - AndroidDaniel Gomez RicoView Answer on Stackoverflow
Solution 13 - AndroidYossi LironView Answer on Stackoverflow
Solution 14 - AndroidCabezasView Answer on Stackoverflow
Solution 15 - AndroidJayView Answer on Stackoverflow
Solution 16 - AndroidAbanoub HannaView Answer on Stackoverflow
Solution 17 - AndroidKhamidjon KhamidovView Answer on Stackoverflow