Skip to content

Commit b184df6

Browse files
imhappidrchen
authored andcommitted
[NavigationBar] Add active indicator attributes to change active indicator height, width, and horizontal margins when it is in an expanded state (ie. when start icon gravity is set to 'start')
PiperOrigin-RevId: 657266378
1 parent 3ea7709 commit b184df6

File tree

12 files changed

+322
-18
lines changed

12 files changed

+322
-18
lines changed

docs/components/BottomNavigation.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,25 @@ The following is an anatomy diagram for the bottom navigation bar:
277277
**Ripple (active)** | " | " | Variations of `?attr/colorPrimary` (see all [states](https://github.com/material-components/material-components-android/tree/master/lib/java/com/google/android/material/bottomnavigation/res/color/m3_navigation_bar_ripple_color_selector.xml))
278278
**Label visibility mode** | `app:labelVisibilityMode` | `setLabelVisibilityMode`<br/>`getLabelVisibilityMode` | `LABEL_VISIBILITY_AUTO`
279279

280+
281+
#### Active indicator attributes
282+
283+
**Element** | **Attribute** | **Related methods** | **Default value**
284+
--------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------- | -----------------
285+
**Color** | `android:color` | `setItemActiveIndicatorColor`<br/>`getItemActiveIndicatorColor` | `?attr/colorSecondaryContainer`
286+
**Width** | `android:width` | `setItemActiveIndicatorWidth`<br/>`getItemActiveIndicatorWidth` | `56dp`
287+
**Height** | `android:height` | `setItemActiveIndicatorHeight`<br/>`getItemActiveIndicatorHeight` | `32dp`
288+
**Shape** | `app:shapeAppearance` | `setItemActiveIndicatorShapeAppearance`<br/>`getItemActiveIndicatorShapeAppearance` | `50% rounded`
289+
**Margin horizontal** | `app:marginHorizontal` | `setItemActiveIndicatorMarginHorizontal`<br/>`getItemActiveIndicatorMarginHorizontal` | `4dp`
290+
**Padding between indicator and label** | `app:activeIndicatorLabelPadding` | `setActiveIndicatorLabelPadding` <br/> `getActiveIndicatorLabelPadding` | `4dp`
291+
**Expanded Width** | `expandedWidth` | `setItemExpandedActiveIndicatorWidth`<br/>`getItemExpandedActiveIndicatorWidth` | `HUG`
292+
**Expanded Height** | `expandedHeight` | `setItemExpandedActiveIndicatorHeight`<br/>`getItemExpandedActiveIndicatorHeight` | `56dp`
293+
**Expanded Margin horizontal** | `app:expandedMarginHorizontal` | `setItemExpandedActiveIndicatorMarginHorizontal`<br/>`getItemExpandedActiveIndicatorMarginHorizontal` | `20dp`
294+
295+
**Note:** The expanded active indicator refers to the active indicator that
296+
expands to wrap the content of the Bottom Navigation item when the
297+
`itemIconGravity` value is equal to `START`.
298+
280299
#### Icon attributes
281300

282301
**Element** | **Attribute** | **Related methods** | **Default value**

docs/components/NavigationRail.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,21 @@ for more attributes.
328328

329329
#### Active indicator attributes
330330

331-
**Element** | **Attribute** | **Related methods** | **Default value**
332-
--------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- | -----------------
333-
**Color** | `android:color` | `setItemActiveIndicatorColor`<br/>`getItemActiveIndicatorColor` | `?attr/colorSecondaryContainer`
334-
**Width** | `android:width` | `setItemActiveIndicatorWidth`<br/>`getItemActiveIndicatorWidth` | `56dp`
335-
**Height** | `android:height` | `setItemActiveIndicatorHeight`<br/>`setItemActiveIndicatorHeight` | `32dp`
336-
**Shape** | `app:shapeAppearance` | `setItemActiveIndicatorShapeAppearance`<br/>`getItemActiveIndicatorShapeAppearance` | `50% rounded`
337-
**Margin horizontal** | `app:marginHorizontal` | `setItemActiveIndicatorMarginHorizontal`<br/>`getItemActiveIndicatorMarginHorizontal` | `4dp`
338-
**Padding between indicator and label** | `app:activeIndicatorLabelPadding` | `setActiveIndicatorLabelPadding` <br/> `setActiveIndicatorLabelPadding` | `4dp`
331+
**Element** | **Attribute** | **Related methods** | **Default value**
332+
--------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------- | -----------------
333+
**Color** | `android:color` | `setItemActiveIndicatorColor`<br/>`getItemActiveIndicatorColor` | `?attr/colorSecondaryContainer`
334+
**Width** | `android:width` | `setItemActiveIndicatorWidth`<br/>`getItemActiveIndicatorWidth` | `56dp`
335+
**Height** | `android:height` | `setItemActiveIndicatorHeight`<br/>`getItemActiveIndicatorHeight` | `32dp`
336+
**Shape** | `app:shapeAppearance` | `setItemActiveIndicatorShapeAppearance`<br/>`getItemActiveIndicatorShapeAppearance` | `50% rounded`
337+
**Margin horizontal** | `app:marginHorizontal` | `setItemActiveIndicatorMarginHorizontal`<br/>`getItemActiveIndicatorMarginHorizontal` | `4dp`
338+
**Padding between indicator and label** | `app:activeIndicatorLabelPadding` | `setActiveIndicatorLabelPadding` <br/> `getActiveIndicatorLabelPadding` | `4dp`
339+
**Expanded Width** | `expandedWidth` | `setItemExpandedActiveIndicatorWidth`<br/>`getItemExpandedActiveIndicatorWidth` | `HUG`
340+
**Expanded Height** | `expandedHeight` | `setItemExpandedActiveIndicatorHeight`<br/>`getItemExpandedActiveIndicatorHeight` | `56dp`
341+
**Expanded Margin horizontal** | `app:expandedMarginHorizontal` | `setItemExpandedActiveIndicatorMarginHorizontal`<br/>`getItemExpandedActiveIndicatorMarginHorizontal` | `20dp`
342+
343+
**Note:** The expanded active indicator refers to the active indicator that
344+
expands to wrap the content of the Navigation Rail item when the
345+
`itemIconGravity` value is equal to `START`.
339346

340347
#### Icon attributes
341348

lib/java/com/google/android/material/bottomnavigation/res/values/dimens.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@
3737
<dimen name="m3_bottom_nav_item_active_indicator_height">@dimen/m3_comp_navigation_bar_active_indicator_height</dimen>
3838
<dimen name="m3_bottom_nav_item_active_indicator_margin_horizontal">4dp</dimen>
3939

40+
<dimen name="m3_expressive_item_expanded_active_indicator_height">40dp</dimen>
4041
</resources>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,6 @@
105105
<item name="marginHorizontal">@dimen/m3_bottom_nav_item_active_indicator_margin_horizontal</item>
106106
<item name="shapeAppearance">@style/ShapeAppearance.M3.Comp.NavigationBar.ActiveIndicator.Shape</item>
107107
<item name="android:color">@macro/m3_comp_navigation_bar_active_indicator_color</item>
108+
<item name="expandedHeight">@dimen/m3_expressive_item_expanded_active_indicator_height</item>
108109
</style>
109110
</resources>

lib/java/com/google/android/material/navigation/NavigationBarItemView.java

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.google.android.material.R;
2020

2121
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
22+
import static com.google.android.material.navigation.NavigationBarView.ACTIVE_INDICATOR_WIDTH_MATCH_PARENT;
23+
import static com.google.android.material.navigation.NavigationBarView.ACTIVE_INDICATOR_WIDTH_WRAP_CONTENT;
2224
import static com.google.android.material.navigation.NavigationBarView.ITEM_ICON_GRAVITY_START;
2325
import static com.google.android.material.navigation.NavigationBarView.ITEM_ICON_GRAVITY_TOP;
2426
import static java.lang.Math.max;
@@ -132,11 +134,14 @@ public abstract class NavigationBarItemView extends FrameLayout implements MenuV
132134
// desired width.
133135
private int activeIndicatorDesiredWidth = 0;
134136
private int activeIndicatorDesiredHeight = 0;
137+
private int activeIndicatorExpandedDesiredWidth = ACTIVE_INDICATOR_WIDTH_WRAP_CONTENT;
138+
private int activeIndicatorExpandedDesiredHeight = 0;
135139
private boolean activeIndicatorResizeable = false;
136140
// The margin from the start and end of this view which the active indicator should respect. If
137141
// the indicator width is greater than the total width minus the horizontal margins, the active
138142
// indicator will assume the max width of the view's total width minus horizontal margins.
139143
private int activeIndicatorMarginHorizontal = 0;
144+
private int activeIndicatorExpandedMarginHorizontal = 0;
140145

141146
@Nullable private BadgeDrawable badgeDrawable;
142147

@@ -169,6 +174,8 @@ public NavigationBarItemView(@NonNull Context context) {
169174
largeLabel.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
170175
setFocusable(true);
171176
calculateTextScaleFactors(smallLabel.getTextSize(), largeLabel.getTextSize());
177+
activeIndicatorExpandedDesiredHeight = getResources().getDimensionPixelSize(
178+
R.dimen.m3_expressive_item_expanded_active_indicator_height_default);
172179

173180
// TODO(b/138148581): Support displaying a badge on label-only bottom navigation views.
174181
innerContentContainer.addOnLayoutChangeListener(
@@ -178,7 +185,8 @@ public NavigationBarItemView(@NonNull Context context) {
178185
}
179186
// If item icon gravity is start, we want to update the active indicator width in a layout
180187
// change listener to keep the active indicator size up to date with the content width.
181-
if (itemIconGravity == ITEM_ICON_GRAVITY_START) {
188+
if (itemIconGravity == ITEM_ICON_GRAVITY_START
189+
&& activeIndicatorExpandedDesiredWidth == ACTIVE_INDICATOR_WIDTH_WRAP_CONTENT) {
182190
LayoutParams lp = (LayoutParams) innerContentContainer.getLayoutParams();
183191
int newWidth = right - left + lp.rightMargin + lp.leftMargin;
184192
LayoutParams indicatorParams = (LayoutParams) activeIndicatorView.getLayoutParams();
@@ -289,16 +297,18 @@ private void updateItemIconGravity() {
289297
int labelGroupTopMargin = activeIndicatorLabelPadding;
290298
int labelGroupSideMargin = 0;
291299
int sidePadding = 0;
300+
int contentGravity = Gravity.CENTER;
292301
badgeFixedEdge = BadgeDrawable.BADGE_FIXED_EDGE_START;
293302
if (itemIconGravity == ITEM_ICON_GRAVITY_START) {
294303
gravity = Gravity.CENTER;
304+
contentGravity = Gravity.START | Gravity.CENTER_VERTICAL;
295305
sideMargin =
296306
getResources()
297307
.getDimensionPixelSize(R.dimen.m3_expressive_navigation_item_leading_trailing_space);
298308
labelGroupTopMargin = 0;
299309
labelGroupSideMargin = activeIndicatorLabelPadding;
300310
badgeFixedEdge = BadgeDrawable.BADGE_FIXED_EDGE_END;
301-
sidePadding = activeIndicatorMarginHorizontal;
311+
sidePadding = activeIndicatorExpandedMarginHorizontal;
302312
if (labelGroup.getParent() != innerContentContainer) {
303313
contentContainer.removeView(labelGroup);
304314
innerContentContainer.addView(labelGroup);
@@ -313,6 +323,7 @@ private void updateItemIconGravity() {
313323
(LayoutParams) innerContentContainer.getLayoutParams();
314324
innerContentLp.leftMargin = sideMargin;
315325
innerContentLp.rightMargin = sideMargin;
326+
innerContentLp.gravity = contentGravity;
316327
LinearLayout.LayoutParams labelGroupLp =
317328
(LinearLayout.LayoutParams) labelGroup.getLayoutParams();
318329
labelGroupLp.rightMargin =
@@ -458,6 +469,13 @@ private void setLayoutConfigurationIconAndLabel(
458469
itemIconGravity == ITEM_ICON_GRAVITY_TOP
459470
? Gravity.CENTER_HORIZONTAL | Gravity.TOP
460471
: Gravity.CENTER);
472+
setViewMarginAndGravity(
473+
innerContentContainer,
474+
0,
475+
0,
476+
itemIconGravity == ITEM_ICON_GRAVITY_TOP
477+
? Gravity.CENTER
478+
: Gravity.START | Gravity.CENTER_VERTICAL);
461479
updateViewPaddingBottom(
462480
labelGroup, itemIconGravity == ITEM_ICON_GRAVITY_TOP ? itemPaddingBottom : 0);
463481
labelGroup.setVisibility(VISIBLE);
@@ -467,6 +485,7 @@ private void setLayoutConfigurationIconAndLabel(
467485

468486
private void setLayoutConfigurationIconOnly() {
469487
setViewMarginAndGravity(contentContainer, itemPaddingTop, itemPaddingTop, Gravity.CENTER);
488+
setViewMarginAndGravity(innerContentContainer, 0, 0, Gravity.CENTER);
470489
updateViewPaddingBottom(labelGroup, 0);
471490
labelGroup.setVisibility(GONE);
472491
}
@@ -865,6 +884,28 @@ public void setActiveIndicatorWidth(int width) {
865884
updateActiveIndicatorLayoutParams(getWidth());
866885
}
867886

887+
/**
888+
* Set the height of the active indicator when it is expanded, ie. the item icon width is set to
889+
* {@link ItemIconGravity#ITEM_ICON_GRAVITY_START}.
890+
*
891+
* @param width The width of the active indicator.
892+
*/
893+
public void setActiveIndicatorExpandedWidth(int width) {
894+
this.activeIndicatorExpandedDesiredWidth = width;
895+
updateActiveIndicatorLayoutParams(getWidth());
896+
}
897+
898+
/**
899+
* Set the height of the active indicator when it is expanded, ie. the item icon width is set to *
900+
* {@link ItemIconGravity#ITEM_ICON_GRAVITY_START}.
901+
*
902+
* @param height The height of the active indicator.
903+
*/
904+
public void setActiveIndicatorExpandedHeight(int height) {
905+
this.activeIndicatorExpandedDesiredHeight = height;
906+
updateActiveIndicatorLayoutParams(getWidth());
907+
}
908+
868909
/**
869910
* Update the active indicators width and height for the available width and label visibility
870911
* mode.
@@ -882,10 +923,15 @@ private void updateActiveIndicatorLayoutParams(int availableWidth) {
882923
min(activeIndicatorDesiredWidth, availableWidth - (activeIndicatorMarginHorizontal * 2));
883924
int newHeight = activeIndicatorDesiredHeight;
884925
if (itemIconGravity == ITEM_ICON_GRAVITY_START) {
885-
newWidth = max(contentContainer.getMeasuredWidth(), newWidth);
886-
newHeight =
887-
getResources()
888-
.getDimensionPixelSize(R.dimen.m3_expressive_horizontal_item_active_indicator_height);
926+
int adjustedAvailableWidth = availableWidth - (activeIndicatorExpandedMarginHorizontal * 2);
927+
if (activeIndicatorExpandedDesiredWidth == ACTIVE_INDICATOR_WIDTH_MATCH_PARENT) {
928+
newWidth = adjustedAvailableWidth;
929+
} else if (activeIndicatorExpandedDesiredWidth == ACTIVE_INDICATOR_WIDTH_WRAP_CONTENT) {
930+
newWidth = contentContainer.getMeasuredWidth();
931+
} else {
932+
newWidth = min(activeIndicatorExpandedDesiredWidth, adjustedAvailableWidth);
933+
}
934+
newHeight = activeIndicatorExpandedDesiredHeight;
889935
}
890936
LayoutParams indicatorParams = (LayoutParams) activeIndicatorView.getLayoutParams();
891937
// If the label visibility is unlabeled, make the active indicator's height equal to its
@@ -921,6 +967,19 @@ public void setActiveIndicatorHeight(int height) {
921967
*/
922968
public void setActiveIndicatorMarginHorizontal(@Px int marginHorizontal) {
923969
this.activeIndicatorMarginHorizontal = marginHorizontal;
970+
updateActiveIndicatorLayoutParams(getWidth());
971+
}
972+
973+
/**
974+
* Set the horizontal margin that will be maintained at the start and end of the expanded active
975+
* indicator, making sure the indicator remains the given distance from the edge of this item
976+
* view.
977+
*
978+
* @see #updateActiveIndicatorLayoutParams(int)
979+
* @param marginHorizontal The horizontal margin, in pixels.
980+
*/
981+
public void setActiveIndicatorExpandedMarginHorizontal(@Px int marginHorizontal) {
982+
this.activeIndicatorExpandedMarginHorizontal = marginHorizontal;
924983
if (itemIconGravity == ITEM_ICON_GRAVITY_START) {
925984
setPadding(marginHorizontal, 0, marginHorizontal, 0);
926985
}

0 commit comments

Comments
 (0)