【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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章