Android Basic Training Course: Menu and ContextMenu

    Menus are a common user interface component in many types of applications. To provide a familiar and consistent user experience, we will use the Menu APIs to present user actions and other options in our activities. In this tut, I present a demo project about creating menus and use it.
DEMO VIDEO:

Android menu types

    Android platform provides 3 types of Menu:
- Option Menu: locating at ActionBar or Toolbar, is the primary menu in Android. It's typically used for providing additional info about an app, as well as linking to a help and settings sections.
- Context Menu: display when long click at a view, for example: a ListView row, usually provide customizing methods for this view.
- Popup Menu: display as a Pop-up Dialog when clicking a View like Button, ImageView,...

Option Menus

    Along with the arrival of the ActionBar in API level 11, this menu types located on it. Firstly, we must declare it's layout by creating a new menu resource file (xml) in res/menu folder:
    As you can see, a menu contains 1 or more items in it. Each item has some properties:
- android:id: requirement property, express the uniqueness of the menu entity.
- android:title: name of entity, show on user interface.
- android:icon: set drawable resource use for entity, show instead of it's title if drawable not null.
- app:showAsAction: if set "never", item will be hide in overflow menu in ActionBar, to visible it, we set "ifRoom" or "always".
And output of this menu (two sorting items is hidden in overflow icon, adding item is visible in ActionBar):
    In programmatically code, we must inflate this option menu to Activity through overriding onCreateOptionsMenu() method:
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    Handling each item click event by overriding onOptionsItemSelected(), distinguish each entity event through it's id:
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.a_z) {
            sortByName(countries);
            return true;

        } else if (item.getItemId() == R.id.z_a) {
            reverseByName(countries);
            return true;

        } else if (item.getItemId() == R.id.add) {
            showAddingDialog();
        }

        return super.onOptionsItemSelected(item);
    }    
    Some necessary methods called in onOptionsItemSelected():
    /**
     * sort countries by name A - Z
     */
    private void sortByName(ArrayList<String> countries) {
        Collections.sort(countries, new Comparator<String>() {
            public int compare(String v1, String v2) {
                return v1.compareTo(v2);
            }
        });
    }

    /**
     * sort countries by name Z - A
     */
    private void reverseByName(ArrayList<String> countries) {
        Collections.sort(countries, Collections.reverseOrder(new Comparator<String>() {

            @Override
            public int compare(String s1, String s2) {
                return s1.compareTo(s2);
            }
        }));
    }

    private void showAddingDialog() {
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
        LayoutInflater inflater = this.getLayoutInflater();
        final View dialogView = inflater.inflate(R.layout.layout_add_dialog, null, false);
        dialogBuilder.setView(dialogView);

        final EditText editText = (EditText) dialogView.findViewById(R.id.edit_text);

        dialogBuilder.setTitle("Adding new Country");
        dialogBuilder.setMessage("Input a Country name");

        dialogBuilder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                if (editText.getText().toString().trim().equals("")) {
                    Toast.makeText(MainActivity.this, "Please input some texts!", Toast.LENGTH_SHORT).show();
                } else {
                    //add new country name to List
                    countries.add(editText.getText().toString().trim());

                    //update ListView adapter
                    adapter.notifyDataSetChanged();
                    Toast.makeText(MainActivity.this, "Adding sucessful!", Toast.LENGTH_SHORT).show();
                }
            }
        });
        dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //do nothing, just close this dialog
            }
        });
        AlertDialog b = dialogBuilder.create();
        b.show();
    }
    When running app, we have this screen:
 
    Clicking the "Add item" (the red plus icon), a Dialog will appear to add new ListView item:
    Clicking the overflow button in ActionBar, 2 remaining options is sorting item by name will appear:

Context Menu Type

   The context menu appears when users long-press user interface items, pressing the item and holding it until the menu appears. Android users are typically accustomed to this type of interaction, as it is standard for system functions such as altering home screen icons.
    Like option menu, it's also declared by xml file in res/menu folder:
    In programmatically code, create ContextMenu by overrding onCreateContextMenu():
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        getMenuInflater().inflate(R.menu.menu_context_main, menu);
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        menu.setHeaderTitle(countries.get(info.position));
    }
    And handling each ContextMenu item event in onContextItemSelected():
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        //find out which menu item was pressed
        switch (item.getItemId()) {
            case R.id.delete:
                countries.remove(info.position);
                adapter.notifyDataSetChanged();
                return true;
            case R.id.go_wiki:
                String listItemName = countries.get(info.position);
                openBrowser("https://en.wikipedia.org/wiki/" + listItemName);

                return true;
            default:
                return false;
        }
    }
    Note: through AdapterView.AdapterContextMenuInfo, ListView item was linked with the ContextMenu item.
    By long-press at each ListView item, a pop-up will be shown with it's title is ListView item name:
    Use this method to open Browser when entry "go to Wikipedia" on ContextMenu clicked:
private void openBrowser(String url) {
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(url));

        startActivity(i);
    }

Popup Menu

   A PopupMenu displays a Menu in a modal popup window anchored to a View. The popup will appear below the anchor view if there is room, or above it if there is not. If the IME is visible the popup will not overlap it until it is touched. Touching outside of the popup will dismiss it. In this example, we show a PopupMenu when click a TextView, inflating it and handle it's items click event is so simple:
 private View.OnClickListener onShowPopupMenu() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupMenu = new PopupMenu(MainActivity.this, v);
                popupMenu.setOnMenuItemClickListener(onPopupMenuClickListener());
                popupMenu.inflate(R.menu.menu_pop_up);
                popupMenu.show();
            }
        };
    }

    private PopupMenu.OnMenuItemClickListener onPopupMenuClickListener() {
        return new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.hide:
                        if (listView.getVisibility() == View.VISIBLE) {
                            //hiding listview
                            listView.setVisibility(View.GONE);
                        } else {
                            //showing listview
                            listView.setVisibility(View.VISIBLE);
                        }
                        return true;
                    case R.id.change_color:
                        listViewHeader.setBackgroundColor(Color.GREEN);
                        return true;
                    case R.id.others:
                        Toast.makeText(MainActivity.this, "Other option, please define later!", Toast.LENGTH_SHORT).show();
                        return true;

                    default:
                        return false;
                }
            }
        };
    }
    This PopupMenu will display below the parent view:

Completing our project

    At this project, I use Toolbar instead of ActionBar as recommended in Material Design style, so set Toolbar as ActionBar in onCreate(). Beside it, register ContextMenu in a defined view by call registerForContextMenu() method:
private ListView listView;
    private ArrayList<String> countries;
    private ArrayAdapter<String> adapter;
    private TextView listViewHeader;
    private Toolbar toolbar;
    private PopupMenu popupMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.list);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        listViewHeader = (TextView) findViewById(R.id.header_list);
        listViewHeader.setOnClickListener(onShowPopupMenu());

        addingDataToList();
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, countries);
        listView.setAdapter(adapter);

        setSupportActionBar(toolbar);

        //register contextMenu with TextView
        registerForContextMenu(listView);
    }

    private void addingDataToList() {
        countries = new ArrayList<>();
        countries.add("Vietnam");
        countries.add("Japan");
        countries.add("China");
        countries.add("Singapore");
        countries.add("USA");
        countries.add("Russia");
        countries.add("Korea");
        countries.add("Thailand");
        countries.add("India");
        countries.add("Malaysia");
        countries.add("Philippines");
        countries.add("Germany");
        countries.add("France");
        countries.add("Netherlands");
    }
    In Activity layout (xml) file, including Toolbar layout:
    And this is a sample Toolbar layout:

Conclusions

    Through this post, you are learned about using menu types in Android. As with any development project, your apps will be more usable if they exploit the type of interaction and functionality users expect as standard. Using the menu is a good way to achieve this when providing informative sections.


Next Chapter

Share


Previous post
« Prev Post
Next post
Next Post »