Как изменить размер и форму определенного элемента навигации нижней панели
Я пытаюсь реализовать эту нижнюю панель, которая содержит элемент большего размера и формы, отличной от других.
Есть ли нехакерский способ добиться этого с помощью встроенного компонента навигации Bottom? Я думаю, не потому, что он не соответствует спецификациям Material Design.
В противном случае, какой будет лучший подход для подражания? Я вижу только 2 способа добиться этого, но ни один из них не кажется мне надежным.
- Для каждого "маленького элемента" добавьте прозрачную полосу в верхней части окна, чтобы достичь размера значка камеры.
- Реализация нижней панели из 5 элементов с "призрачным элементом" в середине, поверх которого я мог бы разместить какой-то другой компонент. Это потребовало бы, чтобы этот компонент был связан с нижней панелью.
РЕДАКТИРОВАТЬ
Это то, что я получил, увеличив размер иконки, как это предложили Харшит и Фмакарони.
Когда элемент не выбран:
Когда элемент выбран:
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);
}
Я сделал что-то подобное, чтобы изменить размер элементов навигации нижней панели по желанию.
И вот что вы можете сделать:
Возьмите большое по размеру изображение того же изображения, которое вы хотите отобразить в увеличенном размере при нажатии, и сохраните его в этой папке для рисования.
Чем применить, когда нижняя панель навигации щелкает конкретный элемент, чем установить предыдущее меньшее изображение с большим изображением.
И вы можете взглянуть на эту библиотеку, использовать эту библиотеку для решения вашей проблемы.
Я достиг такого же пользовательского интерфейса, используя макет кадра. Вот код
<?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())
}
}