Search code examples
androidfloating-action-buttonandroid-snackbar

Android floating action button not returning to initial position


If the FAB (Floating Action Button) hides before a snackbar appears (in CoordinatorLayout) then the next time I show the FAB it is drawn in the old position (not moved down to the original position). If the FAB is visible when the snackbar dissapears, then everything is working as expected. Did I miss something or is it a bug?

UPD: As requested, here is a minimal example. I will put most important bits here, and a fully working example can be found on my github

This is just a very slightly modified example from Android template Activity project.

activity_main.xml:

<?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"
    tools:context="coordination.fab.snackbar.test.testfabsnackbar.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <include layout="@layout/content_main" />

    <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="@android:drawable/ic_dialog_email" />

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

And an OnCreate method from my MainActivity (extends AppCompatActivity):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            fab.hide();
            Snackbar.make(view, "blah", Snackbar.LENGTH_SHORT).show();
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() { fab.show(); }
            }, 3000);
        }
    });
}

Essentially, I just ensure that the action button stays hidden when the snackbar get hidden.

Please tell me if you need more info on anything.

UPD2 If you stumble upon this thread and don't like it - please tell me what I can improve. I really would like to know how to overcome the issue.

UPD3 The issue created in Android bug tracker is merged into this one and should be fixed in the next build


Solution

  • I didn't realise I had this problem until I saw your post, but it happens in my app too.

    Looking at the FloatingActionButton source I see that they set the translationY of the FAB based on the Snackbar, but only if the FAB is visible. If the FAB is not visible, the translationY is not changed and so depending on when it is hidden and shown it could end up stuck in the wrong position.

    What I have just done, and seems to work, is to reset the translationY myself if appropriate.

    Declare the snackbar as a class level variable so we can check on its status.

    Snackbar snack;
    

    Then use this to make your snackbar when you need it:

    snack.make(...etc...).show();
    

    Then when we are calling our fab.show() method we can check on the status of snack and reset translationY ourselves.

            if(snack != null){
                if(!snack.isShown()) {
                    //if the snackbar is not shown, make sure the fab is at the
                    //original location
                    fab.setTranslationY(0.0f);
                }
            }
            fab.show();
    

    If for whatever reason the correct translationY of the FAB is not 0.0 you may want to use fab.getTranslationY to save the correct value and use that when you need to reset it.