如何更改特定底部栏导航项的大小和形状

How to change the size and shape of a particular bottom bar navigation item

我正在尝试实现这个底部栏,其中包含一个比其他项目更大、形状不同的项目。

是否有使用本机底部导航组件实现此目的的简单方法?我猜不是,因为它似乎不符合 Material 设计规范。

否则,最好的方法是什么?我只看到 2 种方法可以实现此目的,但 none 对我来说似乎是可靠的。

编辑

这是我按照 Harshit 和 fmaccaroni 的建议通过增加图标大小获得的结果。

未选择项目时:

当项目被选中时:

亲:图标比其他的大

缺点:它仍然包含在底栏中。此外,它在选择时不垂直居中


可以通过

以编程方式更改底部栏导航中的图标大小
BottomNavigationView bottomNavigationView = (BottomNavigationView) 
activity.findViewById(R.id.bottom_navigation_view);

BottomNavigationMenuView menuView = (BottomNavigationMenuView) 
bottomNavigationView.getChildAt(0);

for (int i = 0; i < menuView.getChildCount(); i++) {
final View iconView = 
menuView.getChildAt(i).findViewById(android.support.design.R.id.icon);

final ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();

final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
// set your height here
layoutParams.height = (int) 
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, displayMetrics);

// set your width here
layoutParams.width = (int) 
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, displayMetrics);

iconView.setLayoutParams(layoutParams);
}

我做了类似的事情来根据需要更改底部栏导航项的大小。

您可以执行以下操作:

  1. 为您希望在单击时显示更大尺寸的同一图像拍摄一张大尺寸图像,并将其存储在该可绘制文件夹中。

  2. 当单击特定项目的导航底部栏而不是将前一个较小的图像设置为较大的图像时应用。

你可以看看 this library 使用这个库来解决你的问题。

this 为参考,您可以迭代 BottomNavigationView 的每个子项并更改指定项目的大小:

BottomNavigationView bottomNavigationView = (BottomNavigationView) activity.findViewById(R.id.bottom_navigation_view);
BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);
for (int i = 0; i < menuView.getChildCount(); i++) {
    final View iconView = menuView.getChildAt(i).findViewById(android.support.design.R.id.icon);
    final ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
    final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
    // If it is my special menu item change the size, otherwise take other size
    if (i == 2){
        // set your height here
        layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, displayMetrics);
        // set your width here
        layoutParams.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, displayMetrics);
    }
    else {
        // set your height here
        layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, displayMetrics);
        // set your width here
        layoutParams.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, displayMetrics);
    }
    iconView.setLayoutParams(layoutParams);
}

经过一些研究,我发现 this library. They did not provide what I was looking for, but they implemented this behavior 在他们的一个样本中,这非常接近我需要的。

这是我通过重用他们的想法得到的(仅在 API 23 上测试过):

<blockquote class="imgur-embed-pub" lang="en" data-id="a/0Oypk"><a href="//imgur.com/0Oypk"></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

它看起来不错,但我不喜欢这个实现,因为底部导航现在分为两个部分。

想法是在底栏中间创建一个空项目,并在其顶部添加一个浮动操作按钮,以营造它是底栏一部分的错觉。

这是我的底栏和浮动导航按钮的布局:

<com.ittianyu.bottomnavigationviewex.BottomNavigationViewEx
    android:id="@+id/navigation"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:layout_gravity="bottom"
    app:elevation="0dp"
    app:itemIconTint="@drawable/menu_item_selector"
    app:itemTextColor="@drawable/menu_item_selector"
    app:layout_constraintBottom_toBottomOf="parent"
    app:menu="@menu/navigation_items" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:focusable="true"
    app:backgroundTint="@color/white"
    app:borderWidth="0dp"
    app:elevation="0dp"
    app:fabSize="mini"
    app:layout_constraintBottom_toBottomOf="@id/navigation"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:srcCompat="@drawable/camera_icon" />

导航栏项目:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <item
        android:id="@+id/action_around_me"
        android:icon="@drawable/ic_bottombar_around_me"
        tools:ignore="MenuTitle" />

    <item
        android:id="@+id/action_my_projects"
        android:icon="@drawable/ic_bottombar_projects"
        tools:ignore="MenuTitle" />

    <!-- Here is the trick -->
    <item
        android:id="@+id/empty"
        android:enabled="false"
        tools:ignore="MenuTitle" />

    <item
        android:id="@+id/action_notifications"
        android:icon="@drawable/ic_bottombar_notification"
        tools:ignore="MenuTitle" />

    <item
        android:id="@+id/action_settings"
        android:icon="@drawable/ic_bottombar_settings"
        tools:ignore="MenuTitle" />
</menu>

每次单击 FAB 按钮时,我都会禁用底部栏:

private void disableBottomBar() {
    Menu menu = navigationBar.getMenu();
    for (int i = 0; i < menu.size(); i++) {
        // The third item is a an empty item so we do not do anything on it
        if (i != 2) {
            menu.getItem(i).setCheckable(false);
        }
    }
}

单击底部栏图标时 setCheckable(true) 的情况相同。

希望对您有所帮助。

自上次 Material 更新(2018 年)以来,可以使用本机 UI 元素执行此操作:

  • BottomAppBar 具有 app:fabAttached 属性
  • FloatingActionButtonapp:layout_anchor 相关的 BottomAppBar
  • 享受与app:fabAlignmentMode
  • 的对齐

您可以与 this great Medium article 联系以获取更多新的 material 元素以及有关此元素的更多详细信息。

希望对您有所帮助!

简单的方法是使用 setScaleX 和 setScaleY。例如:

final View iconView = 
menuView.getChildAt(2).findViewById(android.support.design.R.id.icon);
iconView.setScaleY(1.5f);
iconView.setScaleX(1.5f);
<android.support.design.widget.BottomNavigationView
    android:id="@+id/navigation"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:layout_alignParentBottom="true"
    android:background="?android:attr/windowBackground"
    app:itemIconTint="@color/colorPrimary"
    app:itemTextColor="@android:color/black"
    app:menu="@menu/navigation"
    android:clipChildren="false">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="56dp"
        android:layout_height="56dp"
        android:layout_gravity="center"
        android:layout_marginBottom="8dp"
        app:elevation="6dp"
        android:scaleType="center" />
</android.support.design.widget.BottomNavigationView>

同时将 android:clipChildren="false" 添加到根布局

我使用框架布局实现了相同的 UI。这是代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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">

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph_home" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/background_white_rounded_top"
        app:itemTextColor="@color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:menu="@menu/bottom_nav_bar_home_items"
        app:labelVisibilityMode="unlabeled">

    </com.google.android.material.bottomnavigation.BottomNavigationView>

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <ImageView
            android:id="@+id/toggle_alignment"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_home_scan" />

    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

并且不为中间项提供图标。

<?xml version="1.0" encoding="utf-8"?>
<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/firstFragment"
            android:icon="@drawable/ic_one"
            android:title="" />
        <item
            android:id="@+id/secondFragment"
            android:icon="@drawable/ic_two"
            android:title="" />
        <item
            android:id="@+id/thirdFragment"
            android:title="" />
        <item
            android:id="@+id/fourthFragment"
            android:icon="@drawable/ic_four"
            android:title=""/>
        <item
            android:id="@+id/fifthFragment"
            android:icon="@drawable/ic_five"
            android:title="" />
    </group>
</menu>

对于 Androidx BottomNavigationView

遍历每个 child 并使用 'setIconSize()' 方法更改图标大小(考虑 @SuppressLint("RestrictedApi"))

val menuView: BottomNavigationMenuView = bottomNavigationView.getChildAt(0) as BottomNavigationMenuView
        for (i in 0 until menuView.childCount) {
            if (i == 3) {
                val displayMetrics: DisplayMetrics = resources.displayMetrics
                (menuView.getChildAt(i) as NavigationBarItemView).setIconSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 41f, displayMetrics).toInt())
            }
        }