mirror of
https://github.com/material-components/material-components-android.git
synced 2026-01-16 18:01:42 +08:00
to be easier used by developers and other libraries An example of where the current implementation fails is in Jetpack Navigation component where we rely on setOnNavigationItemSelectedListener and the similar methods in NavigationBarView (setOnItemSelectedListener) are protected. PiperOrigin-RevId: 367467206
223 lines
8.8 KiB
Java
223 lines
8.8 KiB
Java
/*
|
|
* Copyright (C) 2016 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.bottomnavigation;
|
|
|
|
import com.google.android.material.R;
|
|
|
|
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
|
|
|
|
import android.content.Context;
|
|
import android.os.Build.VERSION;
|
|
import androidx.appcompat.widget.TintTypedArray;
|
|
import android.util.AttributeSet;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.FrameLayout;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.RestrictTo;
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
import androidx.core.content.ContextCompat;
|
|
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior;
|
|
import com.google.android.material.internal.ThemeEnforcement;
|
|
import com.google.android.material.navigation.NavigationBarMenuView;
|
|
import com.google.android.material.navigation.NavigationBarView;
|
|
import com.google.android.material.shape.MaterialShapeDrawable;
|
|
|
|
/**
|
|
* Represents a standard bottom navigation bar for application. It is an implementation of <a
|
|
* href="https://material.google.com/components/bottom-navigation.html">material design bottom
|
|
* navigation</a>.
|
|
*
|
|
* <p>Bottom navigation bars make it easy for users to explore and switch between top-level views in
|
|
* a single tap. They should be used when an application has three to five top-level destinations.
|
|
*
|
|
* <p>The bar can disappear on scroll, based on {@link
|
|
* com.google.android.material.behavior.HideBottomViewOnScrollBehavior}, when it is placed within a
|
|
* {@link CoordinatorLayout} and one of the children within the {@link CoordinatorLayout} is
|
|
* scrolled. This behavior is only set if the {@code layout_behavior} property is set to {@link
|
|
* HideBottomViewOnScrollBehavior}.
|
|
*
|
|
* <p>The bar contents can be populated by specifying a menu resource file. Each menu item title,
|
|
* icon and enabled state will be used for displaying bottom navigation bar items. Menu items can
|
|
* also be used for programmatically selecting which destination is currently active. It can be done
|
|
* using {@code MenuItem#setChecked(true)}
|
|
*
|
|
* <pre>
|
|
* layout resource file:
|
|
* <com.google.android.material.bottomnavigation.BottomNavigationView
|
|
* xmlns:android="http://schemas.android.com/apk/res/android"
|
|
* xmlns:app="http://schema.android.com/apk/res/res-auto"
|
|
* android:id="@+id/navigation"
|
|
* android:layout_width="match_parent"
|
|
* android:layout_height="56dp"
|
|
* android:layout_gravity="start"
|
|
* app: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 NavigationBarView {
|
|
static final int MAX_ITEM_COUNT = 5;
|
|
|
|
public BottomNavigationView(@NonNull Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public BottomNavigationView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
this(context, attrs, R.attr.bottomNavigationStyle);
|
|
}
|
|
|
|
public BottomNavigationView(
|
|
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
|
this(context, attrs, defStyleAttr, R.style.Widget_Design_BottomNavigationView);
|
|
}
|
|
|
|
public BottomNavigationView(
|
|
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
|
super(context, attrs, defStyleAttr, defStyleRes);
|
|
|
|
// Ensure we are using the correctly themed context rather than the context that was passed in.
|
|
context = getContext();
|
|
|
|
/* Custom attributes */
|
|
TintTypedArray attributes =
|
|
ThemeEnforcement.obtainTintedStyledAttributes(
|
|
context, attrs, R.styleable.BottomNavigationView, defStyleAttr, defStyleRes);
|
|
|
|
setItemHorizontalTranslationEnabled(
|
|
attributes.getBoolean(
|
|
R.styleable.BottomNavigationView_itemHorizontalTranslationEnabled, true));
|
|
|
|
attributes.recycle();
|
|
|
|
if (shouldDrawCompatibilityTopDivider()) {
|
|
addCompatibilityTopDivider(context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether the menu items horizontally translate on selection when the combined item widths
|
|
* fill up the screen.
|
|
*
|
|
* @param itemHorizontalTranslationEnabled whether the items horizontally translate on selection
|
|
* @see #isItemHorizontalTranslationEnabled()
|
|
*/
|
|
public void setItemHorizontalTranslationEnabled(boolean itemHorizontalTranslationEnabled) {
|
|
BottomNavigationMenuView menuView = (BottomNavigationMenuView) getMenuView();
|
|
if (menuView.isItemHorizontalTranslationEnabled() != itemHorizontalTranslationEnabled) {
|
|
menuView.setItemHorizontalTranslationEnabled(itemHorizontalTranslationEnabled);
|
|
getPresenter().updateMenuView(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether the items horizontally translate on selection when the item widths fill up the
|
|
* screen.
|
|
*
|
|
* @return whether the menu items horizontally translate on selection
|
|
* @see #setItemHorizontalTranslationEnabled(boolean)
|
|
*/
|
|
public boolean isItemHorizontalTranslationEnabled() {
|
|
return ((BottomNavigationMenuView) getMenuView()).isItemHorizontalTranslationEnabled();
|
|
}
|
|
|
|
@Override
|
|
public int getMaxItemCount() {
|
|
return MAX_ITEM_COUNT;
|
|
}
|
|
|
|
/** @hide */
|
|
@RestrictTo(LIBRARY_GROUP)
|
|
@Override
|
|
@NonNull
|
|
protected NavigationBarMenuView createNavigationBarMenuView(@NonNull Context context) {
|
|
return new BottomNavigationMenuView(context);
|
|
}
|
|
|
|
/**
|
|
* Returns true a divider must be added in place of shadows to maintain compatibility in pre-21
|
|
* legacy backgrounds.
|
|
*/
|
|
private boolean shouldDrawCompatibilityTopDivider() {
|
|
return VERSION.SDK_INT < 21 && !(getBackground() instanceof MaterialShapeDrawable);
|
|
}
|
|
|
|
/**
|
|
* Adds a divider in place of shadows to maintain compatibility in pre-21 legacy backgrounds. If a
|
|
* pre-21 background has been updated to a MaterialShapeDrawable, MaterialShapeDrawable will draw
|
|
* shadows instead.
|
|
*/
|
|
private void addCompatibilityTopDivider(@NonNull Context context) {
|
|
View divider = new View(context);
|
|
divider.setBackgroundColor(
|
|
ContextCompat.getColor(context, R.color.design_bottom_navigation_shadow_color));
|
|
FrameLayout.LayoutParams dividerParams =
|
|
new FrameLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
getResources().getDimensionPixelSize(R.dimen.design_bottom_navigation_shadow_height));
|
|
divider.setLayoutParams(dividerParams);
|
|
addView(divider);
|
|
}
|
|
|
|
/**
|
|
* Set a listener that will be notified when a bottom navigation item is selected. This listener
|
|
* will also be notified when the currently selected item is reselected, unless an {@link
|
|
* OnNavigationItemReselectedListener} has also been set.
|
|
*
|
|
* @param listener The listener to notify
|
|
* @see #setOnNavigationItemReselectedListener(OnNavigationItemReselectedListener)
|
|
*/
|
|
@Deprecated
|
|
public void setOnNavigationItemSelectedListener(
|
|
@Nullable OnNavigationItemSelectedListener listener) {
|
|
setOnItemSelectedListener(listener);
|
|
}
|
|
|
|
/**
|
|
* Set a listener that will be notified when the currently selected bottom navigation item is
|
|
* reselected. This does not require an {@link OnNavigationItemSelectedListener} to be set.
|
|
*
|
|
* @param listener The listener to notify
|
|
* @see #setOnNavigationItemSelectedListener(OnNavigationItemSelectedListener)
|
|
*/
|
|
@Deprecated
|
|
public void setOnNavigationItemReselectedListener(
|
|
@Nullable OnNavigationItemReselectedListener listener) {
|
|
setOnItemReselectedListener(listener);
|
|
}
|
|
|
|
/** Listener for handling selection events on bottom navigation items. */
|
|
@Deprecated
|
|
public interface OnNavigationItemSelectedListener extends OnItemSelectedListener {}
|
|
|
|
/** Listener for handling reselection events on bottom navigation items. */
|
|
@Deprecated
|
|
public interface OnNavigationItemReselectedListener extends OnItemReselectedListener {}
|
|
}
|