Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set id for popup menu items, to be found as view id?

Background

Out automatic tests use views' ids to be able to click on them, so we add ids whenever possible.

The problem

For popup menus, sometimes it's needed to populate them dynamically, but as I've found, even when I do add id for each item, the id isn't found, and can't be used. Even using DDMS's feature "dump view hierarchy for UI automator" shows that no view in the popup menu has an id.

What I've tried

This is a sample code of what I use, to try to set an id for the a single menu item.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    View v=findViewById(R.id.button);
    v.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(final View v) {
            PopupMenu popupMenu = new PopupMenu(MainActivity.this, v);
            final Menu menu = popupMenu.getMenu();
            menu.add(0, R.id.myMenuItem, 0, R.string.app_name).setOnMenuItemClickListener(new OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(final MenuItem item) {
                    return false;
                }
            }) ;
            popupMenu.show();
        }
    });
}

Note that the id is declared in "ids.xml" file, as such:

<item name="myMenuItem" type="id"/>

And this is what DDMS tool shows me :

enter image description here

The question

How come this code doesn't work as expected (meaning have an id for the menu item view) ? What can I do to make the views in it to have ids? What is the correct way to add ids for menu items that are created dynamically ?

like image 298
android developer Avatar asked Nov 08 '22 18:11

android developer


1 Answers

Alright, this is by no means an answer to the problem described in the question. Look at it as an alternative to replace PopupMenu in order to achieve what was asked.

No PopupMenu

After digging through the documents for PopupMenu and its source code, I finally come to understand that PopupMenu is not an implementation that would allow customization (my apology to the PO for the misconception in the comments).

An alternative

As an alternative, a ListPopupWindow is a preferred choice to create a popup menu with the following reasons:

  1. It shares the same parent with PopupMenu - ListView.
  2. It is flexible, allowing custom Adapter to be defined with custom layout.
  3. It also allows run-time creation like PopupMenu does, and allows attaching resource id to the item view.

Implementation

First of all, let's define a custom layout for the popup item (popup_item_view.xml).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    <TextView
        android:id="@+id/popup_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Next, define a custom Adapter class to manipulate the layout.

package com.example.popupmenu;

import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PopupAdapter extends BaseAdapter {
    public static class Item {
        public final int id;
        public final String title;

        public Item(int id, @NonNull String title) {
            this.id = id;
            this.title = title;
        }
    }

    private List<Item> mItemList = new ArrayList<>();

    public PopupAdapter(@NonNull Item[] items) {
        mItemList.addAll(Arrays.asList(items));
    }

    @Override
    public int getCount() {
        return mItemList.size();
    }

    @Override
    public Item getItem(int position) {
        return mItemList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final Item item = getItem(position);
        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.popup_item_view, parent, false);
        }
        convertView.setId(item.id);
        TextView titleView = (TextView) convertView.findViewById(R.id.popup_text);
        titleView.setText(item.title);
        return convertView;
    }
}

Finally, replace the PopupMenu code with this.

PopupAdapter.Item[] items = {
    new PopupAdapter.Item(R.id.popup_item_1, "item 1"),
    new PopupAdapter.Item(R.id.popup_item_2, "item 2")
};

ListPopupWindow popup = new ListPopupWindow(MainActivity.this);
popup.setAnchorView(view);
popup.setAdapter(new PopupAdapter(items));
popup.setModal(true);
popup.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // do something
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
       // do something
    }
});
popup.show();

Hope this helps.

like image 107
LightYearsBehind Avatar answered Nov 14 '22 21:11

LightYearsBehind