12

I am trying to implement this bottom bar which contains an item with a bigger size and a different shape than the other ones.

bottom bar

Is there a non-hacky way to achieve this using the native Bottom navigation component ? I guess not because it does not seem compliant with Material Design specs.

Otherwise, what would be the best approach to follow ? I see only 2 ways to achieve this but none of them seems reliable to me.

  • For every "small item", adding a transparent bar at the top of the drawable to reach the size of the camera icon.
  • Implementing a 5 items bottom bar with a "ghost item" in the middle, on top of which I could place some other component. This would require this component to be coupled with the bottom bar.

EDIT

This is what I obtained by increasing the icon size as suggested by Harshit and fmaccaroni.

When the item is not selected :

item_selected

When the item is selected :

item_selected

Pro: The icon is bigger than the other ones

Cons: It is still contained inside the bottom bar. Also, it is not centered vertically when selected


Louis
  • 1,913
  • 2
  • 28
  • 41

8 Answers8

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

also add android:clipChildren="false" to root layout

Siddhesh Shirodkar
  • 891
  • 13
  • 16
5

After a few research I came across this library. They did not provide what I was looking for, but they implemented this behavior in one of their samples, which was pretty close to what I needed.

This is what I got by reusing their idea (tested only on 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>

It looks decent, but I do not like the implementation since the bottom navigation is now split between two components.

The idea is to create an empty item in the middle of the bottom bar, and to add a floating action button on top of it, to create the illusion that it is part of the bottom bar.

Here is the layout of my bottombar and floating navigation button:

<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" />

Navigation bar items :

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

Everytime I the FAB button is clicked, I disable the bottom bar :

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);
        }
    }
}

Same thing with setCheckable(true) when a bottom bar icon is clicked.

Hope this helps.

Louis
  • 1,913
  • 2
  • 28
  • 41
2

Since the last Material update (2018), it's possible to do so with native UI elements:

  • BottomAppBar with app:fabAttached attribute
  • FloatingActionButton with app:layout_anchor relating the BottomAppBar
  • Enjoy the alignment with app:fabAlignmentMode

Alignment center

You can relate to this great Medium article for more new material elements and more details about this one.

Hope it helps you!

DPalagi
  • 179
  • 6
2

the simple way is using setScaleX and setScaleY. for example:

final View iconView = 
menuView.getChildAt(2).findViewById(android.support.design.R.id.icon);
iconView.setScaleY(1.5f);
iconView.setScaleX(1.5f);
royaB
  • 21
  • 1
  • 1
    This is definitely the simplest way to just increase the size of a specific icon. Wanted to add that if you are using androidx instead of the support library, you would use R.id.icon instead of android.support.design.R.id.icon. Also, if it's not clear, you would get the menuView in the same way that fmaccaroni did: `BottomNavigationView bottomNavigationView = (BottomNavigationView) activity.findViewById(R.id.bottom_navigation_view); BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);` – Laurel Thomson Jun 13 '20 at 21:47
1

The icons size in Bottom Bar navigation can be changed programmatically by

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);
}

I did something just like this to change the size of the bottom bar navigation items as desired.

And here is what you can do:

  1. Take a large sized image of the same image that you want to display bigger in size when clicked and store it in that drawable folder.

  2. Than apply when the navigation bottom bar that particular item is clicked than set the previous smaller image with the larger image.

And you can have a look at this library use this library to solve your problem.

halfer
  • 19,824
  • 17
  • 99
  • 186
HarshitMadhav
  • 4,769
  • 6
  • 36
  • 45
  • @Louis okay Louis let me think – HarshitMadhav Nov 29 '17 at 16:30
  • @Louis have a look at my edited answer. Hope this library helps in what you want. Do let me know for further issues. – HarshitMadhav Nov 29 '17 at 16:36
  • If this helps you accept the answer to this question so that other users who come looking for the same problem can be helped too. :) – HarshitMadhav Nov 29 '17 at 16:44
  • I have thought of solving your problem by one more way. Let me know the feedback of this library first whether it solved the problem. – HarshitMadhav Nov 29 '17 at 16:49
  • I had a look at it but I did not find anything useful for my use case, thanks anyway ! – Louis Dec 01 '17 at 10:05
  • @Louis Please check my updated answer you solve your problem without using any library. – HarshitMadhav Dec 01 '17 at 13:54
  • even if the image look bigger it will be contained inside the bottom bar so that won't help – Louis Dec 01 '17 at 15:49
  • stackoverflow does not work this way, upvotes depends on the utility of content, not on the effort that has been put into it. I truely appreciate your help but since it was not useful to me I will not upvote it. Refer to [this article](https://meta.stackoverflow.com/questions/334438/upvote-for-effort-only) for more informations. – Louis Dec 01 '17 at 16:04
  • @Louis Refer to the answer mentioned it says "you can use upvotes as you see fit" else I leave it to you :) – HarshitMadhav Dec 01 '17 at 16:12
0

Taking this as reference you can iterate for each children of your BottomNavigationView and change the size of the specified item:

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);
}
fmaccaroni
  • 3,846
  • 1
  • 20
  • 35
0

I achieved same UI using Frame layout. Here is the code

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

and do not give icon for middle item.

<?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>
Ramakrishna Joshi
  • 1,442
  • 17
  • 22
0

For Androidx BottomNavigationView

iterate over each child and change icon size with 'setIconSize()' method (consider @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())
            }
        }
Mohd Danish
  • 186
  • 2
  • 3