Пользовательское меню ListView и контекстное меню. Как его получить?
У меня есть два файла макетов в моем приложении. Также у меня есть Activity Extends ListActivity. Каждый элемент этого действия рассматривает элемент layout.xml. Я пытаюсь получить контекстное меню, когда долго нажимает на элемент, но я его не вижу.
В моей работе я пытаюсь зарегистрироватьForContextMenu (getListView()) и переопределить два метода
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getIntent().getExtras();
registerForContextMenu(getListView());
new PopulateAdapterTask().execute(ACTION_SELECT);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
return false;
}
long id = getListAdapter().getItemId(info.position);
Log.d(TAG, "id = " + id);
return true;
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
</LinearLayout>
</TabHost>
Item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="15sp"
android:singleLine="true"
android:ellipsize="marquee"
android:scrollHorizontally = "true"
android:maxWidth="200dp"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="right"
>
<ImageButton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@null"
android:paddingRight="10dp"
android:paddingLeft="10dp"
/>
</LinearLayout>
</LinearLayout>
Все это не работает. Может, причина в LinearLayout? Я также нашел аналогичную тему Android: контекстное меню не отображается для ListView с элементами, определенными LinearLayout?, но у меня есть более сложный элемент списка.
Как получить контекстное меню в моем случае?
Также в моей работе у меня внутренний класс расширяет ArrayAdapter. В этом классе в методе getView я могу установить OnCreateContextMenuListener на каждом представлении, после чего появляется контекстное меню, но я не знаю, как обрабатывать клики по элементам. Если я пытаюсь сделать это в методе onContextItemSelected, объект item.getMenuInfo() всегда имеет значение null, и я не могу получить от него некоторую информацию.
private class ChannelAdapter extends ArrayAdapter<Channel> {
private List<Channel> channels;
public ChannelAdapter(Context context, int textViewResourceId, List<Channel> objects) {
super(context, textViewResourceId, objects);
this.channels = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.station_item, null);
}
v.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
});
Спасибо. Надеюсь на вашу помощь.
Ответы
Ответ 1
Я получил решение, мой друг помог мне! Надеюсь, эта информация поможет кому-то.
Это полный код класса с ArrayAdapter и сложным списком и контекстным меню.
public class ComplexListActivity extends ListActivity {
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ComplexObjectAdapter(this, R.layout.item, getComplexObjects()));
registerForContextMenu(getListView());
}
private List getComplexObjects() {
List<ComplexObject> list = new ArrayList<ComplexObject>();
list.add(new ComplexObject("1", "1", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("2", "2", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("3", "3", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("4", "4", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("5", "5", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("6", "6", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("7", "7", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("8", "8", getResources().getDrawable(R.drawable.icon)));
list.add(new ComplexObject("9", "9", getResources().getDrawable(R.drawable.icon)));
return list;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e("", "bad menuInfo", e);
return false;
}
long id = getListAdapter().getItemId(info.position);
Log.d("", "id = " + id);
Toast.makeText(this, "id = " + id, Toast.LENGTH_SHORT).show();
return true;
}
private class ComplexObjectAdapter extends ArrayAdapter<ComplexObject> implements View.OnCreateContextMenuListener {
private List<ComplexObject> objects;
public ComplexObjectAdapter(Context context, int textViewResourceId, List<ComplexObject> objects) {
super(context, textViewResourceId, objects);
this.objects = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.item, null);
}
final ComplexObject o = objects.get(position);
if (o != null) {
TextView textlInfo = (TextView) v.findViewById(R.id.info);
textlInfo.setText(o.getName());
ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
channelIcon.setAdjustViewBounds(true);
channelIcon.setMaxHeight(30);
channelIcon.setMaxWidth(30);
channelIcon.setImageDrawable(o.getLogo());
ImageButton button = (ImageButton) v.findViewById(R.id.button);
button.setImageResource(R.drawable.icon);
v.setOnCreateContextMenuListener(this);
}
return v;
}
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
// empty implementation
}
}
}
сообщите мне, найдет ли кто-нибудь лучший подход. Спасибо!
Ответ 2
Следующие сегменты кода из вложенного класса ComplexObjectAdapter, перечисленные в ответе Георгия Гобозова, действительно не нужны:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.item, null);
}
final ComplexObject o = objects.get(position);
if (o != null) {
TextView textlInfo = (TextView) v.findViewById(R.id.info);
textlInfo.setText(o.getName());
ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
channelIcon.setAdjustViewBounds(true);
channelIcon.setMaxHeight(30);
channelIcon.setMaxWidth(30);
channelIcon.setImageDrawable(o.getLogo());
ImageButton button = (ImageButton) v.findViewById(R.id.button);
button.setImageResource(R.drawable.icon);
// NOT NEEDED
v.setOnCreateContextMenuListener(this);
}
return v;
}
// NOT NEEDED
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
// empty implementation
}
Это просто работает, потому что внутри функции setOnCreateContextMenuListener() из класса View он вызывает функцию setLongClickable (true):
/**
* Register a callback to be invoked when the context menu for this view is
* being built. If this view is not long clickable, it becomes long clickable.
*
* @param l The callback that will run
*
*/
public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
if (!isLongClickable()) {
setLongClickable(true);
}
mOnCreateContextMenuListener = l;
}
Это означает, что проблема может быть решена при установке свойства Long Clickable для каждого дочернего элемента после его создания:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.item, null);
// SET LONG CLICKABLE PROPERTY
v.setLongClickable(true);
}
final ComplexObject o = objects.get(position);
if (o != null) {
TextView textlInfo = (TextView) v.findViewById(R.id.info);
textlInfo.setText(o.getName());
ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
channelIcon.setAdjustViewBounds(true);
channelIcon.setMaxHeight(30);
channelIcon.setMaxWidth(30);
channelIcon.setImageDrawable(o.getLogo());
ImageButton button = (ImageButton) v.findViewById(R.id.button);
button.setImageResource(R.drawable.icon);
// NOT NEEDED
// v.setOnCreateContextMenuListener(this);
}
return v;
}
или также можно решить эту настройку в файле макета XML дочерних элементов списка, например:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:longClickable="true">
<!-- Child elements -->
</LinearLayout>
Ответ 3
На самом деле вам просто нужно сделать View long clickable, вызвав
v.setLongClickable(true);
Не нужно устанавливать манекен setOnCreateContextMenuListener
, потому что он делает именно это - установите элемент с длительным кликом.
Ответ 4
Я не думаю, что вы хотите привязать контекстное меню к определенным элементам listView. Вызывая registerForContextMenu (getListView()), вы должны получить эту функциональность бесплатно. Я бы привязал ваше приложение к отладчику после удаления крючков contextMenu из кода адаптера и установил точку останова внутри onCreateContextMenu(). Мое подозрение в том, что его называют, но макет, который раздувается, не то, что вы ожидаете.
Ответ 5
Основная проблема заключается в том, что элемент нарисован на втором элементе item.xml - поэтому корневой элемент (LinearLayout) - это то, что долгое нажатие, а не то, что предоставил исходный ListView. Таким образом, когда вы раздуваете макет item.xml, вам нужно вызвать setOnCreateContextMenuListener, как вы это сделали во втором примере. Проблема заключается в том, что макет из item.xml(который является LinearLayout) не подходит для связи с объектом, которое было выбрано. Это связано с тем, что LinearLayout не переопределяет метод getContextMenuInfo(), который в ListView возвращает AdapterView.AdapterContextMenuInfo(поскольку все, кажется, принуждают их ContextMenuInfo).
В идеале вы хотите создать собственный потомок LinearLayout, который делает публичным getContextMenuInfo, создает поддельный, если его там нет, и когда onCreateContextMenu вызывается в вашем пользовательском адаптере, он захватывает его из вашего пользовательского LinearLayout и помещает туда позицию /id, которую ваша деятельность может вытащить.
Это то, что я сделал в своем собственном приложении, и он работает очень хорошо и является универсальным решением - на самом деле вы можете размещать все, что вам нравится, до тех пор, пока оно реализует интерфейс ContextMenuInfo (который является только интерфейсом маркера).
Ответ 6
Теперь я не знаю почему, необходимо установить нулевой OnCreateContextMenuListener в каждой строке списка (в дополнение к registerForContextMenu (...) и реализовать onCreateContextMenu (...) и onContextItemSelected (...)