diff options
author | Aurimas Liutikas <aurimas@google.com> | 2016-10-26 00:14:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-10-26 00:14:27 +0000 |
commit | c4037564222e361cb92bbc05a062f8da91be5f5f (patch) | |
tree | 2e5ff3d76be834454f5dad13e9da974962b4e61a | |
parent | 2e2060d9e02a4b78ef885d9c68ba7b8c2304b800 (diff) | |
parent | 578015fc3e5ddc0fdb95db7ad0d00822c54be6df (diff) | |
download | support-nougat-mr1-dev.tar.gz |
Merge changes Id091acf5,Ie27b07ae,I701a2582,I32122d77 into nyc-mr1-devnougat-mr1-dev
* changes:
Start using return value of OnNavigationItemSelectedListener.
Clean up BottomBar docs
Force BottomNavigationView item labels to be singleLine.
Clean-up BottomNavigationMenuView#onMeasure and other style fixes.
7 files changed, 155 insertions, 55 deletions
diff --git a/design/res/layout/design_bottom_navigation_item.xml b/design/res/layout/design_bottom_navigation_item.xml index cc7bb5ffe04..67df838533d 100644 --- a/design/res/layout/design_bottom_navigation_item.xml +++ b/design/res/layout/design_bottom_navigation_item.xml @@ -34,6 +34,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/design_bottom_navigation_text_size" + android:singleLine="true" android:duplicateParentState="true" /> <TextView android:id="@+id/largeLabel" @@ -41,6 +42,7 @@ android:layout_height="wrap_content" android:visibility="invisible" android:textSize="@dimen/design_bottom_navigation_active_text_size" + android:singleLine="true" android:duplicateParentState="true" /> </android.support.design.internal.BaselineLayout> </merge>
\ No newline at end of file diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java index 158dda7b0be..096bdd83aa0 100644 --- a/design/src/android/support/design/internal/BottomNavigationMenuView.java +++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java @@ -16,6 +16,8 @@ package android.support.design.internal; +import static android.support.annotation.RestrictTo.Scope.GROUP_ID; + import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; @@ -32,8 +34,6 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; -import static android.support.annotation.RestrictTo.Scope.GROUP_ID; - /** * @hide For internal use only. */ @@ -55,6 +55,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { private ColorStateList mItemIconTint; private ColorStateList mItemTextColor; private int mItemBackgroundRes; + private int[] mTempChildWidths; private BottomNavigationPresenter mPresenter; private MenuBuilder mMenu; @@ -85,10 +86,12 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { public void onClick(View v) { final BottomNavigationItemView itemView = (BottomNavigationItemView) v; final int itemPosition = itemView.getItemPosition(); - activateNewButton(itemPosition); - mMenu.performItemAction(itemView.getItemData(), mPresenter, 0); + if (!mMenu.performItemAction(itemView.getItemData(), mPresenter, 0)) { + activateNewButton(itemPosition); + } } }; + mTempChildWidths = new int[BottomNavigationMenu.MAX_ITEM_COUNT]; } @Override @@ -105,10 +108,8 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { final int width = MeasureSpec.getSize(widthMeasureSpec); final int count = getChildCount(); - final int childState = 0; final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY); - final int[] childWidths = new int[count]; if (mShiftingMode) { final int inactiveCount = count - 1; final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth; @@ -117,9 +118,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth); int extra = width - activeWidth - inactiveWidth * inactiveCount; for (int i = 0; i < count; i++) { - childWidths[i] = (i == mActiveButton) ? activeWidth : inactiveWidth; + mTempChildWidths[i] = (i == mActiveButton) ? activeWidth : inactiveWidth; if (extra > 0) { - childWidths[i]++; + mTempChildWidths[i]++; extra--; } } @@ -128,9 +129,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth); int extra = width - childWidth * count; for (int i = 0; i < count; i++) { - childWidths[i] = childWidth; + mTempChildWidths[i] = childWidth; if (extra > 0) { - childWidths[i]++; + mTempChildWidths[i]++; extra--; } } @@ -142,7 +143,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { if (child.getVisibility() == GONE) { continue; } - child.measure(MeasureSpec.makeMeasureSpec(childWidths[i], MeasureSpec.EXACTLY), + child.measure(MeasureSpec.makeMeasureSpec(mTempChildWidths[i], MeasureSpec.EXACTLY), heightSpec); ViewGroup.LayoutParams params = child.getLayoutParams(); params.width = child.getMeasuredWidth(); @@ -150,9 +151,8 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { } setMeasuredDimension( ViewCompat.resolveSizeAndState(totalWidth, - MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), childState), - ViewCompat.resolveSizeAndState(mItemHeight, heightSpec, - childState << MEASURED_HEIGHT_STATE_SHIFT)); + MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), 0), + ViewCompat.resolveSizeAndState(mItemHeight, heightSpec, 0)); } @Override @@ -180,19 +180,34 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { return 0; } - public void setIconTintList(ColorStateList color) { - mItemIconTint = color; + /** + * Set the tint which is applied to the menu items' icons. + * + * @param tint the tint to apply. + */ + public void setIconTintList(ColorStateList tint) { + mItemIconTint = tint; if (mButtons == null) return; for (BottomNavigationItemView item : mButtons) { - item.setIconTintList(color); + item.setIconTintList(tint); } } + /** + * Returns the tint which is applied to menu items' icons. + * + * @return The ColorStateList that is used to tint menu items' icons. + */ @Nullable public ColorStateList getIconTintList() { return mItemIconTint; } + /** + * Set the text color to be used on menu items. + * + * @param color the ColorStateList used for menu items' text. + */ public void setItemTextColor(ColorStateList color) { mItemTextColor = color; if (mButtons == null) return; @@ -201,10 +216,19 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { } } + /** + * Returns the text color used on menu items. + * + * @return the ColorStateList used for menu items' text. + */ public ColorStateList getItemTextColor() { return mItemTextColor; } + /** + * Sets the resource id to be used for item background. + * @param background the resource id of the background. + */ public void setItemBackgroundRes(int background) { mItemBackgroundRes = background; if (mButtons == null) return; @@ -213,6 +237,11 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { } } + /** + * Returns the background resource of the menu items. + * + * @return the resource id of the background. + */ public int getItemBackgroundRes() { return mItemBackgroundRes; } diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java index 476889fe829..8a8e0bd052f 100644 --- a/design/src/android/support/design/widget/BottomNavigationView.java +++ b/design/src/android/support/design/widget/BottomNavigationView.java @@ -56,14 +56,28 @@ import android.widget.FrameLayout; * </p> * * <pre> + * layout resource file: * <android.support.design.widget.BottomNavigationView * xmlns:android="http://schemas.android.com/apk/res/android" * xmlns:design="http://schema.android.com/apk/res/android.support.design" * android:id="@+id/navigation" - * android:layout_width="wrap_content" - * android:layout_height="match_parent" + * android:layout_width="match_parent" + * android:layout_height="56dp" * android:layout_gravity="start" * design:menu="@menu/my_navigation_items" /> + * + * res/menu/my_navigation_items.xml: + * <menu xmlns:android="http://schemas.android.com/apk/res/android"> + * <item android:id="@+id/action_search" + * android:title="@string/menu_search" + * android:icon="@drawable/ic_search" /> + * <item android:id="@+id/action_settings" + * android:title="@string/menu_settings" + * android:icon="@drawable/ic_add" /> + * <item android:id="@+id/action_navigation" + * android:title="@string/menu_navigation" + * android:icon="@drawable/ic_action_navigation_menu" /> + * </menu> * </pre> */ public class BottomNavigationView extends FrameLayout { @@ -138,7 +152,7 @@ public class BottomNavigationView extends FrameLayout { mMenu.setCallback(new MenuBuilder.Callback() { @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - return mListener != null && mListener.onNavigationItemSelected(item); + return mListener != null && !mListener.onNavigationItemSelected(item); } @Override @@ -210,7 +224,7 @@ public class BottomNavigationView extends FrameLayout { } /** - * Returns the tint which is applied to menu items' icons. + * Returns the text color used on menu items. * * @see #setItemTextColor(ColorStateList) * @@ -265,7 +279,9 @@ public class BottomNavigationView extends FrameLayout { * * @param item The selected item * - * @return true to display the item as the selected item + * @return true to display the item as the selected item and false if the item should not + * be selected. Consider setting non-selectable items as disabled preemptively to + * make them appear non-interactive. */ boolean onNavigationItemSelected(@NonNull MenuItem item); } diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java index 98851b4c66a..0ddbc6d51d0 100644 --- a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java +++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java @@ -27,11 +27,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.core.AllOf.allOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.content.res.Resources; import android.support.annotation.ColorInt; @@ -95,22 +99,38 @@ public class BottomNavigationViewTest mock(BottomNavigationView.OnNavigationItemSelectedListener.class); mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener); - // Click one of our items + // Make the listener return true to allow selecting the item. + when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(true); onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)), isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); - // And that our listener has been notified of the click + // Verify our listener has been notified of the click verify(mockedListener, times(1)).onNavigationItemSelected( mBottomNavigation.getMenu().findItem(R.id.destination_profile)); + // Verify the item is now selected + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked()); + + // Make the listener return false to disallow selecting the item. + when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(false); + onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)), + isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); + // Verify our listener has been notified of the click + verify(mockedListener, times(1)).onNavigationItemSelected( + mBottomNavigation.getMenu().findItem(R.id.destination_people)); + // Verify the previous item is still selected + assertFalse(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked()); + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked()); // Set null listener to test that the next click is not going to notify the - // previously set listener + // previously set listener and will allow selecting items. mBottomNavigation.setOnNavigationItemSelectedListener(null); // Click one of our items - onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)), + onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)), isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); // And that our previous listener has not been notified of the click verifyNoMoreInteractions(mockedListener); + // Verify the correct item is now selected. + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_home).isChecked()); } @Test diff --git a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml index 83e731470fe..c86843009aa 100644 --- a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml +++ b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml @@ -14,46 +14,56 @@ See the License for the specific language governing permissions and limitations under the License. --> -<RelativeLayout +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> - <Button - android:id="@+id/button_disable" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/bottomnavigation_disable"/> - - <Button - android:id="@+id/button_add" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/bottomnavigation_add" - android:layout_below="@+id/button_disable"/> + <ScrollView android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginBottom="56dp"> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + <Button + android:id="@+id/button_disable" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/bottomnavigation_disable"/> + <Button + android:id="@+id/button_add" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/bottomnavigation_add" + android:layout_below="@+id/button_disable"/> - <Button - android:id="@+id/button_remove" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/bottomnavigation_remove" - android:layout_below="@+id/button_add"/> + <Button + android:id="@+id/button_remove" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/bottomnavigation_remove" + android:layout_below="@+id/button_add"/> - <Button - android:id="@+id/button_tint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/bottomnavigation_tint" - android:layout_below="@+id/button_remove"/> + <Button + android:id="@+id/button_tint" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/bottomnavigation_tint" + android:layout_below="@+id/button_remove"/> + <TextView + android:id="@+id/selected_item" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/button_tint"/> + </RelativeLayout> + </ScrollView> <android.support.design.widget.BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="match_parent" android:layout_height="56dp" android:layout_gravity="bottom" android:background="#eee" - android:layout_alignParentBottom="true" app:menu="@menu/sample_bottom_menu"/> - -</RelativeLayout> +</FrameLayout> diff --git a/samples/SupportDesignDemos/res/menu/sample_bottom_menu.xml b/samples/SupportDesignDemos/res/menu/sample_bottom_menu.xml index 4294f80c2ba..d6d4761e8f0 100644 --- a/samples/SupportDesignDemos/res/menu/sample_bottom_menu.xml +++ b/samples/SupportDesignDemos/res/menu/sample_bottom_menu.xml @@ -20,7 +20,7 @@ <item android:id="@+id/action_settings" android:title="@string/menu_settings" android:icon="@drawable/ic_add"/> - <item android:id="@+id/action_navigation" + <item android:id="@+id/action_music" android:title="@string/tab_text" android:icon="@drawable/ic_action_navigation_menu"/> </menu>
\ No newline at end of file diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java index 72b50db10de..34422181ea8 100644 --- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java +++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java @@ -18,11 +18,13 @@ package com.example.android.support.design.widget; import android.content.res.ColorStateList; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.design.widget.BottomNavigationView; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Button; +import android.widget.TextView; import com.example.android.support.design.R; @@ -74,5 +76,26 @@ public class BottomNavigationViewUsage extends AppCompatActivity { } } }); + final TextView selectedItem = (TextView) findViewById(R.id.selected_item); + bottom.setOnNavigationItemSelectedListener( + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_search: + selectedItem.setText("Entering searching mode"); + break; + case R.id.action_settings: + selectedItem.setText("Entering settings!?!"); + break; + case R.id.action_music: + selectedItem.setText("Play some music"); + break; + default: + selectedItem.setText("Selected " + item.getTitle()); + } + return true; + } + }); } } |