mirror of
https://github.com/material-components/material-components-android.git
synced 2026-01-17 02:11:43 +08:00
Resolves https://github.com/material-components/material-components-android/issues/2131 PiperOrigin-RevId: 365873683
219 lines
8.7 KiB
Java
219 lines
8.7 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)
|
|
*/
|
|
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)
|
|
*/
|
|
public void setOnNavigationItemReselectedListener(
|
|
@Nullable OnNavigationItemReselectedListener listener) {
|
|
setOnItemReselectedListener(listener);
|
|
}
|
|
|
|
/** Listener for handling selection events on bottom navigation items. */
|
|
public interface OnNavigationItemSelectedListener extends OnItemSelectedListener {}
|
|
|
|
/** Listener for handling reselection events on bottom navigation items. */
|
|
public interface OnNavigationItemReselectedListener extends OnItemReselectedListener {}
|
|
}
|