13

I need to put Switch inside item in navigation drawer. I'm using new design support library, but I cannot find if it is posibble at all. When using

android:checkable

item is just full selected and that is not what I wish.

This is screenshot of what I really want. Is that possible to achieve that?

enter image description here

Marcin Lagowski
  • 628
  • 2
  • 12
  • 26
  • Hello @mlody, I wanted to ask. How do you add that switch in the Navigation Drawer. I have asked a question here = http://stackoverflow.com/questions/33951901/android-design-navigation-drawer-how-to-add-a-switch-in-nav-xml - Thanks – Thiago Nov 27 '15 at 07:05
  • @Joolah Unfortunately I havent added this switch, because I didnt found way to do that without external NavigationDrawer. – Marcin Lagowski Nov 29 '15 at 00:32

9 Answers9

27

Your menu item for the navigation drawer:

<item
    android:id="@+id/nav_item1"
    android:icon="@drawable/ic_item1"
    android:title="item1"
    app:actionLayout="@layout/layout_switch"
    />

and the layout for that item:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/drawer_switch"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:text=""/>

</LinearLayout>

EDIT:

I ended up using a different approach. In fact, I found out that you can use any view in the drawer, so there's no point in bothering with the menu stuff. Just create a view the usual way (with listeners, etc.) and add in to the drawer.

lenooh
  • 10,364
  • 5
  • 58
  • 49
  • 2
    Thank you very much. It works. I regret that I did not know that a year ago. – Marcin Lagowski Oct 16 '16 at 19:49
  • How to add listener for switch, can you add codes to your respond plesae – mehmet Apr 01 '17 at 05:13
  • 3
    How do you add a listener to the switch since you apparently can't do it the normal way. – codemoonger Jun 26 '17 at 18:36
  • mehmet & mogren3000: I ended up using a different approach. In fact, I found out that you can use *any* view in the drawer, so there's no point in bothering with the menu stuff. Just create a view the usual way (with listeners, etc.) and add in to the drawer. – lenooh Feb 23 '18 at 21:11
  • How to know if switch has toggled in java file ? – gautam Apr 18 '18 at 18:18
  • @lenooh if i use this in my menu, how listen for switch? – roghayeh hosseini Aug 28 '18 at 05:45
  • roghayeh hosseini: As I wrote in my comment " I ended up using a different approach. In fact, I found out that you can use any view in the drawer, so there's no point in bothering with the menu stuff. Just create a view the usual way (with listeners, etc.) and add in to the drawer." – lenooh Aug 28 '18 at 12:22
  • your code does not work. I kept getting ```Error inflating class com.google.android.material.navigation.NavigationView``` – EdgeDev Dec 13 '19 at 06:32
  • EdgeDev: there's something wrong with *your* code. Check your `NavigationView` stuff. Anyway, I don't recommend this approach, see my comment. – lenooh Dec 13 '19 at 13:45
  • instead `app:actionLayout` use `app:actionViewClass="com.google.android.material.switchmaterial.SwitchMaterial"` – Falchio Jan 30 '23 at 16:18
15

One way I have found of doing this would be to use setActionView on the menuItem you want:

mNavigationView.getMenu().findItem(R.id.nav_connect)
        .setActionView(new Switch(this));

// To set whether switch is on/off use:
((Switch) mNavigationView.getMenu().findItem(R.id.nav_connect).getActionView()).setChecked(true);

Probably want a click listener as well to change the state of the Switch:

mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {

        switch (menuItem.getItemId()) {
            case R.id.nav_connect:
                ((Switch) menuItem.getActionView()).toggle();
                return true;
        }
    }
}

I haven't tried, but you could probably use android:actionLayout="@layout/switch_layout" in xml and point to a custom layout you created.

Also could try using an ActionProvider which might offer a little more robustness. I haven't tried this method either though.

bmhoncho
  • 321
  • 2
  • 10
  • Disclaimer:Please confirm that you are using app:actionLayout="@layout/layout_menu_profile" and not android:actionLayout="@layout/layout_menu_profile" – Abraham Mathew May 12 '20 at 10:42
14

None of the answers seems to be complete so after some more research here is what I came up with:

drawer_switch.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.SwitchCompat 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_switch"
    android:layout_width="fill_parent"
    android:layout_height="match_parent" />

drawer_menu.xml:

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

    <item android:title="@string/header">
        <menu>
            <item
                android:id="@+id/switch_item"
                android:icon="@drawable/ic_switch_item"
                app:actionLayout="@layout/drawer_switch"
                android:title="@string/switch_item" />
        </menu>
    </item>
</menu>

DrawerActivity.java:

SwitchCompat drawerSwitch = (SwitchCompat) navigationView.getMenu().findItem(R.id.switch_item).getActionView();
drawerSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    // do stuff
                } else {
                    // do other stuff
                }
            }
});

DrawerActivity.java:

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

    int id = item.getItemId();

    if (id == R.id.switch_item) {
        return false;
    }

    closeDrawer();
    return true;
}
Sir Codesalot
  • 7,045
  • 2
  • 50
  • 56
  • If you get NULLPointer try this - switch is referenced inside nav item. (Switch) navigationView.getMenu().findItem(R.id.item).getActionView().findViewById(R.id.switch); – Pradeesh tet Mar 21 '20 at 18:03
  • Disclaimer:Please confirm that you are using app:actionLayout="@layout/layout_menu_profile" and not android:actionLayout="@layout/layout_menu_profile" – Abraham Mathew May 12 '20 at 10:39
  • @AbrahamMathew yes I am. You can see it in the answer itself. – Sir Codesalot May 12 '20 at 11:02
3

I did something like this.

navigationView.getMenu().findItem(R.id.vibrate)
            .setActionView(new Switch(this));

    Switch vibrateSwitch =(Switch) 
navigationView.getMenu().findItem(R.id.vibrate).getActionView();
    vibrateSwitch.setChecked(true);
    vibrateSwitch.setOnCheckedChangeListener(new 
CompoundButton.OnCheckedChangeListener(){
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean 
isChecked){
                SharedPreferences sharedPreferences = 
getSharedPreferences(getString(R.string.MyPREFERENCES), MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putBoolean(getString(R.string.VIBRATE), isChecked);
                editor.commit();
        }

    });
Arun
  • 41
  • 2
2

For those of you using Kotlin Extensions

  1. Menu file
<menu 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">

    <item
        android:id="@+id/nav_notifications_switch"
        android:icon="@drawable/ic_notifications"
        android:title="@string/notifications"
        app:actionLayout="@layout/drawer_notifications_switch" />

</menu>
  1. Switch layout file
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toggleSwitch"
    android:layout_width="fill_parent"
    android:layout_height="match_parent" />
  1. Access in code
nav_view.menu.findItem(R.id.nav_notifications_switch)
    .actionView
    .toggleSwitch
    .setOnCheckedChangeListener { _, isChecked ->
        
    }
aneurinc
  • 1,238
  • 12
  • 20
1

simply yes you can do this easily, i will post my code so you can implement it

<item android:id="@+id/nav_item_1"
        android:title="Android"
        android:icon="@drawable/ic_android_black_24dp"
        android:checked="true"/>

and the Main Activity Layout should be :

<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"
tools:context=".MainActivity">

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

    <android.support.v7.widget.Toolbar
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

    <TextView
        android:id="@+id/content_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="50dp"
        android:text="Your Content Goes Here"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="@color/colorAccent" />

    <!-- your content layout -->

</LinearLayout>

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

And here's a step by step tutorial for Navigation Drawer using Design Library

Fareed
  • 560
  • 2
  • 7
  • 23
1

In res -> menu -> menu.xml create <item> with field: app:actionViewClass
example:

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

        <item android:title="">
            <menu>
                <group android:checkableBehavior="single">

                    <item
                        android:checkable="false"
                        android:id="@+id/is_night_mode"
                        android:icon="@drawable/main_navigation_night_mode_light"
                        android:title="@string/main_navigation_night_mode"
                        app:actionViewClass="com.google.android.material.switchmaterial.SwitchMaterial" />
           
                </group>
            </menu>
        </item>
    </menu>

Next in Activity or Fragment find actionView like this:

val nightModeSwitch = binding.navView.menu.findItem(R.id.is_night_mode).actionView as SwitchMaterial

Set OnCheckedChangeListener

nightModeSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
    //do something
}
Falchio
  • 174
  • 1
  • 14
0

You should be able to.

Your navigation drawer view can be a LinearLayout, and inside that, you can include your NavigationView and another ViewGroup adding the switches.

Farbod Salamat-Zadeh
  • 19,687
  • 20
  • 75
  • 125
  • Do you mean to put between tags? I can do that but all I got is text view and switch drawn on navigation drawer ImageView not as part of it but on it. – Marcin Lagowski Jun 13 '15 at 22:36
0

If you have to update the switch in navigation with respect to it's toggling then it's better to use two different menu layouts with checked switch and without checked switch. So by checking the current state you can easily change the navigation drawer.