iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Mobile Development

Android Studio開發過程和介紹系列 第 26

【DAY 26】 Navigation Drawer介紹

  • 分享至 

  • xImage
  •  

前言

Navigation Drawer為頁面添加了一個選單,通常會設計讓選單從左側出現,其中運作的方法也是會使用到Fragment,當點選從左側出現的選項後,就會將當下的頁面替換成點選的頁面,就跟之前文章中提過的一樣,只不過Navigation Drawer將選項移到了左側,並且只有在需要使用時才會出現,成果大概就像下面這樣

建立menu

之所以要建立menu是因為從左側出現的選單,裡面的選項就是引入menu來當作Navigation Drawer的選項,建立方法是在res按右鍵 > new > Android Resource Directory , 接著在Resource type:選擇menu最後在按下OK就成功建立一個menu囉~
https://ithelp.ithome.com.tw/upload/images/20231006/20161500VeFWeNsUef.png

https://ithelp.ithome.com.tw/upload/images/20231006/20161500L6uaxTSRvq.png
新建好的menu可以在res分類下找到
https://ithelp.ithome.com.tw/upload/images/20231006/20161500Z4SifzpyIi.png
接著就像建立一個新的布局檔或drawable資源一樣,這裡也要新建一個menu資源,名字就取navigation_menu就可以了
https://ithelp.ithome.com.tw/upload/images/20231006/20161500nFMHIcJ7Em.png

點開後就可以開始設計你的選單

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

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/fragment_a"
            android:title="My Account" />
        <item
            android:id="@+id/fragment_b"
            android:title="Settings" />
    </group>
</menu>

設計方法如上,使用item為你的選單添加新的選項,id的部分在MainActivity時會用在建立Fragment,title則是你的選項的文字,
tools:showIn ="navigation_view"這一段可加可不加,加了就是比較好判斷item的樣子,不加也不會影響程式的運作,
接著group android:checkableBehavior="single"這段的意思是設定一次只能選擇一個選項。

  • 補充: 可以添加android:icon=""這個指令,這個可以將代表那個文字的圖案加到前面,幫助更快看懂各個選項的意思。

到此選單的項目就設計完成,接著要到main_activity將這個menu引入到Navigation Drawer。

strings

在strings新增這兩段

    <string name="nav_open">Open</string>
    <string name="nav_close">Close</string>

這個在後面的程式會使用到

main_activity

先將開頭的constraintlayout替換成drawerlayout

接著填入這段程式

    android:id="@+id/my_drawer_layout"
    android:fitsSystemWindows="true"
    tools:openDrawer="start"

fitsSystemWindows="true",這個是一個用於設置視圖(View)的 XML 屬性,它用於指示視圖是否應該留出系統窗口(例如狀態欄和導航欄)的空間。
tools:openDrawer="start",這個將彈出的選項設定在開始(左側),這樣做就可以讓選單變成從左側出現,至於為什麼不是使用left,是因為在語系為從右到左的情況下,輸入left會變成從右側出現,為了避免這種問題索性就填入start就好

接著輸入

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

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:id="@+id/toolbar"
            android:elevation="4dp"
            android:background="#34F4DD"
            android:theme="@style/ThemeOverlay.AppCompat.Light"/>

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

這段就相當於在建立整個頁面的樣式,首先用了LinearLayout將Toolbar跟FramLayout給包起來,Toolbar固定會在畫面的上方,而FramLayout就會填滿剩下的空間,就跟之前講到的Fragment一樣,由FramLayout覆蓋到的地方就會被替換掉

最後要將本次的主角,Navigation Drawer給導入到這個頁面

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/navigation_menu" />

首先一樣將位置給設定到start的地方
接著就是將做好的menu給引入app:menu="@menu/navigation_menu"
到此所有介面就都設定好囉‧★,::‧( ̄▽ ̄)/‧:‧°★*

FragmentA 、 FragmentB

這個部分就跟之前介紹的一樣,用同一種方式創立Fragment再把用不到的生命週期相關的方法刪掉就可以了,本次實作中這邊不是重點,所以就沒有多做設定,詳細可以參考之前的文章Day11
專案名稱按右鍵 > New > Fragment > Fragment(Blank)
https://ithelp.ithome.com.tw/upload/images/20231006/20161500YN9F9n3LKE.png

MainActivity

首先要implement Navigation Drawer的監聽器

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{

接著就是宣告

    public DrawerLayout drawerLayout;
    private NavigationView navigationView;
  • onCreate

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

setSupportActionBar(toolbar);這行程式碼設定了應用程序的支援操作欄,將 Toolbar 設定為應用程序的操作欄。

        navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

第二行程式設定的Navigation Drawer的監聽器,當選單中有選項被選取,就會去調用onNavigationItemSelected這個方法來決定要執行什麼動作。

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,R.string.nav_open
                ,R.string.nav_close);
        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();

ActionBarDrawerToggle toggle,建立了一個專屬於Navigation Drawer使用的工具,要像裡面傳入 當前的Activity、DrawerLayout、ToolBar、開始跟結束的字串
drawerLayout.addDrawerListener(toggle);,這段將drawer加進到監聽器裡面一起監聽
toggle.syncState();此行程式碼同步 ActionBarDrawerToggle 的狀態,以確保抽屜圖標(通常是漢堡圖標)的顯示狀態與抽屜的打開或關閉狀態一致。

        if (savedInstanceState == null){
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentA()).commit();
            navigationView.setCheckedItem(R.id.fragment_a);
        }

這段是在判斷是否為首次創建 Activity,是就建立一個FragmentA
navigationView.setCheckedItem(R.id.fragment_a);,這裡指定選單一開始選的是fragment_a也就是My Account。
全部和在一起就如下

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

        navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,R.string.nav_open
                ,R.string.nav_close);
        drawerLayout.addDrawerListener(toggle);
        toggle.syncState();

        if (savedInstanceState == null){
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentA()).commit();
            navigationView.setCheckedItem(R.id.fragment_a);
        }
  • onNavigationItemSelected

這個就是前面setNavigationItemSelectedListener提到的Navigation Drawer的監聽器

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.fragment_a){
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentA()).commit();
        } else if (id == R.id.fragment_b) {
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new FragmentB()).commit();
        }
        drawerLayout.closeDrawer(GravityCompat.START);
        return true;
    }

基本上就是點選了哪一個選項,就將該選項的Fragment替換到頁面上
drawerLayout.closeDrawer(GravityCompat.START);,這裡設定關閉Drawer時會往哪個方向關,這裡設定start所以關閉時就會往開始的方向關閉。

  • onBackPressed

    @Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START)){
            drawerLayout.closeDrawer(GravityCompat.START);
        }else{
            super.onBackPressed();
        }
    }

這個是一個可以提升使用者使用體驗的方法,意思是當按下手機上的返回鍵時會做的動作
這裡的設計就是去偵測是否有Drawer是正在開啟的狀態,如果有就先將Drawer關閉,反之就是直接關掉這個app。

本次的Navigation Drawer就介紹到這邊,這次實作的介面做的比較簡陋,如果想要往介面變得更好看前進就要在Layout建立一個nav_header,並且在設定navgation drawer時使用headerLayout引入,這樣就可以彌補menu只能設計選項,卻不能夠在上面做一些客製化設計的缺點。

下一篇開始我打算做一個大型的實作,用上這個月所學到的各種物件、程式,寫出一個擁有多種功能的App,預計會花三篇來製作。


上一篇
【DAY 25】 CardView介紹
下一篇
【DAY 27】 將這個月所學集合成一個APP!(佈局篇)
系列文
Android Studio開發過程和介紹30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言