Navigation Drawer為頁面添加了一個選單,通常會設計讓選單從左側出現,其中運作的方法也是會使用到Fragment,當點選從左側出現的選項後,就會將當下的頁面替換成點選的頁面,就跟之前文章中提過的一樣,只不過Navigation Drawer將選項移到了左側,並且只有在需要使用時才會出現,成果大概就像下面這樣
之所以要建立menu是因為從左側出現的選單,裡面的選項就是引入menu來當作Navigation Drawer的選項,建立方法是在res按右鍵
> new
> Android Resource Directory
, 接著在Resource type:
選擇menu
最後在按下OK
就成功建立一個menu囉~
新建好的menu可以在res分類下找到
接著就像建立一個新的布局檔或drawable資源一樣,這裡也要新建一個menu資源,名字就取navigation_menu
就可以了
點開後就可以開始設計你的選單
<?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新增這兩段
<string name="nav_open">Open</string>
<string name="nav_close">Close</string>
這個在後面的程式會使用到
先將開頭的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"
,
到此所有介面就都設定好囉‧★,::‧( ̄▽ ̄)/‧:‧°★*
這個部分就跟之前介紹的一樣,用同一種方式創立Fragment再把用不到的生命週期相關的方法刪掉就可以了,本次實作中這邊不是重點,所以就沒有多做設定,詳細可以參考之前的文章Day11。
從專案名稱
按右鍵 > New
> Fragment
> Fragment(Blank)
首先要implement Navigation Drawer的監聽器
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
接著就是宣告
public DrawerLayout drawerLayout;
private NavigationView navigationView;
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,是就建立一個FragmentAnavigationView.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);
}
這個就是前面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所以關閉時就會往開始的方向關閉。
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)){
drawerLayout.closeDrawer(GravityCompat.START);
}else{
super.onBackPressed();
}
}
這個是一個可以提升使用者使用體驗的方法,意思是當按下手機上的返回鍵時會做的動作
這裡的設計就是去偵測是否有Drawer是正在開啟的狀態,如果有就先將Drawer關閉,反之就是直接關掉這個app。
nav_header
,並且在設定navgation drawer時使用headerLayout
引入,這樣就可以彌補menu只能設計選項,卻不能夠在上面做一些客製化設計的缺點。