Trang chủHướng dẫnCách tạo Navigation Drawer trong Android đơn giản [Hướng dẫn chi tiết]

Cách tạo Navigation Drawer trong Android đơn giản [Hướng dẫn chi tiết]

CyStack blog 5 phút để đọc
CyStack blog11/06/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 5 minutes

Trong bài hướng dẫn này, chúng ta sẽ tìm hiểu cách tạo Navigation Drawer trong Android. Đây là một thành phần UI quan trọng thường gặp trong hầu hết các ứng dụng Android. Nó có chức năng tương tự như các thanh menu điều hướng trên các trang web.

tạo navigation drawer trong android

Đây là một menu trượt từ bên trái dùng để hiển thị các liên kết quan trọng trong ứng dụng. Nó giúp người dùng dễ dàng di chuyển qua lại giữa các liên kết này. Mặc định nó được ẩn đi và chỉ hiện ra khi người dùng chạm trượt từ cạnh trái màn hình hoặc nhấn vào icon của nó trên ActionBar.

Nói một cách tổng quát, Navigation Drawer là một bảng điều khiển dạng lớp phủ (overlay panel). Nó thay thế cho một màn hình activity thường chỉ dùng để hiển thị tất cả các tùy chọn và liên kết của ứng dụng.

Trong bài hướng dẫn này, chúng ta sẽ triển khai Navigation Drawer bằng Drawer Layout API trong Android Support Library. Bài viết sẽ trình bày 3 giao diện fragment(các thành phần UI độc lập) có thể mở được từ các mục của drawer.

Cấu trúc project ví dụ

Cấu trúc project tạo Navigation Drawer trong Android

Ví dụ sử dụng Navigation Drawer trong Android

Để triển khai Navigation Drawer, trước tiên chúng ta cần thêm android.support.v4.widget.DrawerLayout làm phần tử gốc (root) cho layout của activity như ở dưới đây.

File activity_main.xml:

<android.support.v4.widget.DrawerLayout 
    xmlns:android="<https://schemas.android.com/apk/res/android>"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

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

    <LinearLayout
        android:id="@+id/container_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />
    </LinearLayout>

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

    </LinearLayout>

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#FFFFFF"
        android:choiceMode="singleChoice"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="1dp" />

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

Các tùy chọn menu trong navigation drawer được lưu trữ dưới dạng một ListView. Mỗi tùy chọn sẽ mở nội dung trong một FrameLayout.

Ở đây, chúng ta sử dụng ToolBar thay cho ActionBar. ToolBar đã xuất hiện từ Android 5.0 như một dạng tổng quát hơn của ActionBar. Nó giúp ta kiểm soát và tùy chỉnh linh hoạt hơn, đồng thời cũng dễ dàng tích hợp với các view khác trong cấu trúc view.

Layout cho ToolBar được định nghĩa trong file layout toolbar.xml dưới đây.

<android.support.v7.widget.Toolbar xmlns:android="<https://schemas.android.com/apk/res/android>"
    xmlns:local="<https://schemas.android.com/apk/res-auto>"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Khi sử dụng Toolbar, ta cần dùng Theme Theme.AppCompat.NoActionBar trong styles.xml. Layout cho các dòng của ListView trong Navigation Drawer nằm ở file list_view_item_row.xml.

<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:padding="10dp" >

    <ImageView
        android:id="@+id/imageViewIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:paddingRight="10dp" />

    <TextView
        android:id="@+id/textViewName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/imageViewIcon"
        android:paddingRight="10dp"
        android:text="Item Name"
        android:textColor="@android:color/black"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        />

</RelativeLayout>

Các mục của navigation drawer được khai báo trong một mảng string tại file strings.xml.

<string-array name="navigation_drawer_items_array">
        <item>Connect</item>
        <item>Fixtures</item>
        <item>Table</item>
    </string-array>

Class DataModel.java được dùng để định nghĩa đối tượng cho các mục trong danh sách của drawer.

package com.journaldev.navigationdrawer;

public class DataModel {

    public int icon;
    public String name;

    // Constructor.
    public DataModel(int icon, String name) {

        this.icon = icon;
        this.name = name;
    }
}

Các mục của drawer được lưu trữ dưới dạng một ListView. Do đó, chúng ta cần sử dụng một class Adapter để cung cấp dữ liệu này cho class Activity.

File DrawerItemCustomAdapter.java:

package com.journaldev.navigationdrawer;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class DrawerItemCustomAdapter extends ArrayAdapter<DataModel> {

    Context mContext;
    int layoutResourceId;
    DataModel data[] = null;

    public DrawerItemCustomAdapter(Context mContext, int layoutResourceId, DataModel[] data) {

        super(mContext, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.mContext = mContext;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View listItem = convertView;

        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        listItem = inflater.inflate(layoutResourceId, parent, false);

        ImageView imageViewIcon = (ImageView) listItem.findViewById(R.id.imageViewIcon);
        TextView textViewName = (TextView) listItem.findViewById(R.id.textViewName);

        DataModel folder = data[position];

        imageViewIcon.setImageResource(folder.icon);
        textViewName.setText(folder.name);

        return listItem;
    }
}

Nội dung file MainActivity.java giống như ở dưới:

package com.journaldev.navigationdrawer;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

    private String[] mNavigationDrawerItemTitles;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    Toolbar toolbar;
    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    android.support.v7.app.ActionBarDrawerToggle mDrawerToggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTitle = mDrawerTitle = getTitle();
        mNavigationDrawerItemTitles= getResources().getStringArray(R.array.navigation_drawer_items_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        setupToolbar();

        DataModel[] drawerItem = new DataModel[3];

        drawerItem[0] = new DataModel(R.drawable.connect, "Connect");
        drawerItem[1] = new DataModel(R.drawable.fixtures, "Fixtures");
        drawerItem[2] = new DataModel(R.drawable.table, "Table");
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        getSupportActionBar().setHomeButtonEnabled(true);

        DrawerItemCustomAdapter adapter = new DrawerItemCustomAdapter(this, R.layout.list_view_item_row, drawerItem);
        mDrawerList.setAdapter(adapter);
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        setupDrawerToggle();

    }

    private class DrawerItemClickListener implements ListView.OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }

    }

    private void selectItem(int position) {

        Fragment fragment = null;

        switch (position) {
            case 0:
                fragment = new ConnectFragment();
                break;
            case 1:
                fragment = new FixturesFragment();
                break;
            case 2:
                fragment = new TableFragment();
                break;

            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(mNavigationDrawerItemTitles[position]);
            mDrawerLayout.closeDrawer(mDrawerList);

        } else {
            Log.e("MainActivity", "Error in creating fragment");
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getSupportActionBar().setTitle(mTitle);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    void setupToolbar(){
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }

    void setupDrawerToggle(){
        mDrawerToggle = new android.support.v7.app.ActionBarDrawerToggle(this,mDrawerLayout,toolbar,R.string.app_name, R.string.app_name);
        //This is necessary to change the icon of the Drawer Toggle upon state change.
        mDrawerToggle.syncState();
    }
}

Trong đoạn code trên, getSupportActionBar().setDisplayHomeAsUpEnabled(false); được dùng để ẩn nút back (trở về) mặc định. Chúng ta đã sử dụng một class DrawerItemClickListener để tải Fragment tương ứng với mục trong danh sách được chọn, thông qua một FragmentManager.

Đồng thời, tiêu đề của ToolBar cũng được cập nhật theo mục được chọn thông qua setTitle(mNavigationDrawerItemTitles[position]);. Các class Fragment và các layout tương ứng của chúng được trình bày dưới đây.

File ConnectFragment.java:

package com.journaldev.navigationdrawer;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ConnectFragment extends Fragment {

    public ConnectFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_connect, container, false);

        return rootView;
    }

}

Layout của fragment nêu trên được định nghĩa như trong file fragment_connect.xml dưới đây.

<RelativeLayout xmlns:android="<https://schemas.android.com/apk/res/android>"
    xmlns:tools="<https://schemas.android.com/tools>"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/label"
        android:layout_alignParentTop="true"
        android:layout_marginTop="100dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="45dp"
        android:text="Connect"
        android:textStyle="bold"/>

    <TextView
        android:layout_below="@id/label"
        android:layout_centerInParent="true"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="12dp"
        android:layout_marginTop="10dp"
        android:gravity="center_horizontal"
        android:text="Edit fragment_connect.xml to change the appearance"
        android:id="@+id/textView2" />

</RelativeLayout>

Hai mục còn lại được định nghĩa hoàn toàn tương tự như trên, do đó chúng ta sẽ không mô tả chi tiết chúng ở đây.

Kết quả của ví dụ Navigation Drawer

Dưới đây là kết quả chạy thử ứng dụng ví dụ về Navigation Drawer ở trên.

Ứng dụng tạo Navigation Drawer trong Android

Tổng kết

Bài hướng dẫn về ví dụ tạo Navigation Drawer trong Android đến đây là kết thúc. Bạn có thể tải code của project mẫu ở link này. Mong gặp lại bạn ở những bài tutorial về Android khác trong tương lai!

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất