How to add footer to NavigationView - Android support design library?
Asked Answered
L

27

140

How can I set footer settings and profile items to NavitationView? to looks like the Inbox by email navigation drawer. The NavitationView items are inflated by menu resource, but I don't know how to set bottom items to a menu resource, or how can I set a custom view to NavigationView or an bottom offset? I have tried putting this <LinearLayout...> as footer view, but on small screens the footer puts over the items and I cant scroll the menu, I have tried to set a footer padding to NavigationView, but the footer takes the padding too.

This is not scrolling on small screens:

<android.support.design.widget.NavigationView
    android:id="@+id/drawer"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/kuona_drawer_header"
    app:menu="@menu/drawer">

    <LinearLayout...>

</android.support.design.widget.NavigationView>

NOT SCROLLING

This scrolls, but the footer its over the menu items:

<android.support.design.widget.NavigationView
    android:id="@+id/drawer"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:paddingBottom="96dp"
    app:headerLayout="@layout/kuona_drawer_header"
    app:menu="@menu/drawer">

    <LinearLayout...>

</android.support.design.widget.NavigationView>

enter image description here

Drawer menu res/menu/drawer.xml file:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:id="@+id/action_current_list"
            android:checked="true"
            android:icon="@drawable/ic_current_list"
            android:title="@string/current_list" />
        <item
            android:id="@+id/action_manage_lists"
            android:icon="@drawable/ic_my_lists"
            android:title="@string/my_lists" />
        <item
            android:id="@+id/action_search_products"
            android:icon="@drawable/ic_search_black_24dp"
            android:title="@string/search_products" />
        <item
            android:id="@+id/action_deals"
            android:icon="@drawable/ic_product_promo"
            android:title="@string/deals" />
    </group>
</menu>
Lowney answered 30/5, 2015 at 7:36 Comment(5)
In which location have you put the @menu/drawer file..Cassella
It is in /res/menu/drawer.xmlLowney
Is there a reason you can't do "Feedback" and "Sign Out" as menu items? If the reason is that you want to dynamically change the menu icon for "Sign Out", you should be able to do that with menuItem.setIcon(Drawable).Indeterminism
It is just for requirements, and personally I want to know how Google does this in inbox app for example.Lowney
This question becomes even more important with 23.1 updateInfare
I
175

If you want a fixed (non-scrolling) footer in your navigation menu, you need wrap NavigationView around another layout, like you've posted. NavigationView works like FrameLayout, so this ends up "stacking" the inner layout on top of the NavigationView menu items. Here's one way to arrange it, using LinearLayout for the footer items:

Fixed Footer

<android.support.design.widget.NavigationView
    android:id="@+id/drawer"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/drawer_header"
    app:menu="@menu/drawer">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:clickable="true"
        android:orientation="vertical">
        <TextView
            android:id="@+id/footer_item_1"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:gravity="center"
            android:text="Footer Item 1" />
        <TextView
            android:id="@+id/footer_item_2"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:gravity="center"
            android:text="Footer Item 2" />
    </LinearLayout>

</android.support.design.widget.NavigationView>

I used TextViews in this example, but you can use whatever you want for the footer views. To avoid the footer items overlapping with the bottom of the menu, add some dummy items to the end of your menu resource file (these will act like "spacers"):

res/menu/drawer.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group>
        <item
            android:id="@+id/nav_item_1"
            android:icon="@drawable/ic_nav_item_1"
            android:title="Nav Item 1" />
        <item
            android:id="@+id/nav_item_2"
            android:icon="@drawable/ic_nav_item_2"
            android:title="Nav Item 2" />
        <item
            android:id="@+id/nav_item_3"
            android:icon="@drawable/ic_nav_item_3"
            android:title="Nav Item 3" />
        <item
            android:id="@+id/nav_item_4"
            android:icon="@drawable/ic_nav_item_4"
            android:title="Nav Item 4" />
        <item
            android:id="@+id/footer_spacer_1"
            android:checkable="false"
            android:enabled="false"
            android:orderInCategory="200"
            android:title="" />
        <item
            android:id="@+id/footer_spacer_2"
            android:checkable="false"
            android:enabled="false"
            android:orderInCategory="200"
            android:title="" />
    </group>
</menu>

Lastly, don't forget to add click listeners in your Activity for the actual footer views:

...
// Click listener for nav footer.
View navFooter1 = findViewById(R.id.footer_item_1);
navFooter1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do footer action
    }
});
View navFooter2 = findViewById(R.id.footer_item_2);
navFooter2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do footer action
    }
});
...

Scrolling Footer

If you allow the footer to scroll with the rest of the NavigationView though, it makes things simpler (no additional layouts or click listeners). Simply add the footer items to your menu resource file as a unique <group> (this will create a separator line), and everything will be handled automatically and scroll together:

res/menu/drawer.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:id="@+id/nav_menu">
        <item
            android:id="@+id/nav_item_1"
            android:icon="@drawable/ic_nav_item_1"
            android:title="Nav Item 1" />
        <item
            android:id="@+id/nav_item_2"
            android:icon="@drawable/ic_nav_item_2"
            android:title="Nav Item 2" />
        <item
            android:id="@+id/nav_item_3"
            android:icon="@drawable/ic_nav_item_3"
            android:title="Nav Item 3" />
        <item
            android:id="@+id/nav_item_4"
            android:icon="@drawable/ic_nav_item_4"
            android:title="Nav Item 4" />
    </group>
    <group android:id="@+id/nav_footer">
        <item
            android:id="@+id/nav_footer_1"
            android:icon="@drawable/ic_footer_item_1"
            android:title="Footer Item 1" />
        <item
            android:id="@+id/nav_footer_2"
            android:icon="@drawable/ic_footer_item_2"
            android:title="Footer Item 2" />
    </group>
</menu>
Indeterminism answered 3/6, 2015 at 4:49 Comment(12)
It is just for requirements, and personally I want to know how Google does this in inbox app for example.Lowney
I'm not sure how Google does it in the gmail app, but from appearances, it looks just like what I've described in the answer. Use a separate <group> if you want a separator line, otherwise, the gmail app's nav footer just looks like normal menu items (to me at least).Indeterminism
Yeah the gmail app footer looks like menu items but footer in the inbox by gmail app does not looks like menu items because it is static(it does not scroll) and fixed to the bottom.Lowney
Ahh, I understand now. I thought you were talking about the gmail app. I haven't installed the inbox app, but if you're looking for a static footer, then you're right, you have to use a separate layout. That shouldn't be too hard though. Let's see...Indeterminism
You want the footer to be fixed (not scroll). But you want it to scroll when the screen is small? Is that your requirement? That'll be harder to implement... Nevermind. I just installed the Inbox by Gmail app, and the nav menu footer is fixed in all cases. That should be pretty simple. I'll update my answer.Indeterminism
No, I want it fixed always inclusive on small screens, but of course the menu items yes.Lowney
I have used the @razzledazzle answer, I think his answer is more straightforward. Your solution appears to overlap the menu items on small screens, I have tried something similar. Thanks.Lowney
Just noticed this answer, this is good for scrolling footers. This would have been even more better if ordering of groups before items came into play, which unfortunately doesn't.Bina
I liked your approach, but I didn't like the part where you add fake items to the menu to push it up so it doesn't overlap with the footer. 1st, it looks hacky, 2nd, it's not "pixel perfect". That being sad, the way I solved it was by measuring the footer and adding a bottom padding as big as the footer's height to the menu itself.Beaker
you may use <dimen name="design_navigation_padding_bottom" tools:override="true">48dp</dimen> in dimen.xml instead of using dummy items in menu ! it's perfect !Elated
@Indeterminism it's working for me on small (4") screens but on my Nexus 6p the footer is completely gone and there is no scrollEggett
How can I set drawer item's font and font size for footer textview?Carbonic
F
39

I'll just give you the hint how to solve it, but I have no chance to test it on NavigationView, and am pretty sure it will work

here the sample layout xml;

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:clipToPadding="false"
  android:paddingBottom="96dp">

  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#6F00" />

  <TextView
    android:layout_width="match_parent"
    android:layout_height="96dp"
    android:layout_gravity="bottom"
    android:layout_marginBottom="-96dp"
    android:background="#600F" />

</FrameLayout>

here is the result:

enter image description here

the trick is by applying padding to parent and minus margin to the child.


Quick try:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.NavigationView 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"
  android:layout_gravity="start"
  android:clipToPadding="false"
  android:paddingBottom="96dp"
  app:headerLayout="@layout/sample_header"
  app:menu="@menu/sample_menu">


  <TextView
    android:layout_width="match_parent"
    android:layout_height="96dp"
    android:layout_gravity="bottom"
    android:layout_marginBottom="-96dp"
    android:background="#600F"
    android:gravity="center"
    android:text="I STAND BY MY SELF" />

</android.support.design.widget.NavigationView>

enter image description here

Farandole answered 8/6, 2015 at 9:41 Comment(4)
This may work, but negative margins are pretty hacky. So, personally, I avoid them if possible.Indeterminism
This footer, if you put down icons centered "botom" you can change depending on the screen and will be cut see this post #32460812Chive
Can you provide any link about full example ?Chive
can we set it to scrollable?Academe
P
34

Following the approaches described in the other answers of nesting navigation views, some problems came up:

  • With many items, or on landscape mode, the footer overlapped with the menu items
  • If the real menu has a lot of items, the nested NavigationView got scrollable, which was not looking nice
  • Having two NavigationViews in the nesting, did not allow to define custom views as footer.
  • Handling of nested scrollviews was a mess (sometimes two scrollbars showed up etc)
  • Fixed Footer should always be on the bottom (with few as well as with many menu items)

My solution for all of these problems was the following:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout ...>

    <include layout="@layout/main_content"/>

    <android.support.design.widget.NavigationView ...>

        <android.support.v4.widget.NestedScrollView
            ...
            android:fillViewport="true"
            android:scrollbars="vertical">

            <LinearLayout
                ...
                android:orientation="vertical">

                <android.support.design.widget.NavigationView
                    ...
                    app:elevation="0dp"
                    app:headerLayout="@layout/nav_header"
                    app:menu="@menu/nav_menu">
                </android.support.design.widget.NavigationView>

                <LinearLayout
                    android:id="@+id/spacer_to_bottom"
                    ...
                    android:layout_height="0dp"
                    android:layout_weight="1">
                </LinearLayout>

                <include layout="@layout/nav_footer"></include>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>

Here, the NestedScrollView acts as a scrolling parent for the sub-NavigationView. That means, the sub-NavigationView does never show up scrollbars itself, but the whole content is shown in a flat way.

The layout 'spacer_to_bottom' fills all remaining space, so that with few menu icons, the footer is still on the bottom.

Finally, the fixed footer is added to the linear layout,which starts with the real menu (sub-NavigationView), the spacer, and has on the bottom the footer.

Here you can find the complete working example as AndroidStudio-Project: https://github.com/MarcDahlem/AndroidSidemenuFooterExample

Especially the navigation drawer can be found here: https://github.com/MarcDahlem/AndroidSidemenuFooterExample/blob/master/app/src/main/res/layout/activity_main.xml

Screenshots:

Few items Many items

Priorate answered 8/6, 2016 at 23:3 Comment(7)
What exactly is not working? I can provide an example project if needed, which works great with a scrolling footer. @AndreaBaccegaPriorate
I agree with @AndreaBaccega, not working, only show the nav menu and doesn't show the footerSanasanabria
okay, second one with problems. I will create an example project and upload it to github. cu soonPriorate
I added an example project on github: github.com/MarcDahlem/AndroidSidemenuFooterExamplePriorate
Big upvote for the elevation attribute. I was going with the same approach, but couldn't get rid of the bottom shadow. Then, I found this. Thank you!Blaney
Thanks for your answer, it works well. The only thing that I found is the scroll of the navigation view, the scroll is not as smooth as it was before applying the trick with nested views. Any idea how to make it smooth also?Campball
Add a button instead of the linear layout in spacer_to_bottom. It will make the shadow disappear.Tetragonal
C
27

The simplest answer is to add a button inside the Drawer layout and set it gravity to bottom in the navigationview.xml.

Here is the code:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.NavigationView
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/navigation"
   android:layout_width="200dp"
   android:layout_height="match_parent"
   android:layout_gravity="start"
   app:headerLayout="@layout/navigation_header"
   app:menu="@menu/menu_navigation">
   
     <Button
            android:id="@+id/btn_sing_in"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="@string/sign_in"
            android:layout_gravity="bottom"/>

</android.support.design.widget.NavigationView>
Cofsky answered 20/7, 2016 at 8:50 Comment(3)
For few menu items, this might work. But as soon as you have many menu items, the button will overlap with the menu items on small devices or in landscape mode.Priorate
true however to overcome this you can put empty menu items.Cofsky
to allign bottom with empty menu items for different screensizes is nearly possible. But there is a general way to do this as I described in my solution ;-) --> see my solution https://mcmap.net/q/165578/-how-to-add-footer-to-navigationview-android-support-design-libraryPriorate
U
23

I know its late answer but its perfect and accurate answer which most developers looking for.

For adding footer in navigation view, Add custom view into navigation menu just like below:

footer_navigation_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content"
    android:orientation="horizontal">

    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/version" />

    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:gravity="right" />

</RelativeLayout>

Now, add above view into your menu xml with group attribute.So that, it can differentiate as footer in menu.

profile_menu.xml

<group android:checkableBehavior="single">

    <item
        android:id="@+id/nav_support"
        android:title="@string/nav_item_support" />

    <item
        android:id="@+id/nav_settings"
        android:title="@string/nav_item_settings" />

    <item
        android:id="@+id/nav_log_out"
        android:title="@string/nav_item_log_out" />
</group>
<group
    android:id="@+id/nav_footer">
    <item
        android:id="@+id/nav_log_version"
        app:actionLayout="@layout/footer_navigation_menu" />
</group>

That's it. Below is output:

enter image description here

Umber answered 1/10, 2018 at 4:45 Comment(4)
It will not work in case of complex bottom view because it gives fixed height to bottom view.Theriault
It might work, but there's no way to set onClickListeners to the views inside the footer layout...In my case I have social media buttons on the footer sending to external urls, but couldn't obtain the views using their ids in any way I could thought of...Platelayer
@RamiroG.M. nav_veiw.getmenu().finItemByid().actionalyout.findviewbyid().setOnclicklisnerPoop
Yes, @Sagar Maiyad your answer is accurate and most of the developers want this. For getting a view inside the custom layout you can use the below code: View footerView=nav_view.getMenu().findItem(R.id.footer).getActionView(); TextView licence = footerView.findViewById(R.id.licence); TextView version = footerView.findViewById(R.id.version);Wigan
C
17

You need to have a container navigation view layout and then that should contain two more navigation layouts. You align those to top and bottom of the parent layout.

I would recommend using a navigation view as the parent and not a FrameLayout because it's essentially a ScrimFrameLayout and interacts with the status bar better.

Here's an example of what your activity should look like:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_dashboard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">

<!-- Activity content goes here -->

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_drawer_container"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start">

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_drawer"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="top"
        app:menu="@menu/menu_navigation_drawer" />

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_drawer_bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:menu="@menu/menu_navigation_drawer_bottom" />

</android.support.design.widget.NavigationView>

You can read more about it and see an example here: http://blog.nitish.io/post/122633295558/android-design-library-navigationview-with-top

Choctaw answered 22/7, 2015 at 21:11 Comment(3)
It is really a nice solution. But wrap content doesn't working on both top and bottom NavigationView. You have to give some constant height to prevent bottom NavigationView block top NavigationView.Estis
perfect solutionRotund
@Nitish how to avoid overlap when "@+id/navigation_drawer" have more values in portrait mode. it went behind the bottom navigation view. In my case top navview menu items are dynamically populated, the bottom navview has static menu values.Esquiline
O
15

Its kind of a bummer that NavigationView does not have a provision to add footer. But you can try something like this,

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_base"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view_container"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:fitsSystemWindows="false"
        android:layout_gravity="start"
        >

        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scrollbarAlwaysDrawVerticalTrack="true"
            android:scrollbars="vertical"
            android:isScrollContainer="true"
            app:headerLayout="@layout/nav_header_base"
            app:menu="@menu/activity_base_drawer"
            android:layout_gravity="top"
            android:layout_marginBottom="x"
            />

        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view_footer"
            android:layout_width="wrap_content"
            android:layout_height="x"
            app:headerLayout="@layout/hear_layout"
            app:menu="@menu/menu_items"
            android:scrollbars="none"
            android:layout_gravity="bottom"
            />

    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

In case if your footer is a list,

    app:headerLayout="@null"
    app:menu="@menu/activity_base_drawer_footer"

But, if it is some kind of custom view,

    app:headerLayout="@layout/my_cutom_footer_view"
    app:menu="@null"

Also, in this case, you will need to set x = height of your custom footer view

Hope it helps.

Ongoing answered 5/5, 2016 at 9:32 Comment(4)
Thanks bro. you made my day..:)Pituri
3 NavigationViews? Why? For worst performances? Please, watch some of these videos: youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCEContortion
@LouisCAD If you have a solution that actually works, without negative margin, please share it with us. I have the problem mentioned here, and this is the only solution that I take in consideration. Maybe is not the perfect solution, and may have some performance impact... but without other implementation, do not just comment about performance matters. First of all, app requirements matter. If Google do not provide solution for your app requirements... you do not have many options.Thaumatrope
i think this is the proper way of doing it. Tried different answers from here and found this most helpful. thank youDover
O
12

enter image description hereI made the same thing in the following manner:

 <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer"
        >

        <LinearLayout android:layout_gravity="bottom"
            android:background="#20191d1e"
            android:layout_width="match_parent"
            android:paddingBottom="2dp"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="2dp"
            android:orientation="horizontal"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/company_image_id"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_margin="@dimen/margin1dp"
                android:padding="@dimen/margin2dp"
                android:src="@mipmap/ic_launcher_round"
                />

            <TextView
                android:id="@+id/txtCompanyName"
                android:layout_width="match_parent"                              android:layout_marginLeft="@dimen/margin3dp"
                android:layout_height="wrap_content"
                android:textSize="13dp" android:layout_gravity="center"
                android:textStyle="bold"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
        </LinearLayout>
    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

Here the main thing is that i put the layout gravity to bottom e.g.

LinearLayout android:layout_gravity="bottom"
Orsa answered 18/7, 2018 at 10:36 Comment(1)
With this solution bottom view will float over the menu items(if there are multiple menu items)...But I want it to be fixed in bottom.Theriault
N
8

This is how I achieve to add layout at bottom of navigation:

Updated libraries

    <com.google.android.material.navigation.NavigationView
    android:id="@+id/navigation_drawer_container"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

                <com.google.android.material.navigation.NavigationView
                    android:id="@+id/nav_view"
                    android:layout_width="wrap_content"
                    android:layout_height="0dp"
                    android:layout_gravity="top"
                    android:layout_weight="0.8"
                    app:headerLayout="@layout/nav_header_home"
                    app:menu="@menu/activity_home_drawer" />

                <com.google.android.material.navigation.NavigationView
                    android:id="@+id/navigation_drawer_bottom"
                    android:layout_width="wrap_content"
                    android:layout_height="0dp"
                    android:layout_weight="0.2">

                    <LinearLayout
                        android:id="@+id/linearLayout"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_alignParentBottom="true"
                        android:layout_below="@+id/scrollView"
                        android:orientation="vertical">

                        <TextView
                            android:id="@+id/text_dashboard_followUsAt"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:paddingLeft="16dp"
                            android:paddingStart="16dp"
                            android:text="Follow us at" />

                        <LinearLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:paddingLeft="16dp"
                            android:paddingStart="16dp">

                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:padding="5dp"
                                android:src="@drawable/fb" />

                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:padding="5dp"
                                android:src="@drawable/fb" />

                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:padding="5dp"
                                android:src="@drawable/fb" />
                        </LinearLayout>

                        <TextView
                            android:id="@+id/text_dashboard_version"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="end"
                            android:layout_marginTop="25dp"
                            android:paddingBottom="5dp"
                            android:paddingEnd="16dp"
                            android:paddingRight="16dp"
                            android:text="Version 1.0" />
                    </LinearLayout>
                </com.google.android.material.navigation.NavigationView>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</com.google.android.material.navigation.NavigationView>
Necrotomy answered 18/9, 2017 at 5:16 Comment(3)
This is right solution for adding footer layout at bottom of Navigation View. Although one linear-layout was not needed that i have edited in this answer.Theriault
How did you set navigation item selected listener in this activity? @zohaib khaliqTheriault
You would attach it to navViewIllinois
B
7

Following your approach, some minor changes can help what you want to achieve.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:background="@color/background_material_light">
    <TextView
       android:id="@+id/footer_item"
       android:layout_width="match_parent"
       android:layout_height="?attr/listPreferredItemHeight"
       android:background="?attr/selectableItemBackground"
       android:gravity="center_vertical"
       android:paddingLeft="?attr/listPreferredItemPaddingLeft"
       android:text="Something"
       android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>

And set some stub items in the menu, so that menu items don't overlap.

<group>
    ...
    <item
        android:title=""
        android:orderInCategory="200"/>
</group>

Also you would want to add a click listener to your footer item.

Bina answered 30/5, 2015 at 11:10 Comment(2)
Thanks for your answer, this gave me a workaround to add my footer, but I hope accept your answer if nobody give me a better answer for doing better. +1Lowney
Keep your options open indeed. Looking forward to better answers too as footers are important.Bina
F
6

My solution with fixed footer and scroll menus (100% tested)

 <android.support.design.widget.NavigationView
    android:id="@+id/container_navigation"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity=""
    android:nestedScrollingEnabled="true"
    android:scrollIndicators="none">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.NavigationView
            android:id="@+id/navigation"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_above="@+id/navigation2"
            android:layout_gravity="top"
            android:nestedScrollingEnabled="true"
            android:paddingBottom="@dimen/dimen_20_dp"
            app:headerLayout="@layout/nav_header"
            app:itemIconTint="@color/black_800"
            app:itemTextColor="@color/black_800"
            app:menu="@menu/navigation_drawer_items">

        </android.support.design.widget.NavigationView>

        <android.support.design.widget.NavigationView
            android:id="@+id/navigation2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="@color/white_100"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/empty_spacer"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:drawableTop="@drawable/ic_search"
                    android:gravity="center"
                    android:text="Share" />

                <TextView
                    android:id="@+id/mnuRate"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:drawableTop="@drawable/ic_search"
                    android:gravity="center"
                    android:text="Rate" />

                <TextView
                    android:id="@+id/mnuHelp"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:drawableTop="@drawable/ic_search"
                    android:gravity="center"
                    android:text="Help" />
            </LinearLayout>
        </android.support.design.widget.NavigationView>

    </RelativeLayout>

</android.support.design.widget.NavigationView>
Fathometer answered 2/11, 2015 at 8:17 Comment(0)
S
5

NavigationView first child is the ListView containing both header and menu items.

The only thing needed to add a footer is call .addFooterView to the ListView

More info: http://www.andreabaccega.com/blog/2015/08/28/how-to-add-footer-to-navigationview/

Copy paste code:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    ListView listView = (ListView) navigationView.getChildAt(0);
    View toRet = LayoutInflater.from(view.getContext()).inflate(R.layout.drawer_footer, listView, false);

    // Manipulate the view (if you need to) before calling addFooterView.

    listView.addFooterView(toRet, null, false);
  }
Submerse answered 28/8, 2015 at 12:33 Comment(2)
on the 'com.android.support:design:23.1.0' not work. it has become a RecyclerView in the NavigationMenuPresenterBrittnee
I added a new answer which might solve your problem.Poree
A
2

Just put another layout inside your NavigationView:

<android.support.design.widget.NavigationView 
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#000000"
        app:itemTextColor="#FFFFFF"
        app:headerLayout="@layout/fragment_side_menu_header"
        app:menu="@menu/side_menu">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="bottom">
        <TextView
            android:textColor="#FFFFFF"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test" />
        <TextView
            android:textColor="#FFFFFF"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test2" />
    </LinearLayout>
</android.support.design.widget.NavigationView>

The trick is to use layout_gravity="bottom" - this will put your whole layout at the bottom and test,test2 are properly stacked.

Adipocere answered 23/7, 2015 at 13:49 Comment(0)
M
2

use this..

<android.support.design.widget.NavigationView
    android:id="@+id/navigation"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/nav_header"
    app:itemIconTint="@color/accent"
    app:itemTextColor="@color/primary_text"
    app:menu="@menu/navigation_drawer_items">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="@color/grey_200"
        android:orientation="vertical">

        <View
            android:layout_width="match_parent"
            android:layout_height="@dimen/divider_height"
            android:background="@color/grey_600"/>

        <com.facebook.share.widget.LikeView
            android:id="@+id/like_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:padding="@dimen/small"/>

        <com.facebook.login.widget.LoginButton
            android:id="@+id/login_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/small"/>
    </LinearLayout>
</android.support.design.widget.NavigationView>

then set bottom padding to NavigationMenuView

final View menuView = navigationView.getChildAt(0);
final View bottomView = navigationView.getChildAt(1);
bottomView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            menuView.setPadding(0, 0, 0, bottomView.getMeasuredHeight());
        }
    });
Marylinmarylinda answered 4/1, 2016 at 14:8 Comment(0)
S
2

Try this, this work for me.

<android.support.design.widget.NavigationView
                    android:id="@+id/nav_view1"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_gravity="start"
                    android:fitsSystemWindows="true">

                    <ScrollView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent">

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

                        <android.support.design.widget.NavigationView
                            android:layout_width="wrap_content"
                            android:layout_height="match_parent"
                            android:id="@+id/nav_view"
                            app:headerLayout="@layout/nav_header_admin"
                            app:menu="@menu/activity_admin_drawer"/>

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:orientation="vertical"
                            android:id="@+id/lyNavFooter">

                           <!--INCLUDE YOUR FOOTER HERE -->

                        </LinearLayout>
                    </LinearLayout>

                    </ScrollView>



                </android.support.design.widget.NavigationView>
Sanasanabria answered 20/9, 2016 at 17:48 Comment(0)
G
1

I use this form, work for me. in landscape & portrait.

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.NavigationView
            android:id="@+id/navigation"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:headerLayout="@layout/master_main_header"
            app:itemIconTint="@color/blue"
            app:menu="@menu/menu_drawer">

        </android.support.design.widget.NavigationView>

        <Button
            android:id="@+id/master_btn_closession"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:background="@color/blue"
            android:text="Cerrar sesión" />
    </LinearLayout>
</android.support.design.widget.NavigationView>
Gamone answered 13/1, 2016 at 22:29 Comment(0)
R
1

<include
    layout="@layout/app_bar_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<android.support.design.widget.NavigationView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/activity_main_drawer">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:scrollbars="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <android.support.design.widget.NavigationView
                android:id="@+id/nav_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:elevation="0dp"
                app:headerLayout="@layout/nav_header_main"
                app:menu="@menu/activity_main_drawer">
                ></android.support.design.widget.NavigationView>

            <LinearLayout
                android:id="@+id/spacer_to_bottom"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:orientation="vertical" />

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginBottom="0dp">

        <include layout="@layout/nav_footer_main" />

    </LinearLayout>
</android.support.design.widget.NavigationView>

Ramses answered 27/12, 2016 at 10:27 Comment(2)
Add some explanation with answer for how this answer help OP in fixing current issueClouse
I've got the solution.you must include a static layout for the footer, inside the <android.support.design.widget.NavigationView>...</android.support.design.widget.NavigationView>. for more detail please check github repocitory (github.com/mehul0/AndroidSidemenuFooterExample-master)Ramses
P
1

This is working for me to put images on footer of navigation drawer(portrait and Landscape orientation)

    <?xml version="1.0" encoding="utf-8"?>
        <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/drawer_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            tools:openDrawer="start">

            <include
                layout="@layout/app_bar_main3"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <android.support.design.widget.NavigationView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="start"
                android:background="#f00"
                android:fitsSystemWindows="true"
                app:menu="@menu/activity_main3_drawer">

                <android.support.v4.widget.NestedScrollView
                    android:layout_width="match_parent"
                    android:fillViewport="true"
                    android:layout_height="match_parent"
                    android:scrollbars="vertical">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical">

                        <android.support.design.widget.NavigationView
                            android:id="@+id/nav_view"
                            app:elevation="0dp"
                            android:layout_height="wrap_content"
                            android:layout_width="match_parent"
                                android:background="#ff0"
                            app:headerLayout="@layout/nav_header_main3"
                            app:menu="@menu/activity_main3_drawer">
                            ></android.support.design.widget.NavigationView>

                        <LinearLayout
                            android:id="@+id/spacer_to_bottom"
                            android:layout_width="match_parent"
                            android:orientation="vertical"
                            android:background="#0f0"
                            android:layout_height="0dp"
                            android:layout_weight="1">
                            <include layout="@layout/nav_footer_main3"></include>
                        </LinearLayout>


                    </LinearLayout>
                </android.support.v4.widget.NestedScrollView>
            </android.support.design.widget.NavigationView>

        </android.support.v4.widget.DrawerLayout>

my nav_footer_main3 is

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="60dp">
        <ImageView
            android:id="@+id/imageView"
            android:layout_gravity="center_horizontal"
            android:layout_width="200dp"
            android:layout_height="50dp"
            android:background="@drawable/logo_1" />
    </LinearLayout>
Pasquil answered 22/1, 2017 at 17:34 Comment(0)
A
1

The layout structure for sticky header and footer in the drawer menu:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout>

    <android.support.design.widget.AppBarLayout>
        <android.support.v7.widget.Toolbar/>
    </android.support.design.widget.AppBarLayout>

    <LinearLayout>
        <include layout="@layout/drawer_header"/>
        <android.support.design.widget.NavigationView/>
        <include layout="@layout/drawer_footer"/>
    </LinearLayout>

</android.support.v4.widget.DrawerLayout>

The complete layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:elevation="0dp">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay" >
        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:layout_gravity="start"
        android:orientation="vertical">
        <include layout="@layout/drawer_menu_header"/>

        <android.support.design.widget.NavigationView
            android:id="@+id/drawer_menu_body"
            app:elevation="0dp"
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:background="@color/white"
            android:theme="@style/AppTheme.PopupOverlay"
            app:menu="@menu/main_drawer">
        </android.support.design.widget.NavigationView>

        <include layout="@layout/drawer_menu_footer"/>
    </LinearLayout>

</android.support.v4.widget.DrawerLayout>
Ascocarp answered 18/5, 2018 at 16:33 Comment(0)
B
1

Try this, this work for me.https://github.com/MarcDahlem/AndroidSidemenuFooterExample/blob/master/app/src/main/res/layout/activity_main.xml

However, you to disable NavigationViewScrolling for smoother scrolling

private void disableNavigationViewScrolling(NavigationView navigationView) {
    if (navigationView != null) {
        NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView.getChildAt(0);
        if (navigationMenuView != null) {
            navigationMenuView.setNestedScrollingEnabled(false);
        }
    }
}

Screenshots:

Bultman answered 20/5, 2018 at 10:0 Comment(0)
N
1

Here's a solution that doesn't require nesting and which dynamically adjusts the bottom padding of the internal NavigationMenuView based on the footer view's own height, which means the footer height can be set to wrap_content and you can dynamically change the footer's visibility to VISIBLE or GONE.

public class NavigationMenuFooterView extends LinearLayout {

    public NavigationMenuFooterView(Context context) {
        super(context);
    }

    public NavigationMenuFooterView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public NavigationMenuFooterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        update(getHeight());
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        update(h);
    }

    private void update(int height) {

        ViewParent parent = getParent();
        if (parent instanceof ViewGroup) {
            View navigationMenuView = ((ViewGroup) parent).findViewById(R.id.design_navigation_view);
            if (navigationMenuView != null) {
                if (getVisibility() == View.GONE) {
                    height = 0;
                }
                navigationMenuView.setPadding(navigationMenuView.getPaddingLeft(),
                        navigationMenuView.getPaddingTop(), navigationMenuView.getPaddingRight(), height);
            }
        }
    }
}

You need to define the id of design_navigation_view in your ids.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <item name="design_navigation_view" type="id"/>
    </resources>

And use like this:

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:itemBackground="@drawable/drawer_item"
        app:itemIconTint="@color/drawer_item"
        app:itemTextColor="@color/drawer_item"
        app:menu="@menu/menu_drawer">

        <util.NavigationMenuFooterView
            android:id="@+id/navigation_footer_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="#fff"
            android:orientation="vertical">

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#ddd" />

            <include layout="@layout/..." />

        </util.NavigationMenuFooterView>

    </com.google.android.material.navigation.NavigationView>

Tested with com.google.android.material:material:1.0.0.

Ninon answered 11/10, 2019 at 12:7 Comment(1)
This is a really nice solution. I used actionLayout solution where footer was also in the menu.xml file but I had applied background to list item so that background was also applied to footer layout. Applying footer this way will not have that kind of issue.Eydie
M
1

i was able by creating two layouts one with header elements and other with footer elements and then include them to the NavigationView:

    <com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    app:headerLayout="@layout/nav_header"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:itemTextColor="@color/white"
    app:menu="@menu/conversation_menu"
    android:background="@color/nav"
    android:fitsSystemWindows="true">

    <!-- Header layout -->
    <include layout="@layout/nav_header" />
    <include layout="@layout/nav_footer" />
    <!-- Scrollable conversations -->
    <androidx.core.widget.NestedScrollView
        android:id="@+id/conversationsScrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/nav_view"
        app:layout_constraintBottom_toTopOf="@id/nav_footer">

        <LinearLayout
            android:id="@+id/conversationsLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <!-- Your conversation items added dynamically -->
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>


</com.google.android.material.navigation.NavigationView>
Mysia answered 19/11, 2023 at 11:36 Comment(0)
P
0

Scrolling footer for Version > 23.x.x

I finally managed to achieve what I wanted, unfortunately it looks like it is not longer possible to just grab the reference to the ListView and add a header and footer as in versions below 23.x.x (as described by Andrea Baccega). Doing this for the header is still possible:

     <android.support.design.widget.NavigationView
     ..
     app:headerLayout="@layout/item_drawer_footer"
     ..
     />

But adding a footer is not possible at the moment. However, I found a workaround in case you are just trying to add a footer: You just reverse the view, this will add the header to the bottom which behaves like a normal footer. Just make sure to create your menu in reverse order

    // Grab reference to the embedded recycler view
    RecyclerView mRecyclerView = (RecyclerView) navigationView.getChildAt(0);

    // Create a LinearLayoutManager and set it to reversed
    LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
    mLayoutManager.setReverseLayout(true);

    // Apply layout manager to the recycler view
    mRecyclerView.setLayoutManager(mLayoutManager);
Poree answered 26/3, 2017 at 13:15 Comment(0)
K
0

My personal solution for fixed header and footer is extending NavigationView as following:

/**
 * Created by guness on 17.01.2018.
 */
class NavigationView : android.support.design.widget.NavigationView {

private var mHeader: View? = null
private var mFooter: View? = null
private var mMenuView: NavigationMenuView? = null

constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
    val a = TintTypedArray.obtainStyledAttributes(context, attrs,
            R.styleable.NavigationView, defStyleAttr,
            R.style.Widget_Design_NavigationView)

    if (a.hasValue(R.styleable.NavigationView_footerLayout)) {
        inflateFooterView(a.getResourceId(R.styleable.NavigationView_footerLayout, 0))
    }

    a.recycle()

    (mFooter?.layoutParams as FrameLayout.LayoutParams?)?.gravity = Gravity.BOTTOM
}

init {
    (0 until childCount)
            .map { getChildAt(it) }
            .filter { it is NavigationMenuView }
            .forEach {
                mMenuView = it as NavigationMenuView
                mMenuView!!.overScrollMode = View.OVER_SCROLL_NEVER
            }
}

override fun inflateHeaderView(@LayoutRes res: Int): View {
    mHeader = LayoutInflater.from(context).inflate(res, this, false)
    setHeaderView(mHeader!!)
    return mHeader!!
}

@Deprecated("There can only be one header", ReplaceWith("#setHeaderView(view: View)"))
override fun addHeaderView(view: View) {
    throw IllegalAccessException("Please use #setHeaderView")
}

@UiThread
fun setHeaderView(view: View) {
    removeHeaderView()
    mHeader = view
    addView(mHeader, 0)
}

@Deprecated("No need to use params", ReplaceWith("#removeHeaderView()"))
override fun removeHeaderView(view: View) {
    removeHeaderView()
}

@UiThread
fun removeHeaderView() {
    if (mHeader != null) {
        removeView(mHeader)
        mHeader = null
    }
}

@Deprecated("No need to count, it is either 1 or zero", ReplaceWith("#hasHeader()"))
override fun getHeaderCount(): Int {
    return if (mHeader == null) 0 else 1
}

@Deprecated("No need to use params", ReplaceWith("#getHeaderView()"))
override fun getHeaderView(index: Int): View? {
    return getHeaderView()
}

fun getHeaderView(): View? {
    return mHeader
}

fun hasHeader(): Boolean {
    return mHeader != null
}

fun inflateFooterView(@LayoutRes res: Int): View {
    mFooter = LayoutInflater.from(context).inflate(res, this, false)
    setFooterView(mFooter!!)
    return mFooter!!
}

@UiThread
fun setFooterView(view: View) {
    removeFooterView()
    mFooter = view
    addView(mFooter, 0)
}

@UiThread
fun removeFooterView() {
    if (mFooter != null) {
        removeView(mFooter)
        mFooter = null
    }
}

fun hasFooter(): Boolean {
    return mFooter != null
}

fun getFooterView(): View? {
    return mFooter
}

fun setOnClickListener(@IdRes res: Int, listener: View.OnClickListener) {
    mHeader?.findViewById<View>(res)?.setOnClickListener(listener)
    mFooter?.findViewById<View>(res)?.setOnClickListener(listener)
}

override fun onMeasure(widthSpec: Int, heightSpec: Int) {
    super.onMeasure(widthSpec, heightSpec)
    val headerHeight = mHeader?.measuredHeight ?: 0
    val footerHeight = mFooter?.measuredHeight ?: 0
    val params = (mMenuView?.layoutParams as ViewGroup.MarginLayoutParams?)
    var changed = false
    if (params?.topMargin != headerHeight) {
        params?.topMargin = headerHeight
        changed = true
    }
    if (params?.bottomMargin != footerHeight) {
        params?.bottomMargin = footerHeight
        changed = true
    }
    if (changed) {
        mMenuView!!.measure(widthSpec, heightSpec)
    }
}
}

Originally NavigationView creates an LinearLayout as first item on the RecyclerView and scrolls all the content together. The idea on this is to create separate Views for footer and header and then, push them to top and bottom using Gravity. Later on measuring content for RecyclerView settles the scrolling content.

Here is the library that contains above code I wrote. https://github.com/guness/NavigationView

Good side of this, now I can define footer view on the xml just like the header on native:

    app:footerLayout="@layout/nav_footer_main"
    app:headerLayout="@layout/nav_header_main"
Kingsize answered 17/1, 2018 at 21:28 Comment(0)
R
0

If you are using listview, you can try this way. The list view support add footer view function, so you can add a custom footer R.layout.drawer_footer view using listview object as below code

View footerView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.drawer_footer, expandableListView, false);
TextView footer = footerView.findViewById(R.id.id_footer_wta_version_information);
expandableListView.addFooterView(footerView);

In my case, I use expandableListView instead of listview (the listview also has addFooter function). Hope this way help you

Rogelioroger answered 15/7, 2020 at 8:26 Comment(0)
B
0

For my case I need to keep the "LogOut" item at the bottom of the "NavigationView" always if has enough space or "emulate" some scroll if don't fit.

The goal was to accomplish that without big changes and of course without adding nested NavigationViews.

The solution that works for me is the following:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <androidx.drawerlayout.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navigation_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:clipToPadding="false"
            android:clipChildren="false"
            android:overScrollMode="never"
            android:fitsSystemWindows="true"
            android:maxWidth="300dp"
            app:headerLayout="@layout/nav_drawer_header"
            app:itemBackground="@drawable/bg_nav_drawer_item"
            app:itemHorizontalPadding="25dp"
            app:itemIconPadding="25dp"
            app:itemIconTint="@color/nav_drawer_item_icon"
            app:itemTextAppearance="@style/NavigationDrawerTextStyle"
            app:itemTextColor="@color/nav_drawer_item_text"
            app:menu="@menu/navigation_drawer_menu">

            <LinearLayout
                android:id="@+id/ll_activity_main_log_out"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="?attr/selectableItemBackground"
                android:orientation="horizontal"
                android:layout_marginBottom="10dp"
                android:paddingStart="30dp"
                tools:ignore="RtlSymmetry">

                <androidx.appcompat.widget.AppCompatImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:src="@drawable/ic_log_out"
                    android:tint="@color/gray_B3BAC2" />

                <TextView
                    style="@style/TextBodyBold.Large"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingVertical="20dp"
                    android:paddingStart="25dp"
                    android:paddingEnd="50dp"
                    android:text="@string/label_logout"
                    android:textColor="@color/gray_B3BAC2" />
            </LinearLayout>
        </com.google.android.material.navigation.NavigationView>
    </androidx.drawerlayout.widget.DrawerLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var mainActivityBinding: ActivityMainBinding
    // ...
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mainActivityBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        mainActivityBinding.apply {
            lifecycleOwner = this@MainActivity
            llActivityMainLogOut.setOnClickListener { mainViewModel.handleOnLogoutUserPress() }
        }
    }

    private var onScrollListener: RecyclerView.OnScrollListener? = null

    /**
     * Listener for "Logout" Drawer Menu Item that checks if should
     * add a scrollListener (and update bottom margin) or keep the item at the bottom of the view.
     */
    private val navigationViewGlobalLayoutListener = object : OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            // Get the NavigationView RecyclerView List Menu
            val drawerViewList = mainActivityBinding.navigationView.getChildAt(0) as RecyclerView

            if (onScrollListener == null) {
                val scrollExtent = drawerViewList.computeVerticalScrollExtent()
                val scrollRange = drawerViewList.computeVerticalScrollRange()
                // Check if the list has enough height space for all items
                if (scrollExtent < scrollRange) {
                    // Adding NavigationView Bottom padding. Is where the logoutItem goes
                    mainActivityBinding.navigationView.setPadding(
                        0,
                        0,
                        0,
                        resources.getDimensionPixelSize(R.dimen.drawer_layout_footer_padding_bottom)
                    )

                    // The first item of the list is a Header, getting the second menu item height
                    val itemHeight = drawerViewList.getChildAt(1).measuredHeight
                    // The first update will add enough negative bottom margin and will hide the item
                    updateDrawerLogoutItemBottomMargin(scrollExtent, scrollRange, itemHeight)

                    onScrollListener = object : RecyclerView.OnScrollListener() {
                        private var totalScrollY = 0

                        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                            totalScrollY += dy

                            updateDrawerLogoutItemBottomMargin(
                                recyclerView.computeVerticalScrollExtent(),
                                recyclerView.computeVerticalScrollRange(),
                                recyclerView.getChildAt(1).measuredHeight,
                                totalScrollY
                            )
                        }
                    }

                    // Adding scroll listener in order to update the bottom logOut item margin
                    // while the list is being scrolled
                    drawerViewList.addOnScrollListener(onScrollListener!!)
                }
            } else {
                // The listener have been already added and computed, removing
                drawerViewList.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        }
    }

    /**
     * @param scrollExtent the current height of the list
     * @param scrollRange the height that needs the list for showing all items
     * @param itemHeight the height of a Menu Item (not header)
     * @param extraScroll scroll offset performed
     */
    private fun updateDrawerLogoutItemBottomMargin(
        scrollExtent: Int,
        scrollRange: Int,
        itemHeight: Int,
        extraScroll: Int = 0
    ) {
        mainActivityBinding.llActivityMainLogOut.updateLayoutParams {
            this as MarginLayoutParams
            bottomMargin = scrollExtent - scrollRange - itemHeight + extraScroll
        }
    }

    override fun onResume() {
        super.onResume()
        mainActivityBinding.navigationView.viewTreeObserver.addOnGlobalLayoutListener(
            navigationViewGlobalLayoutListener
        )
    }

    override fun onPause() {
        super.onPause()
        if (onScrollListener != null) {
            (mainActivityBinding.navigationView.getChildAt(0) as RecyclerView)
                .removeOnScrollListener(onScrollListener!!)
        }
    }

    //...
}

The android:clipChildren="false" and android:clipToPadding="false" in the activity_main.xml NavigationView are mandatory params.

Each case may need different bottom padding in order to add the "extra" drawer item, in my case, the value was: <dimen name="drawer_layout_footer_padding_bottom">70dp</dimen>

And of course don't forget to register the on GlobalLayoutListener in the onResume method and unregister the scrollListener in onPause method if has been registered.

Barboza answered 13/10, 2022 at 15:51 Comment(0)
I
-2

Put these lines into your menu layout. I hope it will fix your issue:

    <group
        android:id="@+id/grp11"
        android:checkableBehavior="single">

        <item


            android:title="" />
        <item


            android:title="" />
        <item

            android:title="" />
        <item


            android:title="" />
        <item


            android:title="" />
        <item

            android:title="" />

    </group>
Isobath answered 5/2, 2020 at 7:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.