diff --git a/docs/components/BottomAppBar.md b/docs/components/BottomAppBar.md
index f5ff8ac82f8..ecfba64c238 100644
--- a/docs/components/BottomAppBar.md
+++ b/docs/components/BottomAppBar.md
@@ -238,6 +238,7 @@ Element | Attribute | Related
**Cradle margin** | `app:fabCradleMargin` | `setFabCradleMargin`
`getFabCradleMargin` | `6dp`
**Cradle rounded corner radius** | `app:fabCradleRoundedCornerRadius` | `setFabCradleRoundedCornerRadius`
`getFabCradleRoundedCornerRadius` | `4dp`
**Cradle vertical offset** | `app:fabCradleVerticalOffset` | `setCradleVerticalOffset`
`getCradleVerticalOffset` | `12dp`
+**End margin** | `app:fabAlignmentModeEndMargin` | `setFabAlignmentModeEndMargin`
`getFabAlignmentModeEndMargin` | N/A
See the
[FAB documentation](https://github.com/material-components/material-components-android/tree/master/docs/components/FloatingActionButton.md)
diff --git a/lib/java/com/google/android/material/bottomappbar/BottomAppBar.java b/lib/java/com/google/android/material/bottomappbar/BottomAppBar.java
index d30ac4af75a..c8d0e3d3652 100644
--- a/lib/java/com/google/android/material/bottomappbar/BottomAppBar.java
+++ b/lib/java/com/google/android/material/bottomappbar/BottomAppBar.java
@@ -180,15 +180,21 @@ public class BottomAppBar extends Toolbar implements AttachedBehavior {
public @interface MenuAlignmentMode {}
@Nullable private Integer navigationIconTint;
- private final int fabOffsetEndMode;
private final MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
@Nullable private Animator modeAnimator;
@Nullable private Animator menuAnimator;
+ @MenuAlignmentMode private int menuAlignmentMode;
@FabAlignmentMode private int fabAlignmentMode;
@FabAnimationMode private int fabAnimationMode;
@FabAnchorMode private int fabAnchorMode;
- @MenuAlignmentMode private int menuAlignmentMode;
+
+ /** No end margin for the FAB. */
+ private static final int NO_FAB_END_MARGIN = -1;
+
+ private final int fabOffsetEndMode;
+ @Px private int fabAlignmentModeEndMargin;
+
private boolean hideOnScroll;
private final boolean paddingBottomSystemWindowInsets;
private final boolean paddingLeftSystemWindowInsets;
@@ -328,6 +334,9 @@ public BottomAppBar(@NonNull Context context, @Nullable AttributeSet attrs, int
a.getBoolean(R.styleable.BottomAppBar_paddingLeftSystemWindowInsets, false);
paddingRightSystemWindowInsets =
a.getBoolean(R.styleable.BottomAppBar_paddingRightSystemWindowInsets, false);
+ fabAlignmentModeEndMargin =
+ a.getDimensionPixelOffset(
+ R.styleable.BottomAppBar_fabAlignmentModeEndMargin, NO_FAB_END_MARGIN);
a.recycle();
@@ -600,6 +609,29 @@ public void setCradleVerticalOffset(@Dimension float verticalOffset) {
}
}
+ /**
+ * Returns the {@link FloatingActionButton} end margin pixel offset for the fab if it is set.
+ *
+ *
An end margin of -1 indicates that the default margin will be used. + */ + @Px + public int getFabAlignmentModeEndMargin() { + return fabAlignmentModeEndMargin; + } + + /** + * Sets the end margin, in pixels, of the {@link FloatingActionButton}. This will only have an + * effect if the fab alignment mode is {@link #FAB_ALIGNMENT_MODE_END}. + * + *
An offset of -1 will use the default margin.
+ */
+ public void setFabAlignmentModeEndMargin(@Px int margin) {
+ if (fabAlignmentModeEndMargin != margin) {
+ fabAlignmentModeEndMargin = margin;
+ setCutoutStateAndTranslateFab();
+ }
+ }
+
/**
* Returns true if the {@link BottomAppBar} should hide when a {@link
* androidx.core.view.NestedScrollingChild} is scrolled. This is handled by {@link
@@ -994,8 +1026,17 @@ private float getFabTranslationY() {
private float getFabTranslationX(@FabAlignmentMode int fabAlignmentMode) {
boolean isRtl = ViewUtils.isLayoutRtl(this);
if (fabAlignmentMode == FAB_ALIGNMENT_MODE_END) {
+ View fab = findDependentView();
int systemEndInset = isRtl ? leftInset : rightInset;
- int totalEndInset = fabOffsetEndMode + systemEndInset;
+ int totalEndInset = systemEndInset;
+ if (fabAlignmentModeEndMargin != NO_FAB_END_MARGIN && fab != null) {
+ totalEndInset += fab.getMeasuredWidth() / 2 + fabAlignmentModeEndMargin;
+ } else {
+ // If no fab end margin is specified, it follows the previous behaviour of
+ // translating by fabOffsetEndMode instead of a clear-cut margin.
+ // This will result in a different padding for different FAB sizes.
+ totalEndInset += fabOffsetEndMode;
+ }
return (getMeasuredWidth() / 2 - totalEndInset) * (isRtl ? -1 : 1);
} else {
return 0;
diff --git a/lib/java/com/google/android/material/bottomappbar/res-public/values/public.xml b/lib/java/com/google/android/material/bottomappbar/res-public/values/public.xml
index daccc88a883..978dd3bb515 100644
--- a/lib/java/com/google/android/material/bottomappbar/res-public/values/public.xml
+++ b/lib/java/com/google/android/material/bottomappbar/res-public/values/public.xml
@@ -22,6 +22,7 @@