Android – Menu


Được đăng vào ngày 23/05/2016 | 0 bình luận
Đánh giá bài viết

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.

NKoyD

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 ActivityonCreateOptionsMenu() 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.

Screenshot_2016-05-23-11-03-44

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.

Screenshot_2016-05-23-14-25-12

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 ButtononClick(). 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.

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 ActivityView 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.

Screenshot_2016-05-23-15-53-05







Trả lời


Lưu ý: bọc code trong cặp thẻ [code language="x"][/code] để highlight code.


Ví dụ:


[code language="cpp"]


    std::cout << "Hello world";


[/code]



Các ngôn ngữ được hỗ trợ gồm: actionscript3, bash, clojure, coldfusion, cpp, csharp, css, delphi, diff, erlang, fsharp, go, groovy, html, java, javafx, javascript, latex, matlab, objc, perl, php, powershell, python, r, ruby, scala, sql, text, vb, xml.

Thư điện tử của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *