Toggle Button in Navigation Drawer

sonovice picture sonovice · Mar 22, 2015 · Viewed 13.4k times · Source

I am trying to implement a toggle button into the Navigation Drawer Project, that Android Studio can automatically generate. In the end I want to have something like this ("Downloaded only"-Button):

enter image description here

Unfortunately I don't understand how to add a toggle button to the ListView of the NavDrawer. I could probably use one of the "Custom NavDrawer Libs" out there but I would like to understand the way Google proposes it with the auto generated example.

Any ideas on how to implement this into the default NavDrawer Project?

Answer

HeW picture HeW · Mar 22, 2015

I would do something like this: instead of using a listview I would use an RecyclerView. Then I create three different layout definitions for the label with icon, the divider and the label with optional switch. Your RecyclerView Adapter should extend Form RecyclerView.Adapter. For each of those three layouts you should create an own implementation of ViewHolder. Now you have to create several classes for the list items and one superclass for all of them. In your Adapter you have to override the getViewType method. Tomorrow when I'm at work I could post some demo code for you.

Edit:

activity_main.xml

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

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="de.devhew.navigationdrawerexample.MainActivity">

    <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/toolbar_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        app:popupTheme="@style/AppTheme.Toolbar.Overflow"
        app:theme="@style/AppTheme.Toolbar" />

    <FrameLayout
        android:id="@+id/main_content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

<fragment
    android:id="@+id/fragment_navigation_drawer"
    android:name="de.devhew.navigationdrawerexample.drawer.NavigationDrawerFragment"
    android:layout_width="280dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:layout="@layout/fragment_navigation_drawer"
    tools:layout="@layout/fragment_navigation_drawer" />

MainActivity.java

public class MainActivity extends ActionBarActivity {

private Toolbar toolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    toolbar = (Toolbar) findViewById(R.id.toolbar_main);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    List<NavDrawerEntry> drawerEntries = new ArrayList<>();
    drawerEntries.add(new NavDrawerItemWithIcon("Home", R.drawable.app_generic));
    drawerEntries.add(new NavDrawerItemWithIcon("People", R.drawable.app_generic));
    drawerEntries.add(new NavDrawerItemWithIcon("Stuff", R.drawable.app_generic));
    drawerEntries.add(new NavDrawerDivider());
    drawerEntries.add(new NavDrawerItem("Settings"));
    drawerEntries.add(new NavDrawerToggle("Wifi only"));

    NavigationDrawerFragment drawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
    drawerFragment.init((android.support.v4.widget.DrawerLayout) findViewById(R.id.drawer_layout),
            toolbar, drawerEntries);
}}

NavigationDrawerFragment.java

public class NavigationDrawerFragment extends Fragment {

private View root;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private RecyclerView mRecyclerView;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    root = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
    return root;
}

public void init(DrawerLayout drawerLayout, final Toolbar toolbar, List<NavDrawerEntry> drawerEntries) {
    mDrawerLayout = drawerLayout;
    mDrawerToggle = new ActionBarDrawerToggle(getActivity(),
            drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
        @Override
        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
            getActivity().invalidateOptionsMenu();
        }

        @Override
        public void onDrawerClosed(View drawerView) {
            super.onDrawerClosed(drawerView);
            getActivity().invalidateOptionsMenu();
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
    mDrawerLayout.post(new Runnable() {
        @Override
        public void run() {
            mDrawerToggle.syncState();
        }
    });

    mRecyclerView = (RecyclerView) root.findViewById(R.id.nav_list);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    mRecyclerView.setHasFixedSize(true);

    NavigationDrawerAdapter adapter = new NavigationDrawerAdapter(getActivity(), drawerEntries);
    mRecyclerView.setAdapter(adapter);
}}

NavigationDrawerAdapter.java

public class NavigationDrawerAdapter
    extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private List<NavDrawerEntry> data;
private LayoutInflater inflater;

public NavigationDrawerAdapter(Context context, List<NavDrawerEntry> data) {
    this.data = data;
    this.inflater = LayoutInflater.from(context);
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

    View itemLayoutView;
    switch (viewType) {
        case 0:
            itemLayoutView = inflater.inflate(R.layout.layout_nav_drawer_item_with_icon, viewGroup, false);
            ItemWithIconVH holder = new ItemWithIconVH(itemLayoutView);
            return holder;
        case 1:
            itemLayoutView = inflater.inflate(R.layout.layout_nav_drawer_divider, viewGroup, false);
            DividerVH dividerViewHolder = new DividerVH(itemLayoutView);
            return dividerViewHolder;
        case 2:
            itemLayoutView = inflater.inflate(R.layout.layout_nav_drawer_item, viewGroup, false);
            ItemVH itemViewHolder = new ItemVH(itemLayoutView);
            return itemViewHolder;
        case 3:
            itemLayoutView = inflater.inflate(R.layout.layout_nav_drawer_toggle, viewGroup, false);
            ToggleVH toggleViewHolder = new ToggleVH(itemLayoutView);
            return toggleViewHolder;
    }
    return null;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    final NavDrawerEntry item = data.get(position);

    if (item instanceof NavDrawerItemWithIcon) {
        ItemWithIconVH viewHolder = (ItemWithIconVH) holder;
        viewHolder.mTitle.setText(((NavDrawerItemWithIcon) item).getTitle());
        viewHolder.mImageView.setImageResource(((NavDrawerItemWithIcon) item).getIconId());
    }

    if (item instanceof NavDrawerItem) {
        ItemVH viewHolder = (ItemVH) holder;
        viewHolder.mTitle.setText(((NavDrawerItem) item).getTitle());
    }

    if (item instanceof NavDrawerToggle) {
        ToggleVH viewHolder = (ToggleVH) holder;
        viewHolder.mTitle.setText(((NavDrawerToggle) item).getTitle());
        viewHolder.mSwitch.setChecked(((NavDrawerToggle) item).isChecked());
    }
}

@Override
public int getItemViewType(int position) {
    if (data.get(position) instanceof NavDrawerItemWithIcon)
        return 0;

    if (data.get(position) instanceof NavDrawerDivider)
        return 1;

    if (data.get(position) instanceof NavDrawerItem)
        return 2;

    if (data.get(position) instanceof NavDrawerToggle)
        return 3;

    return -1;
}

@Override
public int getItemCount() {
    return data.size();
}

class ItemWithIconVH extends RecyclerView.ViewHolder {
    final TextView mTitle;
    final ImageView mImageView;

    public ItemWithIconVH(View itemView) {
        super(itemView);
        mTitle = (TextView) itemView.findViewById(R.id.nav_item_title);
        mImageView = (ImageView) itemView.findViewById(R.id.nav_item_image);
    }
}

class DividerVH extends RecyclerView.ViewHolder {
    public DividerVH(View itemView) {
        super(itemView);
    }
}

class ItemVH extends RecyclerView.ViewHolder {
    final TextView mTitle;

    public ItemVH(View itemView) {
        super(itemView);
        mTitle = (TextView) itemView.findViewById(R.id.nav_item_title);
    }
}

class ToggleVH extends RecyclerView.ViewHolder {
    final TextView mTitle;
    final Switch mSwitch;

    public ToggleVH(View itemView) {
        super(itemView);
        mTitle = (TextView) itemView.findViewById(R.id.nav_item_title);
        mSwitch = (Switch) itemView.findViewById(R.id.nav_switch);
    }
}}

Superclass for all NavDrawer Items:

public class NavDrawerEntry {}

Item without icon:

public class NavDrawerItem extends NavDrawerEntry {
private String title;

public NavDrawerItem(String title) {
    this.setTitle(title);
}

public String getTitle() {
    return title;
}

private void setTitle(String title) {
    this.title = title;
}}

Item with icon:

public class NavDrawerItemWithIcon extends NavDrawerEntry {
private String title;
private int iconId;

public NavDrawerItemWithIcon(String title, int iconId) {
    this.setTitle(title);
    this.setIconId(iconId);
}

public int getIconId() {
    return iconId;
}

private void setIconId(int iconId) {
    this.iconId = iconId;
}

public String getTitle() {
    return title;
}

private void setTitle(String title) {
    this.title = title;
}}

Divider:

public class NavDrawerDivider extends NavDrawerEntry {}

Item with Switch:

public class NavDrawerToggle extends NavDrawerEntry {
private String title;
private boolean checked;

public NavDrawerToggle(String title) {
    this.setTitle(title);
}

public boolean isChecked() {
    return checked;
}

public void setChecked(boolean checked) {
    this.checked = checked;
}

public String getTitle() {
    return title;
}

private void setTitle(String title) {
    this.title = title;
}}

layout_nav_drawer_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:clickable="true"
android:orientation="horizontal">

<TextView
    android:id="@+id/nav_item_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="16dp"
    android:fontFamily="sans-serif"
    android:textColor="#000"
    android:textSize="16sp" /></LinearLayout>

layout_nav_drawer_item_with_icon.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:clickable="true"
android:orientation="horizontal">

<ImageView
    android:id="@+id/nav_item_image"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="16dp"
    android:src="@drawable/app_generic" />

<TextView
    android:id="@+id/nav_item_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="16dp"
    android:fontFamily="sans-serif"
    android:text="Verbundene Geräte"
    android:textColor="#000"
    android:textSize="16sp" /></LinearLayout>

layout_nav_drawer_divider.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

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

layout_nav_drawer_toggle.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:clickable="true">

<TextView
    android:id="@+id/nav_item_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="16dp"
    android:fontFamily="sans-serif"
    android:text="Verbundene Geräte"
    android:textColor="#000"
    android:textSize="16sp" />

<Switch
    android:id="@+id/nav_switch"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:layout_marginRight="16dp" /></RelativeLayout>

fragment_navigation_drawer.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="280dp"
android:layout_height="match_parent"
android:background="#eee"
tools:context="de.vacom.hew.materialdemo.NavigationDrawerFragment">

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:background="@color/primaryColor"
        android:elevation="3dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/nav_app_icon"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="55dp"
            android:src="@drawable/app_generic" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="64dp"
            android:fontFamily="sans-serif-medium"
            android:text="Demo App"
            android:textColor="#eee"
            android:textSize="18sp" />

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/nav_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout></FrameLayout>