Skip to content

Commit

Permalink
[NavigationRail][Badge] Added bigger padding in between items on the …
Browse files Browse the repository at this point in the history
…navigation rail when font scale is large so there is more room for the badges when they are forced inside the view bounds

Also fixed bug with navigation rail items moving when there is a badge vs when there is no longer a badge, and adds 4dp padding between icon container/active indicator and label text as per specs https://m3.material.io/components/navigation-rail/overview

PiperOrigin-RevId: 540349399
  • Loading branch information
imhappi authored and hunterstich committed Jun 14, 2023
1 parent 45c8d42 commit 8b016a0
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 16 deletions.
15 changes: 8 additions & 7 deletions docs/components/NavigationRail.md
Expand Up @@ -311,13 +311,14 @@ for more attributes.

#### Active indicator attributes

**Element** | **Attribute** | **Related methods** | **Default value**
--------------------- | ---------------------- | ------------------------------------------------------------------------------------- | -----------------
**Color** | `android:color` | `setItemActiveIndicatorColor`<br/>`getItemActiveIndicatorColor` | `?attr/colorSecondaryContainer`
**Width** | `android:width` | `setItemActiveIndicatorWidth`<br/>`getItemActiveIndicatorWidth` | `56dp`
**Height** | `android:height` | `setItemActiveIndicatorHeight`<br/>`setItemActiveIndicatorHeight` | `32dp`
**Shape** | `app:shapeAppearance` | `setItemActiveIndicatorShapeAppearance`<br/>`getItemActiveIndicatorShapeAppearance` | `50% rounded`
**Margin horizontal** | `app:marginHorizontal` | `setItemActiveIndicatorMarginHorizontal`<br/>`getItemActiveIndicatorMarginHorizontal` | `4dp`
**Element** | **Attribute** | **Related methods** | **Default value**
--------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- | -----------------
**Color** | `android:color` | `setItemActiveIndicatorColor`<br/>`getItemActiveIndicatorColor` | `?attr/colorSecondaryContainer`
**Width** | `android:width` | `setItemActiveIndicatorWidth`<br/>`getItemActiveIndicatorWidth` | `56dp`
**Height** | `android:height` | `setItemActiveIndicatorHeight`<br/>`setItemActiveIndicatorHeight` | `32dp`
**Shape** | `app:shapeAppearance` | `setItemActiveIndicatorShapeAppearance`<br/>`getItemActiveIndicatorShapeAppearance` | `50% rounded`
**Margin horizontal** | `app:marginHorizontal` | `setItemActiveIndicatorMarginHorizontal`<br/>`getItemActiveIndicatorMarginHorizontal` | `4dp`
**Padding between indicator and label** | `app:activeIndicatorLabelPadding` | `setActiveIndicatorLabelPadding` <br/> `setActiveIndicatorLabelPadding` | `4dp`

#### Icon attributes

