Trình đơn

Trình đơn là thành phần giao diện người dùng phổ biến ở nhiều loại ứng dụng. Để cung cấp trải nghiệm quen thuộc và nhất quán cho người dùng, bạn nên sử dụng API Menu để trình bày thao tác người dùng và các tùy chọn khác trong hoạt động.

Từ bản Android 3.0 (API cấp độ 11) trở đi, thiết bị chạy Android không cần cung cấp nút Menu (Trình đơn) chuyên dụng nữa. Với thay đổi này, các ứng dụng Android sẽ không còn phụ thuộc vào bảng điều khiển gồm 6 mục truyền thống mà cung cấp thanh ứng dụng để hiển thị các thao tác phổ biến của người dùng.

Mặc dù thiết kế và trải nghiệm người dùng đối với một số mục trong trình đơn đã thay đổi, nhưng ngữ nghĩa diễn giải để xác định một nhóm thao tác và tùy chọn vẫn dựa trên API Menu. Hướng dẫn này chỉ ra cách tạo ba loại trình đơn hoặc bản trình bày thao tác cơ bản trên mọi phiên bản Android:

Trình đơn tùy chọn và thanh ứng dụng
Trình đơn tùy chọn là tập hợp chính các mục trong trình đơn cho một hoạt động. Đây là nơi bạn nên đặt các tác vụ có tác động chung đến ứng dụng, chẳng hạn như tính năng "Tìm kiếm", "Soạn email" và "Cài đặt".

Xem phần Tạo trình đơn tùy chọn.

Trình đơn theo bối cảnh và chế độ thao tác theo bối cảnh
Trình đơn theo bối cảnh là trình đơn nổi xuất hiện khi người dùng nhấp và giữ một phần tử. API này cung cấp các thao tác ảnh hưởng đến nội dung hoặc khung ngữ cảnh đã chọn.

Chế độ thao tác theo ngữ cảnh hiển thị các mục hành động ảnh hưởng đến nội dung đã chọn trong thanh ở đầu màn hình và cho phép người dùng chọn nhiều mục.

Xem mục Tạo trình đơn theo bối cảnh.

Trình đơn bật lên
Trình đơn bật lên hiển thị danh sách các mục nằm trong danh sách theo chiều dọc được liên kết với chế độ xem đã gọi trình đơn. Bạn nên cung cấp nhiều hành động liên quan đến nội dung cụ thể hoặc cung cấp tùy chọn cho phần hai của lệnh. Các thao tác trong trình đơn bật lên không được ảnh hưởng trực tiếp đến nội dung tương ứng, đó cũng là mục đích của tính năng thao tác theo ngữ cảnh. Thay vào đó, trình đơn bật lên dành cho các thao tác mở rộng có liên quan đến các khu vực nội dung trong hoạt động.

Xem mục Tạo trình đơn bật lên.

Xác định trình đơn trong XML

Đối với mọi loại trình đơn, Android cung cấp một định dạng XML chuẩn để xác định các mục trong trình đơn. Thay vì tạo một trình đơn trong mã hoạt động, bạn nên xác định một trình đơn và tất cả các mục thuộc trình đơn đó trong tài nguyên trình đơn XML. Sau đó, bạn có thể tăng cường tài nguyên trình đơn (tải tài nguyên này dưới dạng một đối tượng Menu) trong phân mảnh hoặc hoạt động của bạn.

Việc sử dụng tài nguyên trình đơn là một phương pháp hay vì những lý do sau:

  • Dễ dàng hình ảnh hóa cấu trúc trình đơn ở định dạng XML hơn.
  • Thao tác này tách nội dung trình đơn từ mã hành vi của ứng dụng.
  • Công cụ này cho phép bạn tạo cấu hình của trình đơn thay thế cho các phiên bản nền tảng, kích thước màn hình và các cấu hình khác bằng cách tận dụng khung tài nguyên ứng dụng.

Để xác định trình đơn, hãy tạo một tệp XML bên trong thư mục res/menu/của dự án và tạo trình đơn bằng các phần tử sau:

<menu>
Xác định Menu, là một vùng chứa các mục trong trình đơn. Phần tử <menu> phải là nút gốc của tệp đồng thời có thể chứa một hoặc nhiều phần tử <item><group>.
<item>
Tạo MenuItem, đại diện cho mục duy nhất trong một trình đơn. Phần tử này có thể chứa phần tử <menu> lồng nhau để tạo một trình đơn phụ.
<group>
Một vùng chứa không bắt buộc, không hiển thị cho các phần tử <item>. Công cụ này cho phép bạn phân loại các mục trong trình đơn để chúng có chung những thuộc tính như trạng thái hoạt động và khả năng hiển thị. Để biết thêm thông tin, hãy xem mục Tạo nhóm trình đơn.

Trình đơn mẫu có tên là game_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          android:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

Phần tử <item> hỗ trợ một số thuộc tính bạn có thể dùng để xác định giao diện và hành vi của một mục. Các mục trong trình đơn ở trên bao gồm thuộc tính sau:

android:id
Mã tài nguyên dành riêng cho mục. Mã này cho phép ứng dụng nhận ra khi người dùng chọn mục đó.
android:icon
Tham chiếu đến đối tượng có thể vẽ để sử dụng làm biểu tượng của mục.
android:title
Tham chiếu đến một chuỗi dùng làm tiêu đề mục.
android:showAsAction
Chỉ định thời điểm và cách thức mục này xuất hiện dưới dạng một hành động trên thanh ứng dụng.

Đây là những thuộc tính quan trọng nhất mà bạn nên sử dụng. Tuy nhiên, còn có nhiều thuộc tính khác. Để biết thông tin về tất cả các thuộc tính được hỗ trợ, hãy xem tài liệu Trình đơn tài nguyên.

Có thể thêm trình đơn phụ vào một mục trong bất kỳ trình đơn nào bằng cách thêm phần tử <menu>làm phần tử con của <item>. Trình đơn phụ hữu ích khi ứng dụng có nhiều chức năng được sắp xếp thành chủ đề, như các mục trên thanh trình đơn của ứng dụng trên PC (Tệp, Chỉnh sửa, Xem, v.v.). Ví dụ:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

Để sử dụng trình đơn trong hoạt động, bạn cần tăng cường tài nguyên trình đơn (chuyển đổi tài nguyên XML thành một đối tượng có thể lập trình) bằng cách sử dụng MenuInflater.inflate(). Trong các phần sau, bạn sẽ thấy cách phóng to cho từng loại trình đơn.

Tạo trình đơn tùy chọn

Hình 1. Trình đơn Tùy chọn trong Trình duyệt.

Trình đơn tùy chọn là nơi nên chứa các thao tác và tùy chọn khác có liên quan đến ngữ cảnh hoạt động hiện tại, chẳng hạn như "Tìm kiếm", "Soạn email" và "Cài đặt".

Vị trí các mục trong trình đơn tùy chọn xuất hiện trên màn hình phụ thuộc vào phiên bản đã phát triển ứng dụng:

  • Nếu bạn đã triển khai ứng dụng cho phiên bản Android 2.3.x (API cấp độ 10) trở xuống, nội dung của trình đơn tùy chọn sẽ xuất hiện ở đầu màn hình khi người dùng nhấn nút Trình đơn, như trong hình 1. Khi mở ứng dụng, trình đơn biểu tượng sẽ hiển thị đầu tiên, chứa tối đa 6 mục trong trình đơn. Nếu trình đơn chứa hơn 6 mục, Android sẽ đặt mục thứ 6 và mục còn lại vào trình đơn mục bổ sung mà người dùng có thể mở bằng cách chọn Thêm.
  • Nếu bạn đã triển khai ứng dụng cho phiên bảnAndroid 3.0 (API cấp độ 11) trở lên, các mục trong trình đơn tùy chọn sẽ có sẵn trên thanh ứng dụng. Theo mặc định, hệ thống đặt tất cả các mục trong mục bổ sung hành động mà người dùng có thể xem bằng biểu tượng mục bổ sung thao tác ở bên phải của thanh ứng dụng (hoặc bằng cách nhấn nút thiết bịTrình đơn nếu có). Để cho phép truy cập nhanh vào các thao tác quan trọng, bạn có thể quảng bá một số mục xuất hiện trên thanh ứng dụng bằng cách thêm android:showAsAction="ifRoom" vào các phần tử <item> tương ứng (xem hình 2 ).

    Để biết thêm thông tin về mục thao tác và các hành vi khác trên thanh ứng dụng, hãy xem lớp đào tạo về Thêm thanh ứng dụng.

Hình 2. Ứng dụng Google Trang tính hiển thị một số nút, bao gồm cả nút mục bổ sung thao tác.

Bạn có thể khai báo các mục cho trình đơn tùy chọn từ lớp con Activityhoặc lớp con Fragment. Nếu cả hoạt động và phân mảnh đều khai báo các mục cho trình đơn tùy chọn, thì chúng sẽ được kết hợp trong giao diện người dùng. Các mục của hoạt động sẽ xuất hiện trước, sau đó là các mục của từng phân mảnh theo thứ tự và mỗi phân mảnh được thêm vào hoạt động. Có thể sắp xếp lại các mục trong trình đơn nếu cần thiết bằng thuộc tính android:orderInCategorytrong mỗi <item> cần di chuyển.

Để chỉ định trình đơn tùy chọn cho một hoạt động, hãy ghi đè onCreateOptionsMenu() (phân mảnh cung cấp lệnh gọi lại onCreateOptionsMenu() riêng). Trong phương thức này, bạn có thể tăng cường tài nguyên trình đơn của mình (được xác định trong XML) vào Menu được cung cấp trong lệnh gọi lại. Ví dụ:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    val inflater: MenuInflater = menuInflater
    inflater.inflate(R.menu.game_menu, menu)
    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

Ngoài ra còn có thể thêm mục trong trình đơn bằng cách sử dụng add() và truy xuất các mục bằng findItem() để sửa đổi thuộc tính mục đó bằng API MenuItem.

Nếu bạn đã triển khai ứng dụng cho phiên bản Android 2.3.x trở xuống, hệ thống sẽ gọi onCreateOptionsMenu() để tạo trình đơn tùy chọn khi người dùng mở trình đơn lần đầu tiên. Nếu bạn đã phát triển ứng dụng cho phiên bản Android 3.0 trở lên, hệ thống sẽ gọi onCreateOptionsMenu() khi bắt đầu hoạt động để hiển thị các mục trên thanh ứng dụng.

Xử lý sự kiện nhấp chuột

Khi người dùng chọn một mục ở trình đơn tùy chọn (bao gồm các mục hành động trong thanh ứng dụng), hệ thống sẽ gọi phương thức hoạt động onOptionsItemSelected(). Phương thức này truyền tham số MenuItem đã chọn. Có thể xác định mục bằng cách gọi getItemId(), lệnh này trả về mã nhận dạng duy nhất cho mục trong trình đơn (được xác định bằng thuộc tính android:id trong tài nguyên trình đơn hoặc bằng một số nguyên được cấp cho phương thức add()). Có thể so sánh đối chiếu mã này với các mục trong trình đơn đã biết để thực hiện thao tác thích hợp. Ví dụ:

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    // Handle item selection
    return when (item.itemId) {
        R.id.new_game -> {
            newGame()
            true
        }
        R.id.help -> {
            showHelp()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Khi xử lý thành công một mục trong trình đơn, hãy trả lại true. Nếu không xử lý mục trình đơn, bạn nên gọi triển khai lớp trên của onOptionsItemSelected() (cách triển khai mặc định trả về sai).

Nếu hoạt động có chứa phân mảnh, trước tiên, hệ thống sẽ gọi onOptionsItemSelected() cho hoạt động đó, sau đó gọi cho mỗi phân mảnh (theo thứ tự thêm vào từng phân mảnh) cho đến khi một hoạt động trả về true hoặc tất cả các phân mảnh đã được gọi.

Lưu ý: Android 3.0 bổ sung khả năng xác định hành vi khi nhấp cho một mục trong trình đơn ở định dạng XML bằng thuộc tính android:onClick. Giá trị cho thuộc tính này phải là tên phương thức được xác định theo hoạt động sử dụng trình đơn. Phương thức phải ở chế độ công khai và chấp nhận thông số MenuItem. Khi hệ thống gọi, phương thức này sẽ chuyển mục trong trình đơn được chọn. Để biết thêm thông tin và ví dụ, hãy xem thêm tài liệu Tài nguyên của trình đơn.

Mẹo: Nếu ứng dụng chứa nhiều hoạt động và một trong số đó cung cấp trình đơn tùy chọn giống nhau, hãy cân nhắc tạo một hoạt động không triển khai gì ngoài các phương thức onCreateOptionsMenu()onOptionsItemSelected(). Sau đó, mở rộng lớp này cho mỗi hoạt động để chia sẻ cùng một trình đơn tùy chọn. Bằng cách đó, bạn có thể quản lý một bộ mã để xử lý các thao tác trong trình đơn và mỗi lớp con sẽ kế thừa các hoạt động của trình đơn đó. Nếu bạn muốn thêm các mục trình đơn vào một trong các hoạt động con, hãy ghi đè onCreateOptionsMenu() trong hoạt động đó. Gọi super.onCreateOptionsMenu(menu) để tạo mục trong trình đơn gốc, sau đó thêm mục mới trong trình đơn bằng menu.add(). Bạn cũng có thể ghi đè hành vi của lớp cao cấp cho từng mục trong trình đơn.

Thay đổi các mục trên trình đơn trong thời gian chạy

Sau khi gọi onCreateOptionsMenu(), hệ thống sẽ giữ lại bản sao của Menu đã điền và sẽ không gọi lại onCreateOptionsMenu() trừ khi trình đơn bị vô hiệu hóa vì lý do nào đó. Tuy nhiên, chỉ nên sử dụng onCreateOptionsMenu() để tạo trạng thái trình đơn ban đầu và không thực hiện thay đổi trong vòng đời hoạt động.

Nếu muốn sửa trình đơn tùy chọn dựa trên các sự kiện xảy ra trong vòng đời của hoạt động, bạn có thể thao tác như vậy trong phương thức onPrepareOptionsMenu(). Phương thức này chuyển đối tượng Menu vì đối tượng này hiện đang tồn tại để bạn có thể sửa nó, chẳng hạn như thêm, xóa hoặc vô hiệu hóa các mục. (Các phân mảnh cũng cung cấp lệnh gọi lại onPrepareOptionsMenu().)

Trên phiên bản Android 2.3.x trở xuống, hệ thống gọi onPrepareOptionsMenu() mỗi khi người dùng mở trình đơn tùy chọn (nhấn nút Trình đơn).

Trên phiên bản Android 3.0 trở lên, trình đơn tùy chọn luôn mở khi các mục trong trình đơn hiển thị ở thanh ứng dụng. Khi một sự kiện xảy ra và bạn muốn cập nhật trình đơn, bạn phải gọi invalidateOptionsMenu() để yêu cầu lệnh gọi hệ thống onPrepareOptionsMenu().

Lưu ý: Bạn không được thay đổi các mục trong trình đơn tùy chọn dựa trên View hiện đang lấy tiêu điểm. Khi ở chế độ cảm ứng (nghĩa là người dùng không sử dụng bi xoay hoặc d-pad), các chế độ xem không thể lấy tiêu điểm. Vì vậy, bạn không được sử dụng tiêu điểm làm cơ sở để sửa đổi các mục trong trình đơn tùy chọn. Nếu bạn muốn cung cấp các mục trình đơn có phân biệt ngữ cảnh cho View, hãy sử dụng Trình đơn ngữ cảnh.

Tạo trình đơn theo ngữ cảnh

Hình 3. Ảnh chụp màn hình của trình đơn ngữ cảnh nổi (bên trái) và thanh thao tác theo ngữ cảnh (phải).

Trình đơn theo ngữ cảnh cung cấp các thao tác ảnh hưởng đến một mục hoặc khung ngữ cảnh cụ thể trong giao diện người dùng. Có thể cung cấp trình đơn ngữ cảnh cho mọi chế độ xem. Tuy nhiên, chế độ xem này thường dùng phổ biến nhất cho các mục ở ListView, GridView hoặc các tập kênh chế độ xem khác, trong đó người dùng có thể thực hiện thao tác trực tiếp ở mỗi chế độ xem mục.

Có hai cách cung cấp thao tác theo ngữ cảnh:

  • Trong trình đơn ngữ cảnh nổi. Một trình đơn sẽ xuất hiện dưới dạng danh sách nổi của các mục trong trình đơn (tương tự như một hộp thoại) khi người dùng nhấp và giữ (nhấn và giữ) trên một chế độ xem để khai báo hỗ trợ cho trình đơn ngữ cảnh. Người dùng có thể thực hiện thao tác theo ngữ cảnh trên một mục tại một thời điểm.
  • chế độ thao tác theo ngữ cảnh. Chế độ này là cách triển khai hệ thống của ActionMode, hiển thị một thanh thao tác theo ngữ cảnh ở đầu màn hình cùng với mục hành động ảnh hưởng đến (các) mục đã chọn. Khi chế độ này hoạt động, người dùng có thể thực hiện một thao tác với nhiều mục cùng lúc (nếu ứng dụng của bạn cho phép).

Lưu ý: Chế độ thao tác theo ngữ cảnh có sẵn trên phiên bản Android 3.0 (API cấp độ 11) trở lên và là kỹ thuật ưu tiên hiển thị những thao tác theo bối cảnh khi tính năng này hoạt động. Nếu ứng dụng hỗ trợ các phiên bản thấp hơn 3.0, thì bạn nên quay lại trình đơn ngữ cảnh nổi trên các thiết bị đó.

Tạo trình đơn ngữ cảnh nổi

Cung cấp trình đơn ngữ cảnh nổi bằng cách:

  1. Đăng ký View liên kết với trình đơn ngữ cảnh bằng cách gọi registerForContextMenu() và chuyển View vào đó.

    Nếu hoạt động sử dụng ListView hoặcGridView và bạn muốn từng mục cung cấp cùng một trình đơn ngữ cảnh, hãy đăng ký tất cả các mục cho trình đơn ngữ cảnh bằng cách chuyển ListView hoặcGridView tới registerForContextMenu().

  2. Triển khai phương thức onCreateContextMenu() trong Activity hoặc Fragment.

    Khi chế độ xem đã đăng ký nhận được một sự kiện nhấp và giữ, hệ thống sẽ gọi phương thức onCreateContextMenu(). Đây là nơi xác định các mục trong trình đơn, thường là làm tăng thêm một tài nguyên của trình đơn. Ví dụ:

    Kotlin

    override fun onCreateContextMenu(menu: ContextMenu, v: View,
                            menuInfo: ContextMenu.ContextMenuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo)
        val inflater: MenuInflater = menuInflater
        inflater.inflate(R.menu.context_menu, menu)
    }
    

    Java

    @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);
    }
    

    MenuInflater cho phép tăng cường trình đơn ngữ cảnh từ một tài nguyên trình đơn. Các thông số của phương thức gọi lại bao gồm View mà người dùng đã chọn và đối tượng ContextMenu.ContextMenuInfo cung cấp thêm thông tin về mục đã chọn. Nếu hoạt động có nhiều chế độ xem, trong đó mỗi chế độ xem cung cấp một trình đơn ngữ cảnh khác nhau, bạn có thể sử dụng các thông số này để xác định trình đơn ngữ cảnh sẽ tăng cường.

  3. Triển khai onContextItemSelected().

    Khi người dùng chọn một mục trong trình đơn, hệ thống sẽ gọi phương thức này để bạn có thể thực hiện thao tác phù hợp. Ví dụ:

    Kotlin

    override fun onContextItemSelected(item: MenuItem): Boolean {
        val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
        return when (item.itemId) {
            R.id.edit -> {
                editNote(info.id)
                true
            }
            R.id.delete -> {
                deleteNote(info.id)
                true
            }
            else -> super.onContextItemSelected(item)
        }
    }
    

    Java

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        switch (item.getItemId()) {
            case R.id.edit:
                editNote(info.id);
                return true;
            case R.id.delete:
                deleteNote(info.id);
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }
    

    Phương thức getItemId() truy vấn mã nhận dạng cho mục trình đơn đã chọn, bạn nên chỉ định cho mỗi mục trình đơn trong XML bằng cách sử dụngandroid:id như được hiển thị trong phần Xác định trình đơn trong XML.

    Khi xử lý thành công một mục trong trình đơn, hãy trả lại true. Nếu không xử lý mục trong trình đơn, bạn nên chuyển mục trong trình đơn tới triển khai lớp cao cấp. Nếu hoạt động của bạn có các phân mảnh, hoạt động trước đó sẽ nhận được lệnh gọi lại này. Bằng cách gọi lớp cao cấp trên khi không được xử lý, hệ thống sẽ chuyển sự kiện đến phương thức gọi lại tương ứng cho mỗi phân mảnh, lần lượt từng phân mảnh (theo thứ tự thêm từng phân mảnh) cho đến khi true hoặc false được trả về. (Quá trình triển khai mặc định cho Activityandroid.app.Fragment trả về false. Vì vậy, bạn phải luôn gọi lớp cao cấp trên khi chưa xử lý.)

