Skip to content

Commit 6405635

Browse files
Material Design Teamdsn5ft
Material Design Team
authored andcommitted
Handle horizontal system insets for BottomAppBar.
Previously only the bottom inset (navigation bar) would add extra padding to the BottomAppBar which avoided overlapping with the bottom inset when drawing edge-to-edge. A problem arises if the device is rotated horizontally. The FAB (or sometimes the ActionMenuView in RtL layouts) would overlap with the right inset, making usage impossible. This CL adjusts the FAB and ActionMenuView X translations when necessary to avoid the horizontal system insets. Two new stylable attributes have been added to enable/disable this behavior, analogous to the existing attribute for bottom padding. PiperOrigin-RevId: 286419669
1 parent b8afe2b commit 6405635

File tree

7 files changed

+95
-11
lines changed

7 files changed

+95
-11
lines changed

docs/components/BottomAppBar.md

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ FAB Cradle Corner Radius | `app:fabCradleRoundedCornerRadius`
8282
FAB Vertical Offset | `app:fabCradleVerticalOffset`
8383
Hide on scroll | `app:hideOnScroll`
8484
Add Padding for Bottom Insets | `app:paddingBottomSystemWindowInsets`
85+
Add Padding for Left Insets | `app:paddingLeftSystemWindowInsets`
86+
Add Padding for Right Insets | `app:paddingRightSystemWindowInsets`
8587

8688
#### Background Tint
8789

lib/java/com/google/android/material/bottomappbar/BottomAppBar.java