Expand Down
Expand Up @@ -87,6 +87,7 @@ public abstract class NavigationBarItemView extends FrameLayout implements MenuV
@Nullable Drawable itemBackground;
private int itemPaddingTop;
private int itemPaddingBottom;
private int activeIndicatorLabelPadding;
private float shiftAmount;
private float scaleUpFactor;
private float scaleDownFactor;
Expand Down Expand Up @@ -146,6 +147,7 @@ public NavigationBarItemView(@NonNull Context context) {

itemPaddingTop = getResources().getDimensionPixelSize(getItemDefaultMarginResId());
itemPaddingBottom = labelGroup.getPaddingBottom();
activeIndicatorLabelPadding = getResources().getDimensionPixelSize(R.dimen.m3_navigation_item_active_indicator_label_padding);

// The labels used aren't always visible, so they are unreliable for accessibility. Instead,
// the content description of the NavigationBarItemView should be used for accessibility.
Expand Down Expand Up @@ -190,6 +192,7 @@ protected int getSuggestedMinimumWidth() {
protected int getSuggestedMinimumHeight() {
LayoutParams labelGroupParams = (LayoutParams) labelGroup.getLayoutParams();
return getSuggestedIconHeight()
+ (labelGroup.getVisibility() == VISIBLE ? activeIndicatorLabelPadding : 0)
+ labelGroupParams.topMargin
+ labelGroup.getMeasuredHeight()
+ labelGroupParams.bottomMargin;
Expand Down Expand Up @@ -785,6 +788,14 @@ public void setItemPaddingBottom(int paddingBottom) {
}
}

/** Set the padding between the active indicator container and the item label. */
public void setActiveIndicatorLabelPadding(int activeIndicatorLabelPadding) {
if (this.activeIndicatorLabelPadding != activeIndicatorLabelPadding) {
this.activeIndicatorLabelPadding = activeIndicatorLabelPadding;
refreshChecked();
}
}

/** Set whether or not this item should show an active indicator when checked. */
public void setActiveIndicatorEnabled(boolean enabled) {
this.activeIndicatorEnabled = enabled;
Expand Down Expand Up @@ -983,16 +994,9 @@ private int getSuggestedIconWidth() {
}

private int getSuggestedIconHeight() {
int badgeHeight = 0;
if (badgeDrawable != null) {
badgeHeight = badgeDrawable.getMinimumHeight() / 2;
}

// Account for the fact that the badge may fit within the top margin. Bottom margin is ignored
// because the icon view will be aligned to the baseline of the label group. But give space for
// the badge at the bottom as well, so that icon does not move if badge gravity is changed.
LayoutParams iconContainerParams = (LayoutParams) getIconOrContainer().getLayoutParams();
return max(badgeHeight, iconContainerParams.topMargin) + icon.getMeasuredWidth() + badgeHeight;
return iconContainerParams.topMargin
+ getIconOrContainer().getMeasuredHeight();
}

/**
Expand Down
Expand Up @@ -97,6 +97,7 @@ public abstract class NavigationBarMenuView extends ViewGroup implements MenuVie
new SparseArray<>(ITEM_POOL_SIZE);
private int itemPaddingTop = NO_PADDING;
private int itemPaddingBottom = NO_PADDING;
private int itemActiveIndicatorLabelPadding = NO_PADDING;
private boolean itemActiveIndicatorEnabled;
private int itemActiveIndicatorWidth;
private int itemActiveIndicatorHeight;
Expand Down Expand Up @@ -366,6 +367,26 @@ public void setItemPaddingBottom(@Px int paddingBottom) {
}
}

/**
* Get the distance between the item's active indicator container and the label.
*/
@Px
public int getActiveIndicatorLabelPadding() {
return itemActiveIndicatorLabelPadding;
}

/**
* Set the distance between the active indicator container and the item's label.
*/
public void setActiveIndicatorLabelPadding(@Px int activeIndicatorLabelPadding) {
itemActiveIndicatorLabelPadding = activeIndicatorLabelPadding;
if (buttons != null) {
for (NavigationBarItemView item : buttons) {
item.setActiveIndicatorLabelPadding(activeIndicatorLabelPadding);
}
}
}

/**
* Returns whether or not an active indicator is enabled for the navigation bar.
*
Expand Down Expand Up @@ -733,6 +754,9 @@ public void buildMenuView() {
if (itemPaddingBottom != NO_PADDING) {
child.setItemPaddingBottom(itemPaddingBottom);
}
if (itemActiveIndicatorLabelPadding != NO_PADDING) {
child.setActiveIndicatorLabelPadding(itemActiveIndicatorLabelPadding);
}
child.setActiveIndicatorWidth(itemActiveIndicatorWidth);
child.setActiveIndicatorHeight(itemActiveIndicatorHeight);
child.setActiveIndicatorMarginHorizontal(itemActiveIndicatorMarginHorizontal);
Expand Down
Expand Up @@ -211,6 +211,11 @@ public NavigationBarView(
attributes.getDimensionPixelSize(R.styleable.NavigationBarView_itemPaddingBottom, 0));
}

if (attributes.hasValue(R.styleable.NavigationBarView_activeIndicatorLabelPadding)) {
setActiveIndicatorLabelPadding(
attributes.getDimensionPixelSize(R.styleable.NavigationBarView_activeIndicatorLabelPadding, 0));
}

if (attributes.hasValue(R.styleable.NavigationBarView_elevation)) {
setElevation(attributes.getDimensionPixelSize(R.styleable.NavigationBarView_elevation, 0));
}
Expand Down Expand Up @@ -575,6 +580,21 @@ public void setItemPaddingBottom(@Px int paddingBottom) {
menuView.setItemPaddingBottom(paddingBottom);
}

/**
* Set the distance between the active indicator container and the item's label.
*/
public void setActiveIndicatorLabelPadding(@Px int activeIndicatorLabelPadding) {
menuView.setActiveIndicatorLabelPadding(activeIndicatorLabelPadding);
}

/**
* Get the distance between the active indicator container and the item's label.
*/
@Px
public int getActiveIndicatorLabelPadding() {
return menuView.getActiveIndicatorLabelPadding();
}

/**
* Get whether or not a selected item should show an active indicator.
*
Expand Down
Expand Up @@ -51,6 +51,7 @@
<public name="ThemeOverlay.Material3.NavigationView" type="style"/>
<public name="Widget.Material3.DrawerLayout" type="style"/>

<public name="activeIndicatorLabelPadding" type="attr"/>
<public name="itemPaddingTop" type="attr"/>
<public name="itemPaddingBottom" type="attr"/>
<public name="itemActiveIndicatorStyle" type="attr"/>
Expand Down
Expand Up @@ -72,6 +72,8 @@
<!-- The distance from the bottom of the label to the bottom of the navigation
bar item.-->
<attr name="itemPaddingBottom" format="dimension"/>
<!-- Padding between the active indicator container and label. -->
<attr name="activeIndicatorLabelPadding" format="dimension"/>

<!-- The style used for each navigation item's active indicator-->
<attr name="itemActiveIndicatorStyle" format="reference"/>
Expand Down
Expand Up @@ -43,5 +43,6 @@
<dimen name="m3_navigation_menu_divider_horizontal_padding">28dp</dimen>
<dimen name="m3_navigation_menu_headline_horizontal_padding">28dp</dimen>
<dimen name="m3_navigation_drawer_layout_corner_size">16dp</dimen>
<dimen name="m3_navigation_item_active_indicator_label_padding">4dp</dimen>
</resources>

Expand Up @@ -80,6 +80,7 @@
<item name="subheaderInsetStart">@dimen/m3_navigation_menu_headline_horizontal_padding</item>
<item name="subheaderInsetEnd">@dimen/m3_navigation_menu_headline_horizontal_padding</item>
<item name="drawerLayoutCornerSize">@dimen/m3_navigation_drawer_layout_corner_size</item>
<item name="activeIndicatorLabelPadding">@dimen/m3_navigation_item_active_indicator_label_padding</item>
</style>

<style name="ShapeAppearanceOverlay.Material3.NavigationView.Item"
Expand Down
Expand Up @@ -38,10 +38,12 @@
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.animation.AnimationUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.internal.ViewUtils;
import com.google.android.material.internal.ViewUtils.RelativePadding;
import com.google.android.material.navigation.NavigationBarView;
import com.google.android.material.resources.MaterialResources;

/**
* Represents a standard navigation rail view for application. It is an implementation of <a
Expand Down Expand Up @@ -165,6 +167,21 @@ public NavigationRailView(
R.styleable.NavigationRailView_paddingStartSystemWindowInsets, false);
}

int largeFontTopPadding =
getResources()
.getDimensionPixelOffset(R.dimen.m3_navigation_rail_item_padding_top_with_large_font);
int largeFontBottomPadding =
getResources()
.getDimensionPixelOffset(
R.dimen.m3_navigation_rail_item_padding_bottom_with_large_font);
float progress =
AnimationUtils.lerp(0F, 1F, .3F, 1F, MaterialResources.getFontScale(context) - 1F);
float topPadding = AnimationUtils.lerp(getItemPaddingTop(), largeFontTopPadding, progress);
float bottomPadding =
AnimationUtils.lerp(getItemPaddingBottom(), largeFontBottomPadding, progress);
setItemPaddingTop(Math.round(topPadding));
setItemPaddingBottom(Math.round(bottomPadding));

attributes.recycle();

applyWindowInsets();
Expand Down
Expand Up @@ -31,8 +31,11 @@
<dimen name="m3_navigation_rail_default_width">@dimen/m3_comp_navigation_rail_container_width</dimen>
<dimen name="m3_navigation_rail_item_min_height">60dp</dimen>
<dimen name="m3_navigation_rail_item_padding_top">4dp</dimen>
<dimen name="m3_navigation_rail_item_padding_top_with_large_font">12dp</dimen>
<dimen name="m3_navigation_rail_item_padding_bottom_with_large_font">16dp</dimen>
<dimen name="m3_navigation_rail_item_padding_bottom">8dp</dimen>
<dimen name="m3_navigation_rail_item_active_indicator_width">@dimen/m3_comp_navigation_rail_active_indicator_width</dimen>
<dimen name="m3_navigation_rail_item_active_indicator_height">@dimen/m3_comp_navigation_rail_active_indicator_height</dimen>
<dimen name="m3_navigation_rail_item_active_indicator_margin_horizontal">4dp</dimen>

</resources>
Expand Up @@ -81,6 +81,7 @@
<item name="itemMinHeight">@dimen/m3_navigation_rail_item_min_height</item>
<item name="itemTextAppearanceInactive">@macro/m3_comp_navigation_rail_label_text_type</item>
<item name="itemTextAppearanceActive">@macro/m3_comp_navigation_rail_label_text_type</item>
<item name="materialThemeOverlay">@style/ThemeOverlay.Material3.NavigationRailView</item>
</style>

<style name="Widget.Material3.NavigationRailView.ActiveIndicator" parent="">
Expand All @@ -91,4 +92,8 @@
<item name="android:color">@macro/m3_comp_navigation_rail_active_indicator_color</item>
</style>

<style name="ThemeOverlay.Material3.NavigationRailView" parent="">
<item name="badgeStyle">@style/Widget.Material3.Badge.AdjustToBounds</item>
</style>

</resources>
Expand Up @@ -195,6 +195,13 @@ public static boolean isFontScaleAtLeast2_0(@NonNull Context context) {
return context.getResources().getConfiguration().fontScale >= FONT_SCALE_2_0;
}

/**
* Returns the font scale size.
*/
public static float getFontScale(@NonNull Context context) {
return context.getResources().getConfiguration().fontScale;
}

/**
* Return the {@code R.styleable.TextAppearance_android_textSize} value from a text appearance
* style at its density scaled value only.
Expand Down

0 comments on commit 8b016a0

Please sign in to comment.