Skip to content

Commit

Permalink
[NavigationRail] Navigation rail expansion
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 689848271
  • Loading branch information
imhappi authored and kendrickumstattd committed Oct 25, 2024
1 parent 2e95296 commit 08c23dc
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@
import io.material.catalog.R;

import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
import com.google.android.material.navigationrail.NavigationRailView;
import com.google.android.material.snackbar.Snackbar;
import io.material.catalog.feature.DemoFragment;

/** A base class that provides a demo screen structure for a single navigation rail demo. */
Expand All @@ -42,6 +48,39 @@ public View onCreateDemoView(
layoutInflater.inflate(
R.layout.cat_navigation_rail_submenus_fragment, viewGroup, /* attachToRoot= */ false);
navigationRailView = view.findViewById(R.id.cat_navigation_rail);
// Add extended floating action button
navigationRailView.addHeaderView(R.layout.cat_navigation_rail_efab_header_view);
FrameLayout.LayoutParams lp =
(LayoutParams) navigationRailView.getHeaderView().getLayoutParams();
lp.gravity = Gravity.START;
navigationRailView.getHeaderView().
findViewById(R.id.cat_navigation_rail_efab_container)
.setPadding(
navigationRailView.getItemActiveIndicatorExpandedMarginHorizontal(),
0,
navigationRailView.getItemActiveIndicatorExpandedMarginHorizontal(),
0);

ExtendedFloatingActionButton efab =
navigationRailView.getHeaderView().findViewById(R.id.cat_navigation_rail_efab);
efab.setAnimationEnabled(false);
efab.setExtended(false);
efab.setOnClickListener(v ->
Snackbar.make(v, R.string.cat_navigation_rail_efab_message, Snackbar.LENGTH_SHORT)
.show());

ImageView button =
navigationRailView.getHeaderView().findViewById(R.id.cat_navigation_rail_expand_button);
button.setOnClickListener(
v -> {
if (efab.isExtended()) {
efab.shrink();
navigationRailView.collapse();
} else {
efab.extend();
navigationRailView.expand();
}
});
return view;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/cat_navigation_rail_efab_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_gravity="top|start">
<ImageView
android:id="@+id/cat_navigation_rail_expand_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_drawer_menu_24px"
android:contentDescription="@null"
android:scaleType="center" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/cat_navigation_rail_efab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_add_24px"
android:text="@string/cat_navigation_rail_efab_text"/>
</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,29 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<com.google.android.material.navigationrail.NavigationRailView
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cat_navigation_rail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:labelVisibilityMode="labeled"
android:fitsSystemWindows="false"
app:scrollingEnabled="true"
app:menu="@menu/navigation_rail_submenus_menu"/>
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/cat_navigation_rail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:labelVisibilityMode="labeled"
android:fitsSystemWindows="false"
app:scrollingEnabled="true"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/navigation_rail_submenus_menu"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintStart_toEndOf="@id/cat_navigation_rail"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/cat_navigation_rail_center_text"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,26 @@
android:title="@string/cat_navigation_rail_page_10_name"/>
</menu>
</item>

<item
android:title="@string/cat_navigation_rail_subheader_2_name">
<menu>
<item
android:id="@+id/action_page_11"
android:enabled="true"
android:icon="@drawable/ic_star_checkable_24"
android:title="@string/cat_navigation_rail_page_11_name"/>
</menu>
</item>

<item
android:title="@string/cat_navigation_rail_subheader_3_name">
<menu>
<item
android:id="@+id/action_page_12"
android:enabled="true"
android:icon="@drawable/ic_star_checkable_24"
android:title="@string/cat_navigation_rail_page_12_name"/>
</menu>
</item>
</menu>
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,17 @@
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 9</string>
<string name="cat_navigation_rail_page_10_name"
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 10</string>

<string name="cat_navigation_rail_page_11_name"
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 11</string>
<string name="cat_navigation_rail_page_12_name"
description="The title of a page in the navigation rail demo. [CHAR_LIMIT=50]">Page 12</string>
<string name="cat_navigation_rail_subheader_1_name"
description="The title of a subheader in the navigation rail demo. [CHAR_LIMIT=50]">Subheader 1</string>
<string name="cat_navigation_rail_subheader_2_name"
description="The title of a subheader in the navigation rail demo. [CHAR_LIMIT=50]">Subheader 2</string>
<string name="cat_navigation_rail_subheader_3_name"
description="The title of a subheader in the navigation rail demo. [CHAR_LIMIT=50]">Subheader 3</string>

<string name="cat_navigation_rail_add_nav_item"
description="Label for the button that will add a destination to the navigation rail. [CHAR_LIMIT=50]">Add destination</string>
Expand Down Expand Up @@ -116,4 +125,10 @@
description="Content description for a floating action button in the navigation rail.[CHAR_LIMIT=50]">Navigation Rail FAB</string>

<string name="cat_navigation_rail_compact_message" description="Usage guidance for Navigation Rail advising using a Bottom Navigation Bar on compact screens instead. [CHAR_LIMIT=NONE]">The orientation of this Navigation Rail demo has been locked to portrait mode, because landscape mode results in a compact height on this device. For any compact screen dimensions, use a Bottom Navigation Bar instead.</string>

<string name="cat_navigation_rail_efab_text" description="The text on the button to expand the navigation rail [CHAR_LIMIT=NONE]">Label</string>
<string name="cat_navigation_rail_center_text" description="The text in the content centered in the remaining space beside the navigation rail [CHAR_LIMIT=NONE]">center</string>
<string name="cat_navigation_rail_efab_message" description="The message to display when the extended floating action button is clicked [CHAR_LIMIT=NONE]">Button clicked</string>
<string name="cat_navigation_rail_expand_collapse_button_description" description="The content description for the button that expands and collapses the navigation rail [CHAR_LIMIT=NONE]">Button to expand or collapse the navigation rail</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -920,10 +920,7 @@ private boolean isOrWillBeHidden() {

/**
* Set whether or not animations are enabled.
*
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public void setAnimationEnabled(boolean animationEnabled) {
this.animationEnabled = animationEnabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ public NavigationBarItemView(@NonNull Context context) {
}
// If item icon gravity is start, we want to update the active indicator width in a layout
// change listener to keep the active indicator size up to date with the content width.
LayoutParams lp = (LayoutParams) innerContentContainer.getLayoutParams();
int newWidth = right - left + lp.rightMargin + lp.leftMargin;
if (itemIconGravity == ITEM_ICON_GRAVITY_START
&& activeIndicatorExpandedDesiredWidth == ACTIVE_INDICATOR_WIDTH_WRAP_CONTENT
&& (right - left) != (oldRight - oldLeft)) {
LayoutParams lp = (LayoutParams) innerContentContainer.getLayoutParams();
int newWidth = right - left + lp.rightMargin + lp.leftMargin;
&& newWidth != activeIndicatorView.getMeasuredWidth()) {
LayoutParams indicatorParams = (LayoutParams) activeIndicatorView.getLayoutParams();
int minWidth =
min(
Expand Down Expand Up @@ -308,6 +308,16 @@ public int getItemPosition() {
return itemPosition;
}

@NonNull
public BaselineLayout getLabelGroup() {
return labelGroup;
}

@NonNull
public BaselineLayout getExpandedLabelGroup() {
return expandedLabelGroup;
}

public void setShifting(boolean shifting) {
if (isShifting != shifting) {
isShifting = shifting;
Expand Down Expand Up @@ -1103,7 +1113,11 @@ public void setActiveIndicatorExpandedHeight(int height) {
private void updateActiveIndicatorLayoutParams(int availableWidth) {
// Set width to the min of either the desired indicator width or the available width minus
// a horizontal margin.
if (availableWidth <= 0) {
if (availableWidth <= 0 && getVisibility() == VISIBLE) {
// Return early if there's not yet an available width and the view is visible; this will be
// called again when there is an available width. Otherwise if the available width is 0 due to
// the view being gone, we still want to set layout params so that when the view appears,
// there is no jump in animation from turning visible and then adjusting the height/width.
return;
}

Expand All @@ -1125,7 +1139,7 @@ private void updateActiveIndicatorLayoutParams(int availableWidth) {
// If the label visibility is unlabeled, make the active indicator's height equal to its
// width.
indicatorParams.height = isActiveIndicatorResizeableAndUnlabeled() ? newWidth : newHeight;
indicatorParams.width = newWidth;
indicatorParams.width = max(0, newWidth);
activeIndicatorView.setLayoutParams(indicatorParams);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.material.navigationrail;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.transition.Transition;
import androidx.transition.TransitionValues;
import com.google.android.material.navigation.NavigationBarMenuItemView;

/**
* A {@link Transition} that animates the {@link NavigationBarMenuItemView} label horizontally when
* the label is fading in.
*/
class LabelMoveTransition extends Transition {

private static final String LABEL_VISIBILITY = "NavigationRailLabelVisibility";
private static final float HORIZONTAL_DISTANCE = -30f;

@Override
public void captureStartValues(@NonNull TransitionValues transitionValues) {
transitionValues.values.put(LABEL_VISIBILITY, transitionValues.view.getVisibility());
}

@Override
public void captureEndValues(@NonNull TransitionValues transitionValues) {
transitionValues.values.put(LABEL_VISIBILITY, transitionValues.view.getVisibility());
}

@Nullable
@Override
public Animator createAnimator(@NonNull ViewGroup sceneRoot,
@Nullable TransitionValues startValues,
@Nullable TransitionValues endValues) {
if (startValues == null || endValues == null
|| startValues.values.get(LABEL_VISIBILITY) == null
|| endValues.values.get(LABEL_VISIBILITY) == null) {
return super.createAnimator(sceneRoot, startValues, endValues);
}
// Only animate if the view is appearing
if ((int) startValues.values.get(LABEL_VISIBILITY) != View.GONE
|| (int) endValues.values.get(LABEL_VISIBILITY) != View.VISIBLE) {
return super.createAnimator(sceneRoot, startValues, endValues);
}
View view = endValues.view;
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.addUpdateListener(
animation -> {
float progress = animation.getAnimatedFraction();
view.setTranslationX(HORIZONTAL_DISTANCE * (1 - progress));
});
return animator;
}
}
Loading

0 comments on commit 08c23dc

Please sign in to comment.