+63-10
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ public class BottomAppBar extends Toolbar implements AttachedBehavior {
146146
@FabAnimationMode private int fabAnimationMode;
147147
private boolean hideOnScroll;
148148
private final boolean paddingBottomSystemWindowInsets;
149+
private final boolean paddingLeftSystemWindowInsets;
150+
private final boolean paddingRightSystemWindowInsets;
149151

150152
/** Keeps track of the number of currently running animations. */
151153
private int animatingModeChangeCounter = 0;
@@ -168,6 +170,8 @@ interface AnimationListener {
168170
private Behavior behavior;
169171

170172
private int bottomInset;
173+
private int rightInset;
174+
private int leftInset;
171175

172176
/**
173177
* Listens to the FABs hide or show animation to kick off an animation on BottomAppBar that reacts
@@ -243,6 +247,10 @@ public BottomAppBar(@NonNull Context context, @Nullable AttributeSet attrs, int
243247
// Reading out if we are handling bottom padding, so we can apply it to the FAB.
244248
paddingBottomSystemWindowInsets =
245249
a.getBoolean(R.styleable.BottomAppBar_paddingBottomSystemWindowInsets, false);
250+
paddingLeftSystemWindowInsets =
251+
a.getBoolean(R.styleable.BottomAppBar_paddingLeftSystemWindowInsets, false);
252+
paddingRightSystemWindowInsets =
253+
a.getBoolean(R.styleable.BottomAppBar_paddingRightSystemWindowInsets, false);
246254

247255
a.recycle();
248256

@@ -273,11 +281,31 @@ public WindowInsetsCompat onApplyWindowInsets(
273281
View view,
274282
@NonNull WindowInsetsCompat insets,
275283
@NonNull RelativePadding initialPadding) {
284+
// Just read the insets here. doOnApplyWindowInsets will apply the padding under the
285+
// hood.
286+
boolean leftInsetsChanged = false;
287+
boolean rightInsetsChanged = false;
276288
if (paddingBottomSystemWindowInsets) {
277-
// Just read the insets here. doOnApplyWindowInsets will apply the bottom padding
278-
// under the hood.
279289
bottomInset = insets.getSystemWindowInsetBottom();
280290
}
291+
if (paddingLeftSystemWindowInsets) {
292+
leftInsetsChanged = leftInset != insets.getSystemWindowInsetLeft();
293+
leftInset = insets.getSystemWindowInsetLeft();
294+
}
295+
if (paddingRightSystemWindowInsets) {
296+
rightInsetsChanged = rightInset != insets.getSystemWindowInsetRight();
297+
rightInset = insets.getSystemWindowInsetRight();
298+
}
299+
300+
// We may need to change the position of the cutout or the action menu if the side
301+
// insets have changed.
302+
if (leftInsetsChanged || rightInsetsChanged) {
303+
cancelAnimations();
304+
305+
setCutoutState();
306+
setActionMenuViewPosition();
307+
}
308+
281309
return insets;
282310
}
283311
});
@@ -679,10 +707,14 @@ private float getFabTranslationY() {
679707
}
680708

681709
private float getFabTranslationX(@FabAlignmentMode int fabAlignmentMode) {
682-
boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
683-
return fabAlignmentMode == FAB_ALIGNMENT_MODE_END
684-
? (getMeasuredWidth() / 2 - fabOffsetEndMode) * (isRtl ? -1 : 1)
685-
: 0;
710+
boolean isRtl = ViewUtils.isLayoutRtl(this);
711+
if (fabAlignmentMode == FAB_ALIGNMENT_MODE_END) {
712+
int systemEndInset = isRtl ? leftInset : rightInset;
713+
int totalEndInset = fabOffsetEndMode + systemEndInset;
714+
return (getMeasuredWidth() / 2 - totalEndInset) * (isRtl ? -1 : 1);
715+
} else {
716+
return 0;
717+
}
686718
}
687719

688720
private float getFabTranslationX() {
@@ -729,7 +761,11 @@ protected int getActionMenuViewTranslationX(
729761
@NonNull ActionMenuView actionMenuView,
730762
@FabAlignmentMode int fabAlignmentMode,
731763
boolean fabAttached) {
732-
boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
764+
if (fabAlignmentMode != FAB_ALIGNMENT_MODE_END || !fabAttached) {
765+
return 0;
766+
}
767+
768+
boolean isRtl = ViewUtils.isLayoutRtl(this);
733769
int toolbarLeftContentEnd = isRtl ? getMeasuredWidth() : 0;
734770

735771
// Calculate the inner side of the Toolbar's Gravity.START contents.
@@ -748,10 +784,11 @@ protected int getActionMenuViewTranslationX(
748784
}
749785
}
750786

751-
int end = isRtl ? actionMenuView.getRight() : actionMenuView.getLeft();
752-
int offset = toolbarLeftContentEnd - end;
787+
int actionMenuViewStart = isRtl ? actionMenuView.getRight() : actionMenuView.getLeft();
788+
int systemStartInset = isRtl ? rightInset : -leftInset;
789+
int end = actionMenuViewStart + systemStartInset;
753790

754-
return fabAlignmentMode == FAB_ALIGNMENT_MODE_END && fabAttached ? offset : 0;
791+
return toolbarLeftContentEnd - end;
755792
}
756793

757794
private void cancelAnimations() {
@@ -838,6 +875,14 @@ private int getBottomInset() {
838875
return bottomInset;
839876
}
840877

878+
private int getRightInset() {
879+
return rightInset;
880+
}
881+
882+
private int getLeftInset() {
883+
return leftInset;
884+
}
885+
841886
@Override
842887
public void setTitle(CharSequence title) {
843888
// Don't do anything. BottomAppBar can't have a title.
@@ -927,6 +972,14 @@ public void onLayoutChange(
927972
// Should be moved above the bottom insets with space ignoring any shadow padding.
928973
int minBottomMargin = bottomMargin - bottomShadowPadding;
929974
fabLayoutParams.bottomMargin = child.getBottomInset() + minBottomMargin;
975+
fabLayoutParams.leftMargin = child.getLeftInset();
976+
fabLayoutParams.rightMargin = child.getRightInset();
977+
boolean isRtl = ViewUtils.isLayoutRtl(fab);
978+
if (isRtl) {
979+
fabLayoutParams.leftMargin += child.fabOffsetEndMode;
980+
} else {
981+
fabLayoutParams.rightMargin += child.fabOffsetEndMode;
982+
}
930983
}
931984
}
932985
};

lib/java/com/google/android/material/bottomappbar/res/values/attrs.xml

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
<attr name="hideOnScroll" format="boolean"/>
4545
<!-- Whether the BottomAppBar should apply padding to be above the bottom window insets. -->
4646
<attr name="paddingBottomSystemWindowInsets"/>
47+
<!-- Whether the BottomAppBar should apply padding to be to the right of the left window insets. -->
48+
<attr name="paddingLeftSystemWindowInsets"/>
49+
<!-- Whether the BottomAppBar should apply padding to be to the left of the right window insets. -->
50+
<attr name="paddingRightSystemWindowInsets"/>
4751
</declare-styleable>
4852

4953
<!-- Style to use for BottomAppBar in this theme. -->

lib/java/com/google/android/material/bottomappbar/res/values/styles.xml

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
<item name="maxButtonHeight">@dimen/mtrl_bottomappbar_height</item>
2929
<item name="elevation">8dp</item>
3030
<item name="paddingBottomSystemWindowInsets">true</item>
31+
<item name="paddingLeftSystemWindowInsets">true</item>
32+
<item name="paddingRightSystemWindowInsets">true</item>
3133
</style>
3234

3335
<style name="Widget.MaterialComponents.BottomAppBar.Colored" parent="Widget.MaterialComponents.BottomAppBar">

lib/java/com/google/android/material/internal/ViewUtils.java

+19
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ public static void doOnApplyWindowInsets(
162162

163163
final boolean paddingBottomSystemWindowInsets =
164164
a.getBoolean(R.styleable.Insets_paddingBottomSystemWindowInsets, false);
165+
final boolean paddingLeftSystemWindowInsets =
166+
a.getBoolean(R.styleable.Insets_paddingLeftSystemWindowInsets, false);
167+
final boolean paddingRightSystemWindowInsets =
168+
a.getBoolean(R.styleable.Insets_paddingRightSystemWindowInsets, false);
165169

166170
a.recycle();
167171

@@ -177,6 +181,21 @@ public WindowInsetsCompat onApplyWindowInsets(
177181
if (paddingBottomSystemWindowInsets) {
178182
initialPadding.bottom += insets.getSystemWindowInsetBottom();
179183
}
184+
boolean isRtl = isLayoutRtl(view);
185+
if (paddingLeftSystemWindowInsets) {
186+
if (isRtl) {
187+
initialPadding.end += insets.getSystemWindowInsetLeft();
188+
} else {
189+
initialPadding.start += insets.getSystemWindowInsetLeft();
190+
}
191+
}
192+
if (paddingRightSystemWindowInsets) {
193+
if (isRtl) {
194+
initialPadding.start += insets.getSystemWindowInsetRight();
195+
} else {
196+
initialPadding.end += insets.getSystemWindowInsetRight();
197+
}
198+
}
180199
initialPadding.applyToView(view);
181200
return listener != null
182201
? listener.onApplyWindowInsets(view, insets, initialPadding)

lib/java/com/google/android/material/internal/res-public/values/public.xml

+2
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@
1818
<public name="enforceMaterialTheme" type="attr"/>
1919
<public name="insetForeground" type="attr"/>
2020
<public name="paddingBottomSystemWindowInsets" type="attr"/>
21+
<public name="paddingLeftSystemWindowInsets" type="attr"/>
22+
<public name="paddingRightSystemWindowInsets" type="attr"/>
2123
<public name="Widget.Design.ScrimInsetsFrameLayout" type="style"/>
2224
</resources>

lib/java/com/google/android/material/internal/res/values/attrs.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@
5151
</declare-styleable>
5252

5353
<declare-styleable name="Insets">
54-
<!-- Just adding the parameter that we need for now. We can add others if we need them, but
54+
<!-- Just adding the parameters that we need for now. We can add others if we need them, but
5555
ideally we'll be able to use https://github.com/chrisbanes/insetter once it's ready. -->
5656
<attr name="paddingBottomSystemWindowInsets" format="boolean"/>
57+
<attr name="paddingLeftSystemWindowInsets" format="boolean"/>
58+
<attr name="paddingRightSystemWindowInsets" format="boolean"/>
5759
</declare-styleable>
5860

5961
</resources>

0 commit comments

Comments
 (0)