Как изменить размер и форму определенного элемента навигации нижней панели

Я пытаюсь реализовать эту нижнюю панель, которая содержит элемент большего размера и формы, отличной от других.

нижняя панель

Есть ли нехакерский способ добиться этого с помощью встроенного компонента навигации Bottom? Я думаю, не потому, что он не соответствует спецификациям Material Design.

В противном случае, какой будет лучший подход для подражания? Я вижу только 2 способа добиться этого, но ни один из них не кажется мне надежным.

  • Для каждого "маленького элемента" добавьте прозрачную полосу в верхней части окна, чтобы достичь размера значка камеры.
  • Реализация нижней панели из 5 элементов с "призрачным элементом" в середине, поверх которого я мог бы разместить какой-то другой компонент. Это потребовало бы, чтобы этот компонент был связан с нижней панелью.

РЕДАКТИРОВАТЬ

Это то, что я получил, увеличив размер иконки, как это предложили Харшит и Фмакарони.

Когда элемент не выбран:

item_selected

Когда элемент выбран:

item_selected

Pro: значок больше, чем другие

Минусы: он все еще содержится внутри нижней панели. Кроме того, он не центрируется вертикально при выборе

РЕДАКТИРОВАТЬ 2

Мое первоначальное предположение, что это не могло быть реализовано из-за несоответствия спецификациям Material Design, теперь неверно. Принятый ответ обеспечивает способ реализовать это поведение, используя дизайн материала.


8 ответов

Решение

Со времени последнего обновления Материала (2018) это можно сделать с помощью собственных элементов пользовательского интерфейса:

  • BottomAppBar с app:fabAttached атрибут
  • FloatingActionButton с app:layout_anchor относящиеся к BottomAppBar
  • Наслаждайтесь выравниванием с app:fabAlignmentMode

Центр выравнивания

Вы можете обратиться к этой замечательной статье Medium, чтобы узнать больше о новых элементах материала и подробнее об этом.

Надеюсь, это поможет вам!

<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" в корневой макет

РЕДАКТИРОВАТЬ:

Этот ответ был написан до обновления Материала 2018 года. Вероятно, не путь, чтобы идти больше. Обратитесь к ответу DPalagi за актуальным материалом.


После нескольких исследований я наткнулся на эту библиотеку. Они не предоставили то, что я искал, но реализовали это поведение в одном из своих образцов, что было довольно близко к тому, что мне было нужно.

Вот что я получил, повторно использовав их идею (проверено только на 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) при нажатии на значок нижней панели.

Надеюсь это поможет.

Самый простой способ - использовать setScaleX и setScaleY. например:

final View iconView = 
menuView.getChildAt(2).findViewById(android.support.design.R.id.icon);
iconView.setScaleY(1.5f);
iconView.setScaleX(1.5f);

Размер значков в навигационной панели может быть изменен программно

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. Чем применить, когда нижняя панель навигации щелкает конкретный элемент, чем установить предыдущее меньшее изображение с большим изображением.

И вы можете взглянуть на эту библиотеку, использовать эту библиотеку для решения вашей проблемы.

Я достиг такого же пользовательского интерфейса, используя макет кадра. Вот код

      <?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>

Принимая это как ссылку, вы можете выполнить итерацию для каждого дочернего элемента вашего 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);
}

Для Androidx

перебирать каждого дочернего элемента и изменять размер значка с помощью метода 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())
            }
        }
Другие вопросы по тегам