Menu có chức năng hiển thị một danh sách các nút lệnh có liên quan với nhau. Trong các hệ điều hành như Windows, Linux, MacOS… thì menu thường xuất hiện trên thanh menu ở đầu cửa sổ.
Trong Android có 3 loại menu: options (menu tùy chọn), context (menu ngữ cảnh) và menu popup. Chúng ta có thể định nghĩa menu trong file XML và dùng lớp MenuInflater
để lấy dữ liệu từ file XML về, hoặc có thể code tay trong Java.
Menu tùy chọn – Options
Menu tùy chọn được hiển thị khi chúng ta bấm nút menu trên thiết bị, thường thì nút này có dạng 3 hoặc 4 dấu gạch ngang.
Ví dụ:
Trong ví dụ dưới đây, chúng ta sẽ tạo menu tùy chọn có 2 item, click vào các item thì dùng Toast
để hiển thị thông báo tương ứng.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Options Menu" /> </LinearLayout>
File layout chính không có gì đặc biệt cả, chỉ có một TextView
với dòng chữ mô tả đơn giản.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">MainActivity</string> <string name="menu1">Settings</string> <string name="menu2">Tools</string> </resources>
Trong file strings.xml
chúng ta định nghĩa 2 biến String
dùng làm tiêu đề cho từng menu item.
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/settings" android:title="@string/menu1" /> <item android:id="@+id/tools" android:title="@string/menu2" /> </menu>
Để tạo danh sách các item của menu thì chúng ta tạo trong một file xml riêng và đặt trong thư mục res/menu.
Nếu chưa có thư mục này thì chúng ta tự tạo bằng tay. Bên trong file này chúng ta sử dụng thẻ menu để khai báo menu
và thẻ item
để khai báo các item
trong menu đó.
package com.phocode; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.Toast; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.options_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.settings: Toast.makeText(MainActivity.this, "Settings", Toast.LENGTH_SHORT).show(); return true; case R.id.tools: Toast.makeText(MainActivity.this, "Tools", Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); } } }
Để có thể sử dụng menu tùy chọn thì chúng ta phải override lại 2 phương thức của lớp Activity
là onCreateOptionsMenu()
và onOptionsItemSelected()
.
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.options_menu, menu); return true; }
Phương thức onCreateOptionsMenu()
sẽ thực hiện các công việc khởi tạo menu cho đối tượng Activity,
ở đây chúng ta dùng phương thức inflate()
của lớp android.view.MenuInflater
để lấy dữ liệu của menu từ file options_menu.xml
về sử dụng. Phương thức này nhận vào một đối tượng android.view.Menu.
@Override public boolean onOptionsItemSelected(MenuItem item) { ... }
Phương thức onOptionsItemSelected()
sẽ xử lý sự kiện click menu. Phương thức này nhận vào một đối tượng android.view.MenuItem.
case R.id.settings: Toast.makeText(MainActivity.this, "Settings", Toast.LENGTH_SHORT).show(); return true;
Ở đây chúng ta chỉ đơn giản là dùng lớp android.widget.Toast
để hiển thị thông báo item nào đã được click.
Menu ngữ cảnh – Context
Menu ngữ cảnh hiển thị nổi lên trên màn hình nhưng được gắn với một đối tượng View
nào đó chứ không liên quan gì tới Activity,
menu ngữ cảnh sẽ hiện ra khi chúng ta click và giữ tay trên View
đó trong một khoảng thời gian.
Ví dụ:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@+id/lvId" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
Ở đây chúng ta sẽ gắn menu ngữ cảnh lên ListView.
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/delId" android:title="Delete"/> <item android:id="@+id/upId" android:title="Lowercase"/> <item android:id="@+id/lowId" android:title="Uppercase"/> </menu>
Cách định nghĩa menu ngữ cảnh cũng không khác gì so với menu tùy chọn.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">MainActivity</string> <string-array name="languages"> <item>Python</item> <item>Java</item> <item>Ruby</item> <item>C++</item> </string-array> </resources>
Trong file strings.xml
chúng ta định nghĩa danh sách các item dùng cho ListView.
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:textSize="20sp"> </TextView>
File row.xml
sẽ định nghĩa cách các item trong ListView
được hiển thị như thế nào.
package com.phocode; import android.app.Activity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; import android.view.View; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.Toast; import java.util.Arrays; import java.util.ArrayList; public class MainActivity extends Activity { private ListView lv; private ArrayAdapter<String> la; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView)findViewById(R.id.lvId); String[] languages = getResources().getStringArray(R.array.languages); ArrayList<String> lst = new ArrayList<String>(); lst.addAll(Arrays.asList(languages)); la = new ArrayAdapter<String>(this, R.layout.row, lst); lv.setAdapter(la); registerForContextMenu(lv); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int pos = info.position; String i = la.getItem(pos); switch (item.getItemId()) { case R.id.delId: la.remove(i); return true; case R.id.upId: String upln = i.toUpperCase(); la.remove(i); la.insert(upln, pos); return true; case R.id.lowId: String lpln = i.toLowerCase(); la.remove(i); la.insert(lpln, pos); return true; default: return super.onContextItemSelected(item); } } }
Để có thể sử dụng menu ngữ cảnh thì chúng ta phải override 2 phương thức là onCreateContextMenu()
và onContextItemSelected().
String[] languages = getResources().getStringArray(R.array.languages); ArrayList<String> lst = new ArrayList<String>(); lst.addAll(Arrays.asList(languages));
Chúng ta lưu các item của ListView
trong một đối tượng ArrayList.
registerForContextMenu(lv);
Muốn dùng menu ngữ cảnh cho View
nào thì chúng ta gọi phương thức registerForContextMenu()
rồi truyền vào đối tượng View
đó.
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); }
Phương thức onCreateContextMenu()
cho menu ngữ cảnh cũng tương tự như phương thức onCreateOptionsMenu()
cho menu tùy chọn vậy, ở đây chúng ta dùng lớp MenuInflater
để lấy dữ liệu của menu từ file context_menu.xml.
@Override public boolean onContextItemSelected(MenuItem item) { ... }
Phương thức onContextItemSelected()
sẽ làm nhiệm vụ xử lý sự kiện click trên từng item.
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int pos = info.position; String i = la.getItem(pos);
Lớp AdapterContextMenuInfo
có thể lấy một vài thông tin từ lớp MenuItem,
trong đoạn code trên chúng ta lấy ra số thứ tự của item trong danh sách và đoạn text của item đó.
case R.id.delId: la.remove(i); return true;
Trong câu lệnh switch...case,
chúng ta kiểm tra xem người dùng đã click vào menu item nào, nếu click vào nút Delete thì chúng ta xóa item của ListView
đi.
case R.id.upId: String upln = i.toUpperCase(); la.remove(i); la.insert(upln, pos); return true;
Nếu click vào nút Uppercase thì chúng ta chuyển đoạn text của item trong ListView
thành viết hoa, nút Lowercase là viết thường.
Menu Popup
Menu Popup được hiển thị ngay tại vị trí của View.
Ví dụ:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/btnId" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginTop="10dip" android:text="@string/btn_label" android:onClick="onClick" /> <TextView android:id="@+id/tvId" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip"/> </LinearLayout>
Trong file main.xml
chúng ta thiết kế một Button
và một TextView. Button
sẽ hiển thị menu Popup
khi được click vào, phương thức xử lý sự kiện click của Button
là onClick(). TextView
chỉ làm nhiệm vụ hiển thị item nào của menu đã được click thôi.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">MainActivity</string> <string name="btn_label">Show menu</string> <string name="item1">Item 1</string> <string name="item2">Item 2</string> </resources>
Trong file strings.xml
chúng ta định nghĩa một vài biến để làm ID cho Button
và làm chuỗi hiển thị menu item.
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/settings" android:title="@string/item1"/> <item android:id="@+id/tools" android:title="@string/item2"/> </menu>
Menu Popup
cũng được thiết kế từ các thẻ menu và item không khác gì với menu ngữ cảnh và menu tùy chọn, ở đây chúng ta thiết kế menu trong file popup_menu.xml,
file này được đặt trong thư mục res/menu.
package com.phocode; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.MenuItem; import android.widget.TextView; import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; public class MainActivity extends Activity implements OnMenuItemClickListener { private TextView tv; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.tvId); } public void onClick(View v) { PopupMenu pm = new PopupMenu(this, v); pm.getMenuInflater().inflate(R.menu.popup_menu, pm.getMenu()); pm.setOnMenuItemClickListener(this); pm.show(); } @Override public boolean onMenuItemClick(MenuItem item) { tv.setText(item.toString() + " selected"); return true; } }
Chúng ta dùng lớp android.widget.PopupMenu
để thao tác với menu.
public void onClick(View v) { PopupMenu pm = new PopupMenu(this, v); pm.getMenuInflater().inflate(R.menu.popup_menu, pm.getMenu()); pm.setOnMenuItemClickListener(this); pm.show(); }
Trong phương thức onClick(),
chúng ta sẽ hiển thị popup menu bằng lớp MenuInflater
giống như menu ngữ cảnh và menu tùy chọn. Ngoài ra ở đây chúng ta phải gắn listener cho đối tượng PopupMenu
này thông qua phương thức setOnMenuItemClickListener(),
khác với menu ngữ cảnh và menu tùy chọn là 2 loại menu này đã có sẵn trong Activity
và View
nên chúng ta không cần gọi trực tiếp ra như đối tượng menu popup. Sau khi tạo PopupMenu,
chúng ta phải gọi phương thức show()
nếu muốn hiện menu này ra.
@Override public boolean onMenuItemClick(MenuItem item) { tv.setText(item.toString() + " selected"); return true; }
Bên trong phương thức onMenuItemClick(),
chúng ta thiết lập giá trị của TextView
là giá trị của menu item đã được click.