Floating Action Button Not Floating With Snackbar If anchorView set within CoordinatorLayout

When I set snackbar.anchorView = adContainer my FAB doesn’t float.

val snackbar = Snackbar.make(main_content, "Item Deleted", Snackbar.LENGTH_INDEFINITE)
        snackbar.anchorView = adContainer
        snackbar.setAction("Dismiss"){

        }
        snackbar.show()

If I don’t set an anchor view it floats ok.

Question – how can I get the FAB to float up and down if I set the snackbar anchor view to be adContainer?

snackbar with anchorview set

snackbar without anchorview

My XML file-

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/rootConstraintLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Show Snackbar"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/adContainer"
            android:layout_width="match_parent"
            android:layout_height="64dp"
            android:layout_marginStart="1dp"
            android:layout_marginTop="1dp"
            android:layout_marginEnd="1dp"
            android:layout_marginBottom="1dp"
            android:background="#F44336"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_marginBottom="96dp"
        android:layout_marginEnd="32dp"
        android:clickable="true"
        app:layout_anchorGravity="end|bottom"
        app:srcCompat="@android:drawable/ic_input_add"
        android:focusable="true" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Thanks to @Zain for his answer. With my code below I had managed to get the FAB working except there was no bottom margin. With Zains solution there was a bottom margin.

val snackbar = Snackbar.make(main_content, "Item Deleted", Snackbar.LENGTH_INDEFINITE)
            snackbar.setAction("Dismiss"){

            }
            val snackbarView = snackbar.view
            val params = snackbarView.layoutParams as CoordinatorLayout.LayoutParams
            params.anchorId = R.id.adContainer
            params.bottomMargin = 16// this line didn't work
            params.gravity = Gravity.TOP
            params.anchorGravity = Gravity.TOP
            snackbarView.layoutParams = params
            snackbar.show()

Answer

You need to create a custom CoordinatorLayout.Behavior class with FloatingActionButton as the view type that this Behavior operates on

The credits of below custom java class back to this Repo. I just converted it into Kotlin.

You can use either the Kotlin or Java versions.

Kotlin:

class BottomNavigationFABBehavior constructor(context: Context, attrs: AttributeSet?) :
    CoordinatorLayout.Behavior<FloatingActionButton>(context, attrs) {

  override fun layoutDependsOn(
      parent: CoordinatorLayout,
      child: FloatingActionButton,
      dependency: View
  ): Boolean {
        return dependency is SnackbarLayout
    }

    override fun onDependentViewRemoved(
        parent: CoordinatorLayout,
        child: FloatingActionButton,
        dependency: View
    ) {
        child.translationY = 0.0f
    }

    override fun onDependentViewChanged(
        parent: CoordinatorLayout,
        child: FloatingActionButton,
        dependency: View
    ): Boolean {
        return updateButton(child, dependency)
    }

    private fun updateButton(child: View, dependency: View): Boolean {
        return if (dependency is SnackbarLayout) {
            val oldTranslation = child.translationY
            val height = dependency.getHeight().toFloat()
            val newTranslation = dependency.getTranslationY() - height
            child.translationY = newTranslation
            oldTranslation != newTranslation
        } else {
            false
        }
    }
}

Java

public final class BottomNavigationFABBehavior
        extends CoordinatorLayout.Behavior<FloatingActionButton> {

  public BottomNavigationFABBehavior(@Nullable Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
  }

  public boolean layoutDependsOn(
          @Nullable CoordinatorLayout parent,
          @NonNull FloatingActionButton child,
          @NonNull View dependency) {
    return dependency instanceof Snackbar.SnackbarLayout;
  }

  public void onDependentViewRemoved(
          @NonNull CoordinatorLayout parent,
          @NonNull FloatingActionButton child,
          @NonNull View dependency) {
    child.setTranslationY(0.0f);
  }

  public boolean onDependentViewChanged(
          @NonNull CoordinatorLayout parent,
          @NonNull FloatingActionButton child,
          @NonNull View dependency) {
    return this.updateButton(child, dependency);
  }

  private boolean updateButton(View child, View dependency) {
    if (dependency instanceof Snackbar.SnackbarLayout) {
      float oldTranslation = child.getTranslationY();
      float height = (float) dependency.getHeight();
      float newTranslation = dependency.getTranslationY() - height;
      child.setTranslationY(newTranslation);
      return oldTranslation != newTranslation;
    } else {
      return false;
    }
  }
}

Then use this class in your fab app:layout_behavior attribute to make the CoordinatorLayout functions with the needed behavior

The full layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/rootConstraintLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Show Snackbar"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/adContainer"
            android:layout_width="match_parent"
            android:layout_height="64dp"
            android:layout_marginStart="1dp"
            android:layout_marginTop="1dp"
            android:layout_marginEnd="1dp"
            android:layout_marginBottom="1dp"
            android:background="#F44336"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        app:fabSize="normal"
        app:layout_anchor="@id/adContainer"
        app:layout_anchorGravity="end|top"
        app:layout_behavior=".BottomNavigationFABBehavior2"
        app:srcCompat="@android:drawable/ic_input_add"
        app:useCompatPadding="true" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

And of course you need to keep snackbar.anchorView = adContainer as-is

Preview