Запуск PopupMenu с помощью кнопок внутри элемента ListView

Типы меню

Позвольте мне начать с выделения различия между контекстными меню и всплывающими меню (взято отсюда ):

В качестве руководства, документы различают их использование: – PopupMenu: «Предоставление меню стиля переполнения для действий, относящихся к определенному контенту (например, заголовкам электронной почты Gmail …» – ContextualMenu: «Для действий, влияющих на выбранный контент … "

Я после визуального взгляда и взаимодействия PopupMenu .

Моя настройка (и цель)

У меня есть ListView, где у каждого элемента есть кнопка справа.

-------------------- | Item 1 [ ]| -------------------- -------------------- | Item ... [ ]| -------------------- -------------------- | Item n [ ]| -------------------- 

Сохраняя onItemClick для каждого ListItem, я бы хотел использовать кнопку для запуска PopupMenu .

Действия в PopupMenu перечислены в my_menu.xml , поэтому единственное различие между каждым экземпляром меню – это элемент, на который он был нажат.

Что я пробовал

Я попытался переопределить getView() в моем ListAdapter чтобы добавить OnClickListener для каждой кнопки, как в этом сообщении . Результат был непоследовательным; Не все клики регистрировались (возможно, из-за повторной переработки – я еще не пробовал это исправление ), но в целом подход казался squiffy, учитывая легкость указания контекстного меню для списка.

Я также попытался добавить контекстное меню, которое было мертвым легко, за исключением того, что оно срабатывает только при длительном нажатии элемента списка.

Является ли метод getView() способом перехода или что-то проще?

В моем списке, у меня есть кнопка мини-переполнения для каждого элемента, похожая на каждый трек в плейлисте для Play Music. Они отображают PopupMenu для каждого элемента там, когда вы нажимаете кнопку переполнения. Длинная печать ничего не делает.

Я бы хотел, но не уверен, как это сделать? На странице меню только описано, как включить всплывающее меню для отдельных просмотров.

RegisterForContextMenu registerForContextMenu(ListView lv) – единственное, что я видел, что могу применить ко всему ListView, но, похоже, работает только с длинными нажатиями всего списка. Есть ли способ связать это событие с щелчком определенного представления в элементе списка (при сохранении элемента списка для остальной части элемента списка)?

Я попытался установить onClickListener в getView() как описано здесь, но он чувствует себя squishy для PopupMenu, и не все клики регистрировались каждый раз (это было последовательно непоследовательно).

Обновление – с getView () снова переопределено

Когда я создаю StacksCursorAdapter, я передаю экземпляр StackViewFragment, который хранится как поле (поэтому его можно назначить представлениям в качестве прослушивателя кликов).

ViewHolder – это класс с public final ImageView miniOverflow

StacksCursorAdapter (расширяет SimpleCursorAdapter):

 @Override public View getView(int position, View convertView, ViewGroup parent) { View row = super.getView(position, convertView, parent); ViewHolder holder = (ViewHolder) row.getTag(); if (holder == null) { holder = new ViewHolder(row); row.setTag(holder); } holder.miniOverflow.setTag(R.id.tag_stack_position, position); holder.miniOverflow.setOnClickListener(listener); return row; } 

StackViewFragment (расширяет ListFragment, реализует View.OnClickListener):

 @Override public void onClick(View v) { Log.d(TAG, "mini overflow clicked"); Log.d(TAG, "position:::::" + v.getTag(R.id.tag_stack_position)); PopupMenu popup = new PopupMenu(getActivity(), v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.menu_stackview_listitem, popup.getMenu()); popup.show(); } 

stack_list_item.xml:

 <?xml version="1.0" encoding="utf-8"?> <!-- a single row item for a Stacks listview --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="48dp" android:descendantFocusability="blocksDescendants" > ... <other views> ... <ImageView android:id="@+id/moreoverflow_btn" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:alpha="0.4" android:scaleType="fitCenter" android:src="@drawable/ic_menu_moreoverflow_black" android:layout_alignParentRight="true" /> </RelativeLayout> 

Проблема на этом перекрестке состоит в том, что я должен щелкнуть несколько раз изредка, чтобы получить щелчок для регистрации (на кнопке). Это без прокрутки, поэтому это не связано с переработкой вида.

Заключение (решение eskimoapps.com отмечено как правильно)

Таким образом, не было никаких проблем с несколькими кликами, за исключением того, что моя цель касания не была в том месте, которое я ожидал, – ресурс изображения, который я использовал для мини-переполнения, взвешен вправо (так, что три точки находятся рядом с правым краем Цель касания), означающая, что я просто отсутствовал в половине случаев (facepalm).

Переопределение getView() как я показал выше, кажется, работает нормально, и на самом деле getView() можно изменить еще дальше, установив OnClickListener только в том случае, если это необходимо (но определенно, обновление тега должно выполняться для каждого вида, а не Только недавно созданные):

 @Override public View getView(int position, View convertView, ViewGroup parent) { View row = super.getView(position, convertView, parent); ViewHolder holder = (ViewHolder) row.getTag(); if (holder == null) { holder = new ViewHolder(row); row.setTag(holder); holder.miniOverflow.setOnClickListener(listener); } holder.miniOverflow.setTag(R.id.tag_stack_position, position); return row; } 

Solutions Collecting From Web of "Запуск PopupMenu с помощью кнопок внутри элемента ListView"

Переопределение getView – это правильный подход, и вы на правильном пути, думая, что переработка просмотров усложнит ситуацию (если вы действительно пересматриваете виды).

Поскольку методов getOnClickListener нет, вам просто нужно будет установить новый OnClickListener для переработанных представлений, а также неинтегрированных (если вы не хотите создавать пользовательский вид, реализующий getOnClickListener).

Если бы я хотел сделать это сегодня, я бы использовал шаблон HolderView .

Для шаблона HolderView требуется настраиваемая группа view / viewgroup (класс, расширяющий группу View / Viewgroup, которая является корнем вашего макета списка / сетки, с 3 стандартными конструкторами представлений).

Общая идея заключается в том, что адаптер не отвечает за обновление содержимого представления напрямую; Вместо этого он даст представление всей необходимой информации, чтобы обновить себя:

 @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = createView(parent); } updateView((GalleryItemView) convertView, position); return convertView; } private View createView(ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); return inflater.inflate(R.layout.gallery_item_view, null, false); } private void updateView(GalleryItemView view, int position) { GalleryElement item = getItem(position); view.updateWith(position, item, listener); } 

На мой взгляд:

 public class GalleryItemView extends ImageView { public GalleryItemView(Context context, AttributeSet attrs) { super(context, attrs); } void updateWith(int position, final GalleryElement item, final GalleryAdapter.GalleryItemListener listener) { if (position % 2 == 0) { setBackgroundColor(getColor(android.R.color.holo_orange_dark)); } else { setBackgroundColor(getColor(android.R.color.holo_orange_light)); } setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.onGalleryItemClicked(item.id); } }); } @ColorInt private int getColor(@ColorRes int colorRes) { return getResources().getColor(colorRes); } }