Navigation Drawer คืออะไร?
Navigation Drawer (หรือ Slide Menu) เป็น UI Pattern ที่ซ่อนเมนูไว้ด้านข้าง (มักเป็นซ้าย) ลากออกมาได้ โดยใช้ DrawerLayout เป็น Root View และ NavigationView สำหรับแสดงเมนู ปัจจุบันเป็นมาตรฐานของ Material Design
โครงสร้างไฟล์ Layout (สร้างโดย Android Studio Template)
1. activity_main.xml (Root Layout)
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<!-- Main Content -->
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Navigation Drawer (NavigationView) -->
<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"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
2. app_bar_main.xml (Toolbar + Content)
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.appbar.AppBarLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.Material3.Dark.ActionBar">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.Material3.Light" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
3. content_main.xml (เนื้อหาหลัก)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
4. nav_header_main.xml (Header ของ Drawer)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:padding="16dp"
android:theme="@style/ThemeOverlay.Material3.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:contentDescription="@string/nav_header_desc"
app:srcCompat="@drawable/ic_account_circle" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:text="Tutorials Point"
android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
android:textColor="#FFF"
android:textStyle="bold" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Father of all educational website"
android:textColor="#FFF" />
</LinearLayout>
5. menu/activity_main_drawer.xml (Menu Items)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_home"
android:icon="@drawable/ic_home"
android:title="หน้าแรก" />
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_gallery"
android:title="แกลเลอรี" />
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_slideshow"
android:title="สไลด์โชว์" />
<item
android:id="@+id/nav_tools"
android:icon="@drawable/ic_tools"
android:title="เครื่องมือ" />
</group>
<item android:title="ติดต่อเรา">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_share"
android:title="แชร์" />
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_send"
android:title="ส่ง" />
</menu>
</item>
</menu>
MainActivity.java - การเชื่อมต่อและจัดการ Event
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import com.google.android.material.navigation.NavigationView;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle toggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// DrawerLayout & Toggle
drawerLayout = findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawerLayout, toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
// NavigationView
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_home) {
// Handle Home
} else if (id == R.id.nav_gallery) {
// Handle Gallery
} else if (id == R.id.nav_slideshow) {
// Handle Slideshow
} else if (id == R.id.nav_tools) {
// Handle Tools
} else if (id == R.id.nav_share) {
// Handle Share
} else if (id == R.id.nav_send) {
// Handle Send
}
// ปิด Drawer หลังเลือก
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
toggle.syncState(); // Sync state หลัง rotate
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
toggle.onConfigurationChanged(newConfig);
}
}
การปรับแต่งเพิ่มเติม
เปลี่ยนตำแหน่ง Drawer เป็นขวา
<!-- ใน NavigationView --> android:layout_gravity="end" // แทน start <!-- ใน Java --> drawerLayout.closeDrawer(GravityCompat.END);
เพิ่ม Badge/Notification Count ใน Menu Item
// ใน Java Menu menu = navigationView.getMenu(); MenuItem item = menu.findItem(R.id.nav_messages); // ใช้ BadgeDrawable (Material Components 1.2+) BadgeDrawable badge = BadgeDrawable.create(this); badge.setNumber(5); badge.setVisible(true); item.setIcon(BadgeUtils.createBadgeDrawable(this, item.getIcon(), badge));
ใช้ Navigation Component (Modern Way)
แทนที่การจัดการ Fragment/Intent เอง ให้ใช้ NavController และ NavigationUI:
// build.gradle implementation "androidx.navigation:navigation-fragment-ktx:2.7.0" implementation "androidx.navigation:navigation-ui-ktx:2.7.0" // ใน Activity NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); NavigationUI.setupWithNavController(navigationView, navController); NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
สรุป
- ใช้
DrawerLayout+NavigationView+Toolbar - Implements
NavigationView.OnNavigationItemSelectedListener - จัดการ Back Press เพื่อปิด Drawer ก่อน
- โปรเจกต์ใหม่ควรใช้ Navigation Component แทนการจัดการ Fragment เอง
- รองรับ RTL อัตโนมัติ (START/END แทน LEFT/RIGHT)