6363import androidx .coordinatorlayout .widget .CoordinatorLayout .AttachedBehavior ;
6464import java .lang .annotation .Retention ;
6565import java .lang .annotation .RetentionPolicy ;
66+ import java .lang .ref .WeakReference ;
6667import java .util .ArrayList ;
6768import java .util .List ;
6869
@@ -420,11 +421,14 @@ private void dispatchAnimationEnd() {
420421 * Sets the fab diameter. This will be called automatically by the {@link BottomAppBar.Behavior}
421422 * if the fab is anchored to this {@link BottomAppBar}.
422423 */
423- void setFabDiameter (@ Px int diameter ) {
424+ boolean setFabDiameter (@ Px int diameter ) {
424425 if (diameter != getTopEdgeTreatment ().getFabDiameter ()) {
425426 getTopEdgeTreatment ().setFabDiameter (diameter );
426427 materialShapeDrawable .invalidateSelf ();
428+ return true ;
427429 }
430+
431+ return false ;
428432 }
429433
430434 private void maybeAnimateModeChange (@ FabAlignmentMode int targetMode ) {
@@ -810,6 +814,47 @@ public static class Behavior extends HideBottomViewOnScrollBehavior<BottomAppBar
810814
811815 private final Rect fabContentRect ;
812816
817+ private WeakReference <BottomAppBar > viewRef ;
818+
819+ private final OnLayoutChangeListener fabLayoutListener = new OnLayoutChangeListener () {
820+ @ Override
821+ public void onLayoutChange (View v , int left , int top , int right , int bottom , int oldLeft ,
822+ int oldTop , int oldRight , int oldBottom ) {
823+ BottomAppBar child = viewRef .get ();
824+
825+ // If the child BAB no longer exists, remove the listener.
826+ if (child == null || !(v instanceof FloatingActionButton )) {
827+ v .removeOnLayoutChangeListener (this );
828+ return ;
829+ }
830+
831+ FloatingActionButton fab = ((FloatingActionButton ) v );
832+
833+ fab .getMeasuredContentRect (fabContentRect );
834+ int height = fabContentRect .height ();
835+
836+ // Set the cutout diameter based on the height of the fab.
837+ if (!child .setFabDiameter (height )) {
838+ // The size of the fab didn't change so return early.
839+ return ;
840+ }
841+
842+ CoordinatorLayout .LayoutParams fabLayoutParams = (CoordinatorLayout .LayoutParams ) v
843+ .getLayoutParams ();
844+
845+ // Set the bottomMargin of the fab if it is 0dp. This adds space below the fab if the
846+ // BottomAppBar is hidden.
847+ if (fabLayoutParams .bottomMargin == 0 ) {
848+ // Extra padding is added for the fake shadow on API < 21. Ensure we don't add too much
849+ // space by removing that extra padding.
850+ int bottomShadowPadding = (fab .getMeasuredHeight () - fabContentRect .height ()) / 2 ;
851+ int bottomMargin = child .getResources ()
852+ .getDimensionPixelOffset (R .dimen .mtrl_bottomappbar_fab_bottom_margin );
853+ fabLayoutParams .bottomMargin = Math .max (0 , bottomMargin - bottomShadowPadding );
854+ }
855+ }
856+ };
857+
813858 public Behavior () {
814859 fabContentRect = new Rect ();
815860 }
@@ -822,6 +867,8 @@ public Behavior(Context context, AttributeSet attrs) {
822867 @ Override
823868 public boolean onLayoutChild (
824869 CoordinatorLayout parent , BottomAppBar child , int layoutDirection ) {
870+ viewRef = new WeakReference <>(child );
871+
825872 View dependentView = child .findDependentView ();
826873 if (dependentView != null && !ViewCompat .isLaidOut (dependentView )) {
827874 // Set the initial position of the FloatingActionButton with the BottomAppBar vertical
@@ -832,25 +879,12 @@ public boolean onLayoutChild(
832879
833880 if (dependentView instanceof FloatingActionButton ) {
834881 FloatingActionButton fab = ((FloatingActionButton ) dependentView );
882+
883+ // Always update the BAB if the fab is laid out.
884+ fab .addOnLayoutChangeListener (fabLayoutListener );
885+
835886 // Ensure the FAB is correctly linked to this BAB so the animations can run correctly
836887 child .addFabAnimationListeners (fab );
837-
838- // Set the correct cutout diameter
839- fab .getMeasuredContentRect (fabContentRect );
840- child .setFabDiameter (fabContentRect .height ());
841-
842- // Set the bottomMargin of the fab if it is 0dp. This adds space below the fab if the
843- // BottomAppBar is hidden.
844- if (fabLayoutParams .bottomMargin == 0 ) {
845- // Extra padding is added for the fake shadow on API < 21. Ensure we don't add too much
846- // space by removing that extra padding.
847- int bottomShadowPadding = (fab .getMeasuredHeight () - fabContentRect .height ()) / 2 ;
848- int bottomMargin =
849- child
850- .getResources ()
851- .getDimensionPixelOffset (R .dimen .mtrl_bottomappbar_fab_bottom_margin );
852- fabLayoutParams .bottomMargin = Math .max (0 , bottomMargin - bottomShadowPadding );
853- }
854888 }
855889
856890 // Move the fab to the correct position
0 commit comments