Sử dụng chế độ thao tác theo ngữ cảnh

Chế độ thao tác theo ngữ cảnh là cách triển khai hệ thống của ActionMode tập trung sự tương tác của người dùng vào việc thực hiện các thao tác theo ngữ cảnh. Khi người dùng bật chế độ này bằng cách chọn một mục, thanh tác vụ theo ngữ cảnh sẽ xuất hiện ở đầu màn hình để hiển thị các thao tác mà người dùng có thể thực hiện trên (các) mục hiện được chọn. Khi chế độ này được bật, người dùng có thể chọn nhiều mục (nếu cho phép), bỏ chọn các mục và tiếp tục điều hướng trong hoạt động (tùy thuộc vào mức độ cho phép). Chế độ thao tác bị vô hiệu hóa và thanh tác vụ theo ngữ cảnh sẽ biến mất khi người dùng bỏ chọn tất cả các mục, nhấn nút QUAY LẠI hoặc chọn thao tác Xong ở bên trái của thanh.

Lưu ý: thanh thao tác theo ngữ cảnh không nhất thiết phải liên kết với thanh ứng dụng. Chúng hoạt động độc lập, ngay cả khi thanh thao tác theo ngữ cảnh vượt qua vị trí thanh ứng dụng về mặt hình ảnh.

Đối với chế độ xem cung cấp thao tác theo ngữ cảnh, bạn nên gọi chế độ thao tác theo ngữ cảnh trên một trong hai sự kiện (hoặc cả hai):

  • Người dùng nhấp và giữ chuột vào chế độ xem.
  • Người dùng chọn hộp đánh dấu hoặc thành phần giao diện người dùng tương tự trong chế độ xem.

Cách ứng dụng gọi chế độ thao tác theo ngữ cảnh và xác định hành vi cho từng tác vụ tùy thuộc vào thiết kế của bạn. Về cơ bản, có hai thiết kế:

  • Tùy ý đối với các thao tác theo ngữ cảnh trên chế độ xem riêng lẻ.
  • Đối với các thao tác theo ngữ cảnh theo nhóm (batch) trên các nhóm mục trong ListView hoặc GridView (cho phép người dùng chọn nhiều mục và thực hiện thao tác đối với tất cả các mục đó).

Phần sau đây mô tả cách thiết lập bắt buộc cho từng trường hợp.

Bật chế độ thao tác theo ngữ cảnh cho chế độ xem riêng lẻ

Nếu chỉ muốn gọi chế độ thao tác theo ngữ cảnh khi người dùng chọn chế độ xem cụ thể, bạn phải:

  1. Triển khai giao diện ActionMode.Callback. Trong phương thức gọi lại, bạn có thể chỉ định hành động đối với thanh thao tác theo ngữ cảnh, phản hồi các sự kiện nhấp chuột vào mục hành động và xử lý các sự kiện trong vòng đời khác đối với chế độ hành động.
  2. Gọi startActionMode() khi bạn muốn hiển thị thanh (chẳng hạn như khi người dùng nhấp và giữ chế độ xem).

Ví dụ:

  1. Triển khai giao diện ActionMode.Callback:

    Kotlin

    private val actionModeCallback = object : ActionMode.Callback {
        // Called when the action mode is created; startActionMode() was called
        override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
            // Inflate a menu resource providing context menu items
            val inflater: MenuInflater = mode.menuInflater
            inflater.inflate(R.menu.context_menu, menu)
            return true
        }
    
        // Called each time the action mode is shown. Always called after onCreateActionMode, but
        // may be called multiple times if the mode is invalidated.
        override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
            return false // Return false if nothing is done
        }
    
        // Called when the user selects a contextual menu item
        override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
            return when (item.itemId) {
                R.id.menu_share -> {
                    shareCurrentItem()
                    mode.finish() // Action picked, so close the CAB
                    true
                }
                else -> false
            }
        }
    
        // Called when the user exits the action mode
        override fun onDestroyActionMode(mode: ActionMode) {
            actionMode = null
        }
    }
    

    Java

    private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
    
        // Called when the action mode is created; startActionMode() was called
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // Inflate a menu resource providing context menu items
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
            return true;
        }
    
        // Called each time the action mode is shown. Always called after onCreateActionMode, but
        // may be called multiple times if the mode is invalidated.
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false; // Return false if nothing is done
        }
    
        // Called when the user selects a contextual menu item
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
                case R.id.menu_share:
                    shareCurrentItem();
                    mode.finish(); // Action picked, so close the CAB
                    return true;
                default:
                    return false;
            }
        }
    
        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            actionMode = null;
        }
    };
    

    Lưu ý là các lệnh gọi lại sự kiện này gần giống như lệnh gọi lại cho trình đơn tùy chọn, ngoại trừ mỗi lệnh gọi này cũng chuyển đối tượng ActionMode liên kết với sự kiện. Có thể sử dụng API ActionMode để thực hiện nhiều thay đổi đối với CAB, chẳng hạn như sửa đổi tiêu đề và phụ đề với setTitle()setSubtitle() (nhằm cho biết số lượng mục đã chọn).

    Ngoài ra, lưu ý mẫu ở trên sẽ đặt biến actionMode thành null khi hủy chế độ hành động. Ở bước tiếp theo, bạn sẽ thấy cách khởi chạy biến đó và cách lưu biến thành viên trong tác vụ hoặc phân mảnh hữu ích thế nào.

  2. Gọi startActionMode() để bật chế độ thao tác theo ngữ cảnh khi thích hợp, chẳng hạn như để phản hồi một lượt nhấp và giữ trên View:

    Kotlin

    someView.setOnLongClickListener { view ->
        // Called when the user long-clicks on someView
        when (actionMode) {
            null -> {
                // Start the CAB using the ActionMode.Callback defined above
                actionMode = activity?.startActionMode(actionModeCallback)
                view.isSelected = true
                true
            }
            else -> false
        }
    }
    

    Java

    someView.setOnLongClickListener(new View.OnLongClickListener() {
        // Called when the user long-clicks on someView
        public boolean onLongClick(View view) {
            if (actionMode != null) {
                return false;
            }
    
            // Start the CAB using the ActionMode.Callback defined above
            actionMode = getActivity().startActionMode(actionModeCallback);
            view.setSelected(true);
            return true;
        }
    });
    

    Khi gọi startActionMode(), hệ thống sẽ trả về ActionMode đã tạo. Khi lưu sự kiện này vào một biến thành viên, bạn có thể thay đổi thanh thao tác theo ngữ cảnh để phản hồi các sự kiện khác. Trong mẫu trên, ActionMode được dùng để đảm bảo bản sao ActionMode sẽ không được tạo lại nếu đã kích hoạt, bằng cách kiểm tra xem thành viên có rỗng hay không trước khi bắt đầu chế độ hành động.

Bật thao tác theo ngữ cảnh hàng loạt trong ListView hoặc meshView

Nếu có một tập kênh các mục trong ListView hoặc GridView (hoặc phần mở rộng khác của AbsListView) và muốn cho phép người dùng thực hiện các thao tác hàng loạt, bạn phải:

Ví dụ:

Kotlin

val listView: ListView = getListView()
with(listView) {
    choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
    setMultiChoiceModeListener(object : AbsListView.MultiChoiceModeListener {
        override fun onItemCheckedStateChanged(mode: ActionMode, position: Int,
                                               id: Long, checked: Boolean) {
            // Here you can do something when items are selected/de-selected,
            // such as update the title in the CAB
        }

        override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
            // Respond to clicks on the actions in the CAB
            return when (item.itemId) {
                R.id.menu_delete -> {
                    deleteSelectedItems()
                    mode.finish() // Action picked, so close the CAB
                    true
                }
                else -> false
            }
        }

        override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
            // Inflate the menu for the CAB
            val menuInflater: MenuInflater = mode.menuInflater
            menuInflater.inflate(R.menu.context, menu)
            return true
        }

        override fun onDestroyActionMode(mode: ActionMode) {
            // Here you can make any necessary updates to the activity when
            // the CAB is removed. By default, selected items are deselected/unchecked.
        }

        override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
            // Here you can perform updates to the CAB due to
            // an <code><a href="/reference/android/view/ActionMode.html#invalidate()">invalidate()</a></code> request
            return false
        }
    })
}

Java

ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {

    @Override
    public void onItemCheckedStateChanged(ActionMode mode, int position,
                                          long id, boolean checked) {
        // Here you can do something when items are selected/de-selected,
        // such as update the title in the CAB
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        // Respond to clicks on the actions in the CAB
        switch (item.getItemId()) {
            case R.id.menu_delete:
                deleteSelectedItems();
                mode.finish(); // Action picked, so close the CAB
                return true;
            default:
                return false;
        }
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Inflate the menu for the CAB
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context, menu);
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        // Here you can make any necessary updates to the activity when
        // the CAB is removed. By default, selected items are deselected/unchecked.
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        // Here you can perform updates to the CAB due to
        // an <code><a href="/reference/android/view/ActionMode.html#invalidate()">invalidate()</a></code> request
        return false;
    }
});

Vậy là xong. Bây giờ, khi người dùng chọn một mục bằng thao tác nhấp và giữ chuột, hệ thống sẽ gọi phương thức onCreateActionMode() và hiển thị thanh thao tác theo ngữ cảnh cùng với các thao tác đã chỉ định. Mặc dù thanh thao tác theo ngữ cảnh hiển thị, nhưng người dùng có thể chọn các mục khác.

Trong một số trường hợp, thao tác theo ngữ cảnh cung cấp các mục hành động phổ biến, bạn có thể muốn thêm hộp đánh dấu hoặc phần tử giao diện người dùng tương tự cho phép người dùng chọn mục, vì họ có thể không phát hiện ra hành vi nhấp và giữ chuột. Khi người dùng chọn hộp đánh dấu, bạn có thể gọi chế độ thao tác theo ngữ cảnh bằng cách đặt mục danh sách tương ứng ở trạng thái đã đánh dấu chọn là setItemChecked().

Tạo trình đơn bật lên

Hình 4. Trình đơn bật lên trong ứng dụng Gmail được gắn vào nút mục bổ sung ở trên cùng bên phải.

PopupMenu là một trình đơn cách thức (modal) liên kết với một View. Công cụ này xuất hiện bên dưới chế độ xem liên kết nếu còn chỗ hoặc phía trên chế độ xem. Công cụ này hữu ích khi:

  • Cung cấp trình đơn cách điệu mục bổ sung cho các tác vụ liên quan đến nội dung cụ thể (chẳng hạn như tiêu đề email của Gmail, được hiển thị trong hình 4).

    Lưu ý: Tác vụ này không giống với trình đơn ngữ cảnh, thường là đối với các tác vụ ảnh hưởng đến nội dung đã chọn. Đối với tác vụ ảnh hưởng đến nội dung đã chọn, hãy dùng chế độ thao tác theo ngữ cảnh hoặc trình đơn ngữ cảnh nổi.

  • Cung cấp phần thứ hai của một câu lệnh (chẳng hạn như nút được đánh dấu là "Thêm" để tạo một trình đơn bật lên với các tùy chọn "Thêm").
  • Cung cấp trình đơn thả xuống tương tự như Spinner nhưng không giữ lại lựa chọn liên tục.

Lưu ý: PopupMenu có sẵn với API cấp độ 11 trở lên.

Nếu xác định trình đơn trong XML, dưới đây là cách bạn có thể hiển thị trình đơn bật lên:

  1. Tạo bản sao PopupMenu bằng hàm khởi tạo của nó, thao tác này lấy ứng dụng hiện tại ContextView mà bạn nên liên kết trình đơn.
  2. Sử dụng MenuInflater để phóng to tài nguyên của trình đơn vào đối tượng Menu do PopupMenu.getMenu() trả về.
  3. Gọi PopupMenu.show().

Ví dụ: đây là một nút có thuộc tính android:onClick hiển thị trình đơn bật lên:

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_overflow_holo_dark"
    android:contentDescription="@string/descr_overflow_button"
    android:onClick="showPopup" />

Sau đó, tác vụ có thể hiển thị trình đơn bật lên như sau:

Kotlin

fun showPopup(v: View) {
    val popup = PopupMenu(this, v)
    val inflater: MenuInflater = popup.menuInflater
    inflater.inflate(R.menu.actions, popup.menu)
    popup.show()
}

Java

public void showPopup(View v) {
    PopupMenu popup = new PopupMenu(this, v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.actions, popup.getMenu());
    popup.show();
}

Trong API cấp độ 14 trở lên, bạn có thể kết hợp 2 dòng để tăng cường trình đơn bằng PopupMenu.inflate().

Trình đơn bị loại bỏ khi người dùng chọn một mục hoặc nhấn ra bên ngoài khu vực trình đơn. Có thể theo dõi sự kiện loại bỏ bằng cách sử dụng PopupMenu.OnDismissListener.

Xử lý sự kiện nhấp chuột

Để thực hiện thao tác khi người dùng chọn một mục trong trình đơn, bạn phải triển khai giao diện PopupMenu.OnMenuItemClickListener và đăng ký giao diện đó với PopupMenu bằng cách gọi setOnMenuItemclickListener(). Khi người dùng chọn một mục, hệ thống sẽ gọi lệnh gọi lại onMenuItemClick() trong giao diện.

Ví dụ:

Kotlin

fun showMenu(v: View) {
    PopupMenu(this, v).apply {
        // MainActivity implements OnMenuItemClickListener
        setOnMenuItemClickListener(this@MainActivity)
        inflate(R.menu.actions)
        show()
    }
}

override fun onMenuItemClick(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.archive -> {
            archive(item)
            true
        }
        R.id.delete -> {
            delete(item)
            true
        }
        else -> false
    }
}

Java

public void showMenu(View v) {
    PopupMenu popup = new PopupMenu(this, v);

    // This activity implements OnMenuItemClickListener
    popup.setOnMenuItemClickListener(this);
    popup.inflate(R.menu.actions);
    popup.show();
}

@Override
public boolean onMenuItemClick(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.archive:
            archive(item);
            return true;
        case R.id.delete:
            delete(item);
            return true;
        default:
            return false;
    }
}

Tạo nhóm trình đơn

Nhóm trình đơn là một tập hợp các mục trong trình đơn có chung đặc điểm nhất định. Với một nhóm, bạn có thể:

Có thể tạo một nhóm bằng cách lồng các phần tử <item> bên trong phần tử <group> trong tài nguyên của trình đơn hoặc bằng cách chỉ định một mã nhóm bằng phương thức add().

Dưới đây là một tài nguyên trình đơn mẫu bao gồm một nhóm:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_save"
          android:icon="@drawable/menu_save"
          android:title="@string/menu_save" />
    <!-- menu group -->
    <group android:id="@+id/group_delete">
        <item android:id="@+id/menu_archive"
              android:title="@string/menu_archive" />
        <item android:id="@+id/menu_delete"
              android:title="@string/menu_delete" />
    </group>
</menu>

Các mục trong nhóm xuất hiện cùng cấp với mục đầu tiên – cả ba mục trong trình đơn đồng cấp với nhau. Tuy nhiên, có thể sửa đổi đặc điểm của hai mục trong nhóm bằng cách tham chiếu mã nhóm và sử dụng các phương thức được liệt kê ở trên. Hệ thống cũng sẽ không bao giờ tách riêng các mục được nhóm lại. Ví dụ: nếu khai báo android:showAsAction="ifRoom" cho mỗi mục, cả hai sẽ xuất hiện trong thanh thao tác hoặc trong mục bổ sung hành động.

Sử dụng các mục trong trình đơn có thể đánh dấu

Hình 5. Ảnh chụp màn hình của trình đơn phụ có các mục có thể đánh dấu chọn.

Trình đơn có thể hữu ích như khi là một giao diện giúp bật và tắt lựa chọn, sử dụng hộp đánh dấu cho các lựa chọn độc lập hoặc nút chọn cho các nhóm lựa chọn loại trừ lẫn nhau. Hình 5 cho thấy một trình đơn phụ có các mục có thể đánh dấu bằng nút chọn.

Lưu ý: Các mục trong trình đơn (từ trình đơn tùy chọn) không thể hiển thị hộp đánh dấu hoặc nút chọn. Nếu chọn đặt các mục trong Trình đơn biểu tượng có thể đánh dấu, bạn phải cho biết trạng thái đã đánh dấu theo cách thủ công bằng cách hoán đổi biểu tượng và/hoặc văn bản mỗi khi trạng thái thay đổi.

Có thể xác định thao tác đánh dấu cho từng mục trong trình đơn bằng cách sử dụng thuộc tính android:checkable trong phần tử <item>, hoặc cho toàn bộ nhóm có thuộc tính android:checkableBehavior trong phần tử <group>. Ví dụ: tất cả các mục trong nhóm trình đơn này đều có thể đánh dấu được bằng nút chọn:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/red"
              android:title="@string/red" />
        <item android:id="@+id/blue"
              android:title="@string/blue" />
    </group>
</menu>

Thuộc tính android:checkableBehavior chấp nhận một trong hai:

single
Chỉ có thể đánh dấu chọn một mục trong nhóm (nút chọn)
all
Bạn có thể đánh dấu vào tất cả các mục (hộp đánh dấu)
none
Không có mục nào đánh dấu được

Có thể áp dụng trạng thái đã đánh dấu mặc định cho một mục bằng thuộc tính android:checked trong phần tử <item> và thay đổi mã đó bằng phương thức setChecked().

Khi chọn một mục có thể đánh dấu, hệ thống sẽ gọi phương thức gọi lại đã chọn cho mục tương ứng (chẳng hạn như onOptionsItemSelected()). Ở đây, bạn phải đặt trạng thái của hộp đánh dấu vì hộp đánh dấu hoặc nút chọn không tự động thay đổi trạng thái của hộp đánh dấu. Có thể truy vấn trạng thái hiện tại của mục (như trước khi người dùng chọn mục) với isChecked(), sau đó đặt trạng thái đã đánh dấu là setChecked(). Ví dụ:

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.vibrate, R.id.dont_vibrate -> {
            item.isChecked = !item.isChecked
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.vibrate:
        case R.id.dont_vibrate:
            if (item.isChecked()) item.setChecked(false);
            else item.setChecked(true);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Nếu không đặt trạng thái đánh dấu theo cách này, trạng thái hiển thị của mục (hộp đánh dấu hoặc nút chọn) sẽ không thay đổi khi người dùng chọn mục đó. Khi đặt trạng thái, hoạt động này sẽ giữ nguyên trạng thái đã đánh dấu của mục để khi người dùng mở trình đơn vào lúc khác, trạng thái đã đánh dấu đã đặt sẽ hiển thị.

Lưu ý: Mục trình đơn có thể đánh dấu chỉ dùng cho mỗi phiên và không được lưu sau khi ứng dụng bị hủy. Nếu muốn lưu các chế độ cài đặt ứng dụng cho người dùng, bạn nên lưu trữ dữ liệu bằng cách sử dụng Lựa chọn ưu tiên dùng chung.

Thêm mục trong trình đơn dựa trên ý định

Đôi khi bạn muốn một mục trong trình đơn khởi chạy tác vụ bằng cách sử dụng Intent (dù tác vụ đó nằm trong ứng dụng của bạn hay ứng dụng khác). Khi biết ý định mình muốn sử dụng và có một mục cụ thể trong trình đơn kích hoạt ý định đó, bạn có thể thực thi ý định với startActivity() trong phương thức gọi lại theo mục đã chọn (chẳng hạn như lệnh gọi lại onOptionsItemSelected()).

Tuy nhiên, nếu không chắc chắn thiết bị của người dùng có chứa ứng dụng xử lý ý định, thao tác thêm mục trình đơn gọi ứng dụng đó có thể dẫn đến việc một mục trình đơn không hoạt động, vì mục đích có thể không giải quyết được một hoạt động. Để giải quyết vấn đề này, Android cho phép bạn tự động thêm các mục vào trình đơn khi Android tìm thấy các hoạt động trên thiết bị xử lý ý định của bạn.

Để thêm các mục trên trình đơn dựa vào các hoạt động hiện có chấp nhận ý định:

  1. Xác định ý định bằng danh mục CATEGORY_ALTERNATIVE và/hoặc CATEGORY_SELECTED_ALTERNATIVE, cùng với bất kỳ yêu cầu nào khác.
  2. Gọi Menu.addIntentOptions(). Sau đó, Android sẽ tìm kiếm mọi ứng dụng có thể thực hiện ý định đồng thời thêm các ứng dụng đó vào trình đơn của bạn.

Nếu không có ứng dụng nào được cài đặt đáp ứng ý định, sẽ không có mục trình đơn nào được thêm.

Lưu ý: CATEGORY_SELECTED_ALTERNATIVE dùng để xử lý phần tử đang được chọn trên màn hình. Vì vậy, chỉ nên sử dụng trình đơn này khi tạo Trình đơn trong onCreateContextMenu().

Ví dụ:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Create an Intent that describes the requirements to fulfill, to be included
    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
    val intent = Intent(null, dataUri).apply {
        addCategory(Intent.CATEGORY_ALTERNATIVE)
    }

    // Search and populate the menu with acceptable offering applications.
    menu.addIntentOptions(
            R.id.intent_group,  // Menu group to which new items will be added
            0,                  // Unique item ID (none)
            0,                  // Order for the items (none)
            this.componentName, // The current activity name
            null,               // Specific items to place first (none)
            intent,             // Intent created above that describes our requirements
            0,                  // Additional flags to control items (none)
            null)               // Array of MenuItems that correlate to specific items (none)

    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);

    // Create an Intent that describes the requirements to fulfill, to be included
    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
    Intent intent = new Intent(null, dataUri);
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);

    // Search and populate the menu with acceptable offering applications.
    menu.addIntentOptions(
         R.id.intent_group,  // Menu group to which new items will be added
         0,      // Unique item ID (none)
         0,      // Order for the items (none)
         this.getComponentName(),   // The current activity name
         null,   // Specific items to place first (none)
         intent, // Intent created above that describes our requirements
         0,      // Additional flags to control items (none)
         null);  // Array of MenuItems that correlate to specific items (none)

    return true;
}

Đối với mỗi hoạt động được tìm thấy cung cấp bộ lọc ý định khớp với ý định đã xác định, một mục trong trình đơn sẽ được thêm vào, sử dụng giá trị trong android:label của bộ lọc ý định làm tiêu đề mục của trình đơn và biểu tượng ứng dụng làm mục trong trình đơn biểu tượng. Phương thức addIntentOptions() trả về số lượng các mục trong trình đơn đã thêm vào.

Lưu ý: Khi gọi addIntentOptions(), lệnh này sẽ ghi đè mọi mục trong trình đơn theo nhóm trình đơn đã chỉ định ở đối số đầu tiên.

Cho phép thêm hoạt động vào các trình đơn khác

Ngoài ra còn có thể cung cấp dịch vụ về hoạt động của mình cho các ứng dụng khác để có thể đưa ứng dụng vào trình đơn của những ứng dụng khác (ngược với vai trò được mô tả ở trên).

Để được đưa vào trình đơn ứng dụng khác, cần xác định bộ lọc ý định như bình thường, nhưng hãy đảm bảo sử dụng các giá trị CATEGORY_ALTERNATIVE và/hoặc CATEGORY_SELECTED_ALTERNATIVE cho danh mục bộ lọc ý định. Ví dụ:

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

Đọc thêm về cách viết bộ lọc ý định trong tài liệuÝ định và bộ lọc ý định.