如何在 Material Design 导航抽屉中添加复选框?

17

我使用菜单项图标菜单,但我想在所有菜单项上添加复选框。这是我的drawer_menu.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="all">
    <item
        android:checked="false"
        android:id="@+id/item_navigation_drawer_inbox"
        android:icon="@drawable/ic_inbox_black_24dp"
        android:checkable="true"
        android:title="Inbox" />
    <item
        android:id="@+id/item_navigation_drawer_starred"
        android:icon="@drawable/ic_action_toggle_star"
        android:checkable="true"
        android:title="Starred" />
    <item
        android:id="@+id/item_navigation_drawer_sent_mail"
        android:icon="@drawable/ic_action_content_send"
        android:checkable="true"
        android:title="Sent mail" />
    <item
        android:id="@+id/item_navigation_drawer_drafts"
        android:icon="@drawable/ic_action_content_drafts"
        android:checkable="true"
        android:title="Drafts"
        />
</group>

<item android:title="Subheader">
    <menu>
        <item
            android:id="@+id/item_navigation_drawer_settings"
            android:icon="@drawable/ic_action_content_mail"
            android:title="Settings" />
        <item
            android:id="@+id/item_navigation_drawer_help_and_feedback"
            android:icon="@drawable/ic_action_action_delete"
            android:title="Help and feedback" />
    </menu>
</item>

</menu>

有图标和文本。我希望还能加上复选框。

[icon] [some text]  [checkbox]

像这个样子。

我在我的代码中使用了 Material Design 的导航抽屉。

这是我的 nav_header.xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="192dp"
android:gravity="bottom"
android:theme="@style/ThemeOverlay.AppCompat.Dark">

<ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scaleType="centerCrop"
    android:background="@drawable/bg_ist_nav_img" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="52dp"
    android:layout_gravity="left|bottom"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center_vertical"
        android:text="text"
        android:textSize="30sp"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2" />

</LinearLayout>

</FrameLayout>

最后这是我的activity_main.xml

 <android.support.v4.widget.DrawerLayout 
xmlns:andro id="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">


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

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/status_bar_kitkat_height"
        android:background="?colorPrimary"/>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/status_bar_lollipop_height"
        android:background="?colorPrimaryDark"/>

</LinearLayout>

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/status_bar_margin_top">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Inbox"
        android:textAppearance="@style/TextAppearance.AppCompat.Display1"
        android:textColor="@color/md_text" />



    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:background="?attr/colorPrimary"
        android:elevation="4dp"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:theme="@style/ToolbarTheme" />

</FrameLayout>

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="@bool/fitsSystemWindows"
    app:headerLayout="@layout/navigation_drawer_header"
    app:menu="@menu/navigation_drawer_menu"
    app:theme="@style/NavigationViewTheme" />

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

导航抽屉应该作为导航使用,而不是多选元素。您使用复选框的意图是什么? - Thomas R.
我想创建一个多选菜单项。使用android:checkableBehavior="all"可以实现,但用户无法理解多选项,因为当复选框被点击时,这对用户体验非常有用。但在此之前,我需要将复选框添加到导航抽屉菜单中。 - slymnozdmrc
不幸的是,NavigationView 中菜单的格式仅限于图标、名称以及在选择菜单项时突出显示。要显示复选框、消息指示器、下拉列表或任何其他视觉元素,您必须使用 NavigationView 之外的其他东西。 - kris larson
@krislarson 感谢您的回答,我想我应该改变我的方式,不应该使用NavigationView,而是使用其他东西。 - slymnozdmrc
在GitHub上有几个可插拔的导航抽屉,您可以查看它们是否支持复选框。 - kris larson
显示剩余2条评论
4个回答

54

使用app:actionLayout,您可以创造奇迹。

以下是一个示例,实现在抽屉中自定义小部件,而不需要任何Java代码:

<android.support.v4.widget.DrawerLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:openDrawer="end"
    >
    <android.support.design.widget.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="end"
        android:background="@android:color/white"
        app:menu="@menu/widgets"
        />
</android.support.v4.widget.DrawerLayout>

enter image description here

menu/widgets.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="Widgets"
        >
        <menu>
            <item
                android:title="Checkable menu item (checked)"
                android:checkable="true"
                android:checked="true"
                />
            <item
                android:title="CheckBox"
                app:actionLayout="@layout/widget_check" />
            <item
                android:title="Switch"
                app:actionLayout="@layout/widget_switch" />
            <item
                android:title="EditText"
                app:actionLayout="@layout/widget_edit" />
            <item
                android:title=""
                app:actionLayout="@layout/widget_wide" />
            <item
                android:title="NumberPicker"
                app:actionLayout="@layout/widget_number" />
            <item
                android:title="Custom LinearLayout number"
                app:actionLayout="@layout/widget_custom" />
        </menu>
    </item>
</menu>

所有布局(每个文件都是一个单独的文件)

<!-- layout/widget_check.xml -->
<CheckBox
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:text="check"
    android:checked="true"
    />

<!-- layout/widget_edit.xml -->
<EditText
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="hello"
    android:inputType="text"
    />

<!-- layout-v14/widget_switch.xml
     for older versions you can add a CheckBox into layout/widget_switch.xml
     and treat both as Checkable or CompoundButton -->
<Switch
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:checked="true"
    tools:targetApi="ICE_CREAM_SANDWICH"
    />

<!-- layout/widget_wide.xml
     Just some text, notice that it's wide on the UI because it has a lot of text,
     and not because it has match_parent -->
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="#888"
    android:text="Wide can be only forced by content, match_parent doesn't work"
    />

<!-- layout-v11/widget_number.xml
     you're probably better off creating a custom widget anyway -->
<NumberPicker
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    tools:targetApi="HONEYCOMB"
    />

<!-- layout/widget_custom.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="horizontal"
    >
    <Button
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:padding="0dp"
        android:text="&lt;"
        android:gravity="center"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="12"
        />
    <Button
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:padding="0dp"
        android:text="&gt;"
        android:gravity="center"
        />
</LinearLayout>

代码连接

您可以像访问其他菜单一样访问它:

// <item android:id="@+id/switch" title="Switch" ... />
NavigationView nav = (NavigationView)findViewById(R.id.navigation_view);
MenuItem switchItem = nav.getMenu().findItem(R.id.switch);
CompoundButton switchView = (CompoundButton)MenuItemCompat.getActionView(switchItem);
switchView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { }
});

支持库在许多地方/用途上都非常棒,但遗憾的是文档严重不足。 - TWiStErRob
1
很棒的答案,应该加入到Android菜单创建的文档中。谢谢! - Bahadin Khalilieh
这是一个很好的答案。现在在2020年,如果您使用androidx进行向后兼容,您可以使用“SwitchCompat”来简单地使用一个布局。 - CaptainCrunch
很棒的答案!这段代码在2020年可以通过一些调整与Kotlin一起使用。 :) - Stanojkovic

32

使用actionViewClass是TWiStErRob代码的替代解决方案

   <item
        android:id="@+id/nav_switch"
        android:title="Switch"
        app:actionViewClass="android.widget.Switch"
    />

所以您不需要创建布局文件。当然,在Switch的情况下,API 14+应该使用菜单。


这应该是被接受的答案,因为它是最简单的。 很奇怪,为什么只有一个赞。 - mhdjazmati
1
也可以使用android.widget.CheckBox。 - Eran Boudjnah
不错!虽然我觉得大多数时候需要添加至少一个属性来自定义小部件的行为/视觉效果,在这种情况下创建XML可能比子类化"View"更好。 - TWiStErRob
谢谢。我会在我的应用程序中使用这个答案。被采纳的答案也很好。它提供了所有的细节。但需要记住的是,必须使用getActionView()来设置控件的状态。它本质上是一个菜单项内部的控件。 - Hong
如何使其默认选中? - Nikhil Wagh

6
作为对 @Alex 回答的回应,您可以像这样使用它:
<item
    android:id="@+id/checkboxX-axis"
    android:title="Show x-axis"
    android:icon="@drawable/ic_x_axis_black_24dp"
    app:actionViewClass="android.widget.CheckBox"
    />

要在程序中访问checkBox,你可以这样做:

MenuItem menuItem = navigationView.getMenu().findItem(R.id.checkboxX_axis);
CompoundButton compundButton = (CompoundButton) menuItem.getActionView();
compundButton.setChecked(true) // or set an eventListener to it.

3

经过长时间的研究,我决定使用自定义滑动抽屉。我解决了我的问题,也许你可以用我的方法。所以现在我有复选框。

首先,我定义了 drawer_list_item.xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/list_item_title">

<ImageView
    android:id="@+id/icon"
    android:layout_width="25dp"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_marginLeft="12dp"
    android:layout_marginRight="12dp"
    android:contentDescription="@string/desc_list_item_icon"
    android:src="@drawable/ic_home"
    android:layout_centerVertical="true" />

<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_toRightOf="@id/icon"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:textColor="@color/counter_text_bg"
    android:gravity="center_vertical"
    android:text="text"
    android:paddingRight="40dp"/>

<CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/checkBox"
    android:checked="false"
    android:layout_marginLeft="20dp"
    android:buttonTint="@color/md_indigo_500"
    android:layout_marginEnd="19dp"
    android:layout_alignBaseline="@+id/title"
    android:layout_alignBottom="@+id/title"
    android:layout_alignParentEnd="true" />

</RelativeLayout>

现在我们有图标、文本和可爱的复选框。

接着我在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"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Framelayout to display Fragments -->
<FrameLayout
    android:id="@+id/frame_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<!-- Listview to display slider menu -->
<ListView
    android:id="@+id/list_slidermenu"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:listSelector="@drawable/list_selector"
    android:background="@color/list_item_title"/>

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

我把ListView放在这里。 最后,在MainActivity.java中,我以编程方式定义了代码。
    mTitle = mDrawerTitle = getTitle();     
    navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
    navMenuIcons = getResources().     
    obtainTypedArray(R.array.nav_drawer_icons);

    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.list_slidermenu);

    navDrawerItems = new ArrayList<NavDrawerItem>();
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[0],   
    navMenuIcons.getResourceId(0, -1)));

    navDrawerItems.add(new NavDrawerItem(navMenuTitles[1],  
    navMenuIcons.getResourceId(1, -1)));

    navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], 
    navMenuIcons.getResourceId(2, -1)));

    navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], 
    navMenuIcons.getResourceId(3, -1)));

    navDrawerItems.add(new NavDrawerItem(navMenuTitles[4], 
    navMenuIcons.getResourceId(4, -1)));

    navDrawerItems.add(new NavDrawerItem(navMenuTitles[5],   
    navMenuIcons.getResourceId(5, -1)));

    navMenuIcons.recycle();


    adapter = new NavDrawerListAdapter(getApplicationContext(),
            navDrawerItems);
    mDrawerList.setAdapter(adapter);


    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,         
      R.string.app_name, 
    ){
        public void onDrawerClosed(View view) {
            getActionBar().setTitle(mTitle);
            invalidateOptionsMenu();
        }

        public void onDrawerOpened(View drawerView) {
            getActionBar().setTitle(mDrawerTitle);
            invalidateOptionsMenu();
        }
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
    menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
    return super.onPrepareOptionsMenu(menu);
}

@Override
public void setTitle(CharSequence title) {
    mTitle = title;
    getActionBar().setTitle(mTitle);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);.
    mDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    mDrawerToggle.onConfigurationChanged(newConfig);
}

另外,您需要使用

我在string.xml中获取图标和文本,您需要为文本定义字符串数组并为图标定义数组。我按照这个教程编写代码,这很有用,您可以在http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/中找到更多详细信息。

希望这个解决方案对您有所帮助。


NavDrawerItem 类是什么? - arne.z
是的,NavDrawerItem里面有什么? 另外,我们能看一下NavDrawerListAdapter里面有什么吗? - mochadwi
请查看这里的参考文献:https://dev59.com/aoXca4cB1Zd3GeqPIG1Y#27209139 - mochadwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接