【Interface&navigation】创建一个导航抽屉(63)

导航抽屉是一个UI面板,显示应用程序的主导航菜单。它在不使用时隐藏,但在用户从屏幕左边缘滑动手指时显示,或者当在应用程序的顶层时,用户触摸应用栏中的抽屉图标。

此页面显示如何使用支持库中DrawerLayout提供的API 实现导航抽屉 。

导航抽屉设计

在您决定在应用程序中使用导航抽屉之前,您应该了解导航抽屉设计指南中定义的用例和设计原则 。

【Interface&navigation】创建一个导航抽屉(63)
图1.导航抽屉

添加依赖项


此页面使用Android支持库中的API,因此您需要将以下依赖项添加到应用程序模块的build.gradle文件中:

dependencies {
  implementation 'com.android.support:appcompat-v7:27.1.1'
  implementation 'com.android.support:design:27.1.1'
}

在您的布局中添加一个抽屉


要添加导航抽屉,请使用a DrawerLayout作为根视图声明布局 。在其中DrawerLayout,为UI的主要内容添加布局(隐藏抽屉时的主要布局)和包含导航抽屉内容的另一个视图。

例如,以下布局使用 DrawerLayout带有两个子视图的a:a FrameLayout包含主要内容(例如,可以Fragment在运行时填充),以及a NavigationView用于导航抽屉的内容。

<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<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"
    android:fitsSystemWindows="true">

    <!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Container for contents of drawer - use NavigationView to make configuration easier -->
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true" />

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

此示例演示了一些重要的布局特征:

将FrameLayout被设置为匹配父视图的宽度和高度,因为它代表了整个UI当导航抽屉被关闭。
的NavigationView(抽屉)必须指定其与水平重力 android:layout_gravity属性。要支持从右到左(RTL)语言,请指定值"start"而不是 "left"(因此当布局为RTL时,抽屉显示在右侧)。
该NavigationView套 android:fitsSystemWindows以"true"保证抽屉的内容不覆盖状态栏和其他系统的窗口。该DrawerLayout还使用fitsSystemWindows作为一个标志,它需要它的插图儿童(如主要内容视图),但仍得出在这个空间状态栏背景以实物设计规格(默认为你的主题colorPrimaryDark)。

声明导航抽屉的菜单项


要配置抽屉中列出的菜单项,请指定具有该app:menu属性的菜单资源,如下面的示例代码所示:

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

使用相应的文件名创建菜单资源。例如,在res/menu/drawer_view.xml:

<?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/nav_camera"
            android:icon="@drawable/ic_menu_camera"
            android:title="@string/import" />
        <item
            android:id="@+id/nav_gallery"
            android:icon="@drawable/ic_menu_gallery"
            android:title="@string/gallery" />
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="@string/slideshow" />
        <item
            android:id="@+id/nav_manage"
            android:icon="@drawable/ic_menu_manage"
            android:title="@string/tools" />
    </group>
</menu>

您可以通过应用于组来使一组项目单一选择 android:checkableBehavior="single"。这允许您显示当前选择的列表项。

要了解有关创建菜单XML文件的更多信息,请参阅 菜单资源文档。

添加标题到导航抽屉


(可选)您可以通过使用app:headerLayout如下所示的属性指定布局来在抽屉顶部添加标题 :

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

以下是提供标题的示例标题布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="192dp"
    android:background="?attr/colorPrimaryDark"
    android:padding="16dp"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    android:orientation="vertical"
    android:gravity="bottom">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="My header title"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>

</LinearLayout>

有关导航抽屉标题大小,间距和排版的设计建议,请参阅 模式 - 导航抽屉。

处理导航点击事件


要在用户点击抽屉中的列表项时接收回调,请实现OnNavigationItemSelectedListener界面并NavigationView通过调用 将其附加到您的 界面 setNavigationItemSelectedListener()。例如:

public class MainActivity extends AppCompatActivity { 

    private DrawerLayout mDrawerLayout;

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

        mDrawerLayout = findViewById(R.id.drawer_layout);

        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() { 
                    @Override 
                    public boolean onNavigationItemSelected(MenuItem menuItem) {
                        // set item as selected to persist highlight 
                        menuItem.setChecked(true);
                        // close drawer when item is tapped 
                        mDrawerLayout.closeDrawers();

                        // Add code here to update the UI based on the item selected 
                        // For example, swap UI fragments here 

                        return true; 
                    } 
                }); 
    } 
} 

当点击一个项目时,此代码将所选项目设置为选中,更改列表项目的样式以突出显示,因为列表项目是可检查组的一部分(如上面菜单文件中所示)。它还通过调用关闭抽屉 closeDrawers()。

如果您的应用根据用户选择的导航菜单项切换内容,则应考虑在主要内容区域中使用片段。从导航抽屉导航时交换片段允许无缝抽屉动画,因为相同的基本布局保持不变。要了解如何使用片段构建布局,请参阅片段文档。

将导航抽屉按钮添加到应用栏


此时,您已经拥有一个可用的导航抽屉 - DrawerLayout为用户提供了内置支持,可以通过屏幕一侧的滑动来打开和关闭导航抽屉。但是,如果您的UI设计包含应用栏,您还应该允许用户通过触摸应用栏左上方的抽屉图标来打开和关闭抽屉(如图2所示)。这就是你在本节中要做的。
【Interface&navigation】创建一个导航抽屉(63)
图2.左侧带有导航抽屉按钮的应用栏

将工具栏添加到布局中

要使您的UI符合材料设计准则,导航抽屉应显示 在应用栏的前面(如图1所示),而不是在它下面。要实现这一点,您需要将其 Toolbar 用作应用栏,而不是使用带有内置应用栏的主题。您可以Toolbar按如下方式添加 到布局:

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

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

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    </FrameLayout>
...

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

然后打开清单文件并将应用主题设置为不带操作栏的应用主题,例如Theme.AppCompat.Light.NoActionBar:

<manifest ...>
  <application
      ...
      android:theme="@style/Theme.AppCompat.Light.NoActionBar" >
  ...
</manifest>

如果要覆盖此主题中的某些样式,请参阅 样式和主题。

将工具栏设置为操作栏

现在工具栏出现在布局中,但它不能用作应用栏。要将工具栏应用为应用栏,请首先确保您的活动来自 AppCompatActivity。然后从布局中调用setSupportActionBar()并传递Toolbar对象:

public class MainActivity extends AppCompatActivity { 

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ... 
    } 
} 

添加导航抽屉按钮

现在添加打开导航抽屉的按钮。首先需要将菜单按钮的图标添加到项目中。您可以从“ 材质设计图标”页面下载材质菜单图标,或从Android Studio导入图标:

在“ 项目”窗口中,右键单击res文件夹,然后选择“ 新建”>“矢量资产”。
选择“ 材质”图标作为资源类型,然后单击“ 图标”按钮以打开“ 选择图标”窗口。
搜索“菜单”并选择菜单图标(图标为3条水平线)。
单击“ 确定”,然后将文件重命名为“ic_menu”,然后单击“ 下一步”将其导入。
通过调用启用应用栏的“主页”按钮setDisplayHomeAsUpEnabled(true),然后通过调用将其更改为使用菜单图标setHomeAsUpIndicator(int),如下所示:

public class MainActivity extends AppCompatActivity { 

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionbar = getSupportActionBar();
        actionbar.setDisplayHomeAsUpEnabled(true);
        actionbar.setHomeAsUpIndicator(R.drawable.ic_menu);

        ... 
    } 
} 

轻触按钮时打开抽屉

要在用户点击导航抽屉按钮时打开抽屉,请覆盖 onOptionsItemSelected() 以挂钩到选项菜单框架并监听用户何时点击带有ID的项目android.R.id.home。然后打电话openDrawer()打开导航抽屉:

public class MainActivity extends AppCompatActivity { 

    private DrawerLayout mDrawerLayout;

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

        mDrawerLayout = findViewById(R.id.drawer_layout);
        ... 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                mDrawerLayout.openDrawer(GravityCompat.START);
                return true; 
        } 
        return super.onOptionsItemSelected(item);
    } 
} 

要了解有关处理选项菜单点击的更多信息,请参阅菜单指南。

请注意,上面的代码 GravityCompat.START作为打开的抽屉动画重力传递给openDrawer()。这可确保您的导航抽屉打开动画对于从右到左和从左到右的布局都能正常运行。

听取开/关事件和其他状态变化


如果您的应用需要在导航抽屉打开,关闭或只是更改其状态和位置时做出响应 - 如果您需要根据抽屉的确切位置调整UI的其他部分,则可能会有用 - 您应该在DrawerLayout.DrawerListener接口并传递给它addDrawerListener()。例如

public class MainActivity extends AppCompatActivity { 

    private DrawerLayout mDrawerLayout;

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

        mDrawerLayout = findViewById(R.id.drawer_layout);
        ... 

        mDrawerLayout.addDrawerListener(
                new DrawerLayout.DrawerListener() { 
                    @Override 
                    public void onDrawerSlide(View drawerView, float slideOffset) { 
                        // Respond when the drawer's position changes 
                    } 

                    @Override 
                    public void onDrawerOpened(View drawerView) { 
                        // Respond when the drawer is opened 
                    } 

                    @Override 
                    public void onDrawerClosed(View drawerView) { 
                        // Respond when the drawer is closed 
                    } 

                    @Override 
                    public void onDrawerStateChanged(int newState) { 
                        // Respond when the drawer motion state changes 
                    } 
                } 
        ); 
    } 
    ... 
} 

联系我

QQ:94297366
微信打赏:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ

公众号推荐:

【Interface&navigation】创建一个导航抽屉(63)

猜你喜欢

转载自blog.51cto.com/4789781/2178009