Как установить тег в MenuItem?

Я создаю всплывающее меню в android, и мне нужно сохранить некоторые идентификаторы в каждом элементе меню. Идентификаторы являются String, поэтому было бы неплохо, если бы я мог установить массив String в MenuItem.

Проблема в том, что MenuItem не имеет метода setTag.

Как еще я могу прикрепить к нему некоторые данные?

EDIT: Geobits упоминается о getActionView();

К сожалению, он возвращает null.

Однако можно ли сделать следующее?

 View view = new View(getActivity());
 view.setTag(tag);
 menuItem.setActionView(view);

Ответ 1

Каждый MenuItem имеет связанный с ним View называемый ActionView. Если вы используете пользовательский ActionView, вы можете получить его с помощью MenuItem.getActionView() и установить/получить тег на нем.

Например, чтобы установить тег:

public void setMenuItemTag(MenuItem item, Object tag)
{
    View actionView = item.getActionView();
    actionView.setTag(tag);
}

редактировать

Если вы не используете пользовательский ActionView, вы можете использовать HashMap для хранения тегов. Используйте MenuItem в качестве ключа.

public void setMenuItemTag(MenuItem item, Object tag)
{
    myMap.put(item, tag);
}

// returns null if tag has not been set(or was set to null)
public Object getMenuItemTag(MenuItem item, Object tag)
{
    return myMap.get(item);
}

Ответ 2

Хакерный способ установки тегов при использовании пользовательских представлений. Идея довольно проста, после создания фактического представления мы пытаемся найти ее по ее тексту и значку

private void addButtonToMenu(Toolbar toolbar, Menu menu, String title, Drawable icon, String testId) {
    MenuItem menuItem = menu.add(title);
    if (icon != null){
        menuItem.setIcon(icon);
    }
    setTestId(toolbar, title, icon, testId);
}

private void setTestId(Toolbar toolbar, String title, Drawable icon, String testId) {
    UiUtils.runOnPreDrawOnce(toolbar, () -> {
        ActionMenuView buttonsLayout = ViewUtils.findChildByClass(toolbar, ActionMenuView.class);
        List<TextView> buttons = ViewUtils.findChildrenByClass(buttonsLayout, TextView.class);
        for (TextView view : buttons) {
            if (!TextUtils.isEmpty(title) && title.equals(view.getText())) {
                view.setTag(testId);
            } else if (icon != null && ArraryUtils.containes(view.getCompoundDrawables(), icon)) {
                view.setTag(testId);
            }
        }
    });
}

// Helper functions

public class UiUtils {

    public static void runOnPreDrawOnce(final View view, final Runnable task) {
        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                view.getViewTreeObserver().removeOnPreDrawListener(this);
                task.run();
                return true;
            }
        });
    }
}

public class ArrayUtils {
    public static boolean contains(Object[] array, Object item) {
        if (isNullOrEmpty(array)) return false;
        for (Object o : array) {
            if (o == item) return true;
        }
        return false;
    }

    private static boolean isNullOrEmpty(Object[] array) {
        return array == null || array.length == 0;
    }
}

public class ViewUtils {
    @Nullable
    public static <T> T findChildByClass(ViewGroup root, Class clazz) {
        for (int i = 0; i < root.getChildCount(); i++) {
            View view = root.getChildAt(i);
            if (clazz.isAssignableFrom(view.getClass())) {
                return (T) view;
            }

            if (view instanceof ViewGroup) {
                view = findChildByClass((ViewGroup) view, clazz);
                if (view != null && clazz.isAssignableFrom(view.getClass())) {
                    return (T) view;
                }
            }
        }
        return null;
    }

    public static <T> List<T> findChildrenByClass(ViewGroup root, Class clazz) {
        List<T> ret = new ArrayList<>();
        for (int i = 0; i < root.getChildCount(); i++) {
            View view = root.getChildAt(i);
            if (clazz.isAssignableFrom(view.getClass())) {
                ret.add((T) view);
            }
        }
        return ret;
    }
}