Skip to content

Commit cc09ce8

Browse files
imhappidsn5ft
authored andcommitted
[NavigationRail] Add scrollingEnabled attribute and update NavigationRail to have unlimited items when expanded while keeping the limit of 7 items while collapsed, and add demo to catalog
PiperOrigin-RevId: 676208760
1 parent f9aaf03 commit cc09ce8

File tree

15 files changed

+265
-13
lines changed

15 files changed

+265
-13
lines changed

catalog/java/io/material/catalog/navigationrail/NavigationRailFragment.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ public Fragment createFragment() {
8282
return new NavigationRailAnimatedDemoFragment();
8383
}
8484
});
85+
additionalDemos.add(
86+
new Demo(R.string.cat_navigation_rail_submenus_demo_title) {
87+
@Override
88+
public Fragment createFragment() {
89+
return new NavigationRailSubMenuDemoFragment();
90+
}
91+
});
8592
return additionalDemos;
8693
}
8794

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.material.catalog.navigationrail;
18+
19+
import io.material.catalog.R;
20+
21+
import android.os.Bundle;
22+
import android.view.LayoutInflater;
23+
import android.view.View;
24+
import android.view.ViewGroup;
25+
import androidx.annotation.NonNull;
26+
import androidx.annotation.Nullable;
27+
import com.google.android.material.navigationrail.NavigationRailView;
28+
import io.material.catalog.feature.DemoFragment;
29+
30+
/** A base class that provides a demo screen structure for a single navigation rail demo. */
31+
public class NavigationRailSubMenuDemoFragment extends DemoFragment {
32+
33+
@Nullable NavigationRailView navigationRailView;
34+
35+
@Override
36+
@NonNull
37+
public View onCreateDemoView(
38+
@NonNull LayoutInflater layoutInflater,
39+
@Nullable ViewGroup viewGroup,
40+
@Nullable Bundle bundle) {
41+
View view =
42+
layoutInflater.inflate(
43+
R.layout.cat_navigation_rail_submenus_fragment, viewGroup, /* attachToRoot= */ false);
44+
navigationRailView = view.findViewById(R.id.cat_navigation_rail);
45+
return view;
46+
}
47+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright 2024 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<com.google.android.material.navigationrail.NavigationRailView
18+
xmlns:android="http://schemas.android.com/apk/res/android"
19+
xmlns:app="http://schemas.android.com/apk/res-auto"
20+
android:id="@+id/cat_navigation_rail"
21+
android:layout_width="wrap_content"
22+
android:layout_height="match_parent"
23+
app:labelVisibilityMode="labeled"
24+
android:fitsSystemWindows="false"
25+
app:scrollingEnabled="true"
26+
app:menu="@menu/navigation_rail_submenus_menu"/>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2024 The Android Open Source Project
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
<menu xmlns:android="http://schemas.android.com/apk/res/android">
19+
<item
20+
android:id="@+id/action_page_1"
21+
android:enabled="true"
22+
android:icon="@drawable/ic_star_checkable_24"
23+
android:title="@string/cat_navigation_rail_page_1_name"/>
24+
<item
25+
android:id="@+id/action_page_2"
26+
android:enabled="true"
27+
android:icon="@drawable/ic_star_checkable_24"
28+
android:title="@string/cat_navigation_rail_page_2_name"/>
29+
<item
30+
android:id="@+id/action_page_3"
31+
android:enabled="true"
32+
android:icon="@drawable/ic_star_checkable_24"
33+
android:title="@string/cat_navigation_rail_page_3_name"/>
34+
<item
35+
android:id="@+id/action_page_4"
36+
android:enabled="true"
37+
android:icon="@drawable/ic_star_checkable_24"
38+
android:title="@string/cat_navigation_rail_page_4_name"/>
39+
<item
40+
android:id="@+id/action_page_5"
41+
android:enabled="true"
42+
android:icon="@drawable/ic_star_checkable_24"
43+
android:title="@string/cat_navigation_rail_page_5_name"/>
44+
<item
45+
android:id="@+id/action_page_6"
46+
android:enabled="true"
47+
android:icon="@drawable/ic_star_checkable_24"
48+
android:title="@string/cat_navigation_rail_page_6_name"/>
49+
<item
50+
android:id="@+id/action_page_7"
51+
android:enabled="true"
52+
android:icon="@drawable/ic_star_checkable_24"
53+
android:title="@string/cat_navigation_rail_page_7_name"/>
54+
55+
<item
56+
android:id="@+id/navigation_rail_submenu"
57+
android:title="@string/cat_navigation_rail_subheader_1_name">
58+
<menu>
59+
<item
60+
android:id="@+id/action_page_8"
61+
android:enabled="true"
62+
android:icon="@drawable/ic_star_checkable_24"
63+
android:title="@string/cat_navigation_rail_page_8_name"/>
64+
<item
65+
android:id="@+id/action_page_9"
66+
android:enabled="true"
67+
android:icon="@drawable/ic_star_checkable_24"
68+
android:title="@string/cat_navigation_rail_page_9_name"/>
69+
<item
70+
android:id="@+id/action_page_10"
71+
android:enabled="true"
72+
android:visible="false"
73+
android:icon="@drawable/ic_star_checkable_24"
74+
android:title="@string/cat_navigation_rail_page_10_name"/>
75+
</menu>
76+
</item>
77+
</menu>

catalog/java/io/material/catalog/navigationrail/res/values/strings.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
description="Label the navigation rail demo that shows animated icons [CHAR_LIMIT=100]">Animated Demo</string>
3131
<string name="cat_navigation_rail_compact_demo_title"
3232
description="Label for the demo that shows navigation rail in compact style. [CHAR_LIMIT=100]">Compact Style Demo</string>
33+
<string name="cat_navigation_rail_submenus_demo_title"
34+
description="Label the navigation rail demo that shows a submenu example [CHAR_LIMIT=100]">SubMenu Demo</string>
35+
3336

3437
<string name="cat_navigation_rail_page_1_name"
3538
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 1</string>
@@ -45,6 +48,14 @@
4548
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 6</string>
4649
<string name="cat_navigation_rail_page_7_name"
4750
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 7</string>
51+
<string name="cat_navigation_rail_page_8_name"
52+
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 8</string>
53+
<string name="cat_navigation_rail_page_9_name"
54+
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 9</string>
55+
<string name="cat_navigation_rail_page_10_name"
56+
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 10</string>
57+
<string name="cat_navigation_rail_subheader_1_name"
58+
description="The title of a subheader in the navigation rail demo. [CHAR_LIMIT=50]">Subheader 1</string>
4859

4960
<string name="cat_navigation_rail_add_nav_item"
5061
description="Label for the button that will add a destination to the navigation rail. [CHAR_LIMIT=50]">Add destination</string>

docs/components/NavigationRail.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ The following is an anatomy diagram for the navigation rail:
294294
**Fits system windows** | `android:fitsSystemWindows` | `getFitsSystemWindows`<br/>`setFitsSystemWindows` | `true`
295295
**Padding top system window insets** | `app:paddingTopSystemWindowInsets` | N/A | `null`
296296
**Padding bottom system window insets** | `app:paddingBottomSystemWindowInsets` | N/A | `null`
297+
**Top margin** | `app:contentMarginTop` | N/A | N/A
298+
**Scrolling** | `app:scrollingEnabled` | N/A | `false`
297299

298300
#### Header attributes
299301

@@ -311,7 +313,6 @@ for more attributes.
311313
**Element** | **Attribute** | **Related methods** | **Default value**
312314
---------------- | ---------------------- | ------------------------------------- | -----------------
313315
**Menu gravity** | `app:menuGravity` | `setMenuGravity`<br/>`getMenuGravity` | `TOP\|CENTER_HORIZONTAL`
314-
**Top margin** | `app:contentMarginTop` | N/A | N/A
315316

316317
#### Navigation item attributes
317318

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public final class NavigationBarMenu extends MenuBuilder {
3939

4040
@NonNull private final Class<?> viewClass;
4141
private final int maxItemCount;
42+
43+
/** Constant to indicate there is no limit to the number of Navigation Bar items */
44+
public static final int NO_MAX_ITEM_LIMIT = Integer.MAX_VALUE;
45+
4246
private final boolean subMenuSupported;
4347

4448
public NavigationBarMenu(

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,10 @@ public void buildMenuView() {
11271127
}
11281128
// Add subheader item
11291129
child = new NavigationBarSubheaderView(getContext());
1130+
((NavigationBarSubheaderView) child).
1131+
setTextAppearance(horizontalItemTextAppearanceActive != 0
1132+
? horizontalItemTextAppearanceActive : itemTextAppearanceActive);
1133+
((NavigationBarSubheaderView) child).setTextColor(itemTextColorFromUser);
11301134
child.setOnlyShowWhenExpanded(true);
11311135
child.initialize((MenuItemImpl) menuItem, 0);
11321136
nextSubheaderItemCount = menuItem.getSubMenu().size();

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
2121

2222
import android.content.Context;
23+
import android.content.res.ColorStateList;
2324
import android.graphics.drawable.Drawable;
2425
import androidx.appcompat.view.menu.MenuItemImpl;
2526
import android.view.LayoutInflater;
@@ -28,6 +29,8 @@
2829
import androidx.annotation.NonNull;
2930
import androidx.annotation.Nullable;
3031
import androidx.annotation.RestrictTo;
32+
import androidx.annotation.StyleRes;
33+
import androidx.core.widget.TextViewCompat;
3134

3235
/**
3336
* Provides a view that will be used to render subheader items inside a {@link
@@ -43,6 +46,7 @@ public class NavigationBarSubheaderView extends FrameLayout
4346
boolean onlyShowWhenExpanded;
4447
@Nullable
4548
private MenuItemImpl itemData;
49+
@Nullable private ColorStateList textColor;
4650

4751
NavigationBarSubheaderView(@NonNull Context context) {
4852
super(context);
@@ -59,6 +63,22 @@ public void initialize(@NonNull MenuItemImpl menuItem, int i) {
5963
updateVisibility();
6064
}
6165

66+
public void setTextAppearance(@StyleRes int textAppearance) {
67+
TextViewCompat.setTextAppearance(subheaderLabel, textAppearance);
68+
// Set the text color if the user has set it, since it takes precedence
69+
// over a color set in the text appearance.
70+
if (textColor != null) {
71+
subheaderLabel.setTextColor(textColor);
72+
}
73+
}
74+
75+
public void setTextColor(@Nullable ColorStateList color) {
76+
textColor = color;
77+
if (color != null) {
78+
subheaderLabel.setTextColor(color);
79+
}
80+
}
81+
6282
@Override
6383
@Nullable
6484
public MenuItemImpl getItemData() {

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public NavigationBarView(
208208
// Create the menu view.
209209
menuView = createNavigationBarMenuView(context);
210210
menuView.setMinimumHeight(getSuggestedMinimumHeight());
211-
menuView.setCollapsedMaxItemCount(getMaxItemCount());
211+
menuView.setCollapsedMaxItemCount(getCollapsedMaxItemCount());
212212

213213
presenter.setMenuView(menuView);
214214
presenter.setId(MENU_PRESENTER_ID);
@@ -1174,10 +1174,21 @@ public interface OnItemReselectedListener {
11741174

11751175
/** Returns whether or not submenus are supported. */
11761176
protected boolean isSubMenuSupported() {
1177-
// TODO: b/352634230 - NavigationRail should support submenus once ready
11781177
return false;
11791178
}
11801179

1180+
// TODO: b/361189184 - Make public once expanded state is public
1181+
/**
1182+
* Returns the maximum number of items that can be shown in the collapsed state in
1183+
* NavigationBarView.
1184+
*
1185+
* @hide
1186+
*/
1187+
@RestrictTo(LIBRARY_GROUP)
1188+
public int getCollapsedMaxItemCount() {
1189+
return getMaxItemCount();
1190+
}
1191+
11811192
/**
11821193
* Returns reference to a newly created {@link NavigationBarMenuView}
11831194
*

lib/java/com/google/android/material/navigation/res/layout/m3_navigation_menu_subheader.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,5 @@
2424
android:layout_marginTop="@dimen/m3_navigation_subheader_top_margin"
2525
android:gravity="center_vertical|start"
2626
android:ellipsize="end"
27-
android:textAppearance="?attr/textAppearanceLabelMedium"
2827
android:filterTouchesWhenObscured="true"
2928
android:maxLines="1"/>

lib/java/com/google/android/material/navigationrail/NavigationRailFrameLayout.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
public class NavigationRailFrameLayout extends FrameLayout {
3535

3636
int paddingTop = 0;
37+
boolean scrollingEnabled = false;
3738

3839
public NavigationRailFrameLayout(@NonNull Context context) {
3940
super(context);
@@ -43,6 +44,10 @@ public void setPaddingTop(int paddingTop) {
4344
this.paddingTop = paddingTop;
4445
}
4546

47+
public void setScrollingEnabled(boolean scrollingEnabled) {
48+
this.scrollingEnabled = scrollingEnabled;
49+
}
50+
4651
@Override
4752
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
4853
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -63,7 +68,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
6368

6469
// Measure menu
6570
menuView = getChildAt(1);
66-
menuHeightSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
71+
// If scrolling is not enabled, we try to measure the menu such that it'll fit in the
72+
// remaining space
73+
if (!scrollingEnabled) {
74+
menuHeightSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
75+
}
6776
}
6877
LayoutParams menuLp = (LayoutParams) menuView.getLayoutParams();
6978
measureChild(menuView, widthMeasureSpec, menuHeightSpec);

0 commit comments

Comments
 (0)