I have a two layouts files in my app. Also I have Activity extends ListActivity. Every item of this activity looks consider item.xml layout file. I am trying to get context menu when make long presss on item, but I don't see it.
In my activity I trying to registerForContextMenu(getListView()) and override two methods
@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>
All this doesn't work. Maybe the reason is in LinearLayout? I also find similar topic Android: Context menu doesn't show up for ListView with members defined by LinearLayout? but I have more complicated list item.
How to get context menu in my case?
Also in my activity I have inner class extends ArrayAdapter. In this class in getView method I can set OnCreateContextMenuListener on every View, after that context menu is appears, but I don't know how to handle items clicks. If I am trying to do this in method onContextItemSelected, item.getMenuInfo() object always is null and i can't to get some information from it.
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);
}
});
Thanks. Hope for your help.
Actually, you just need to make View long clickable by calling
It's not needed to set dummy
setOnCreateContextMenuListener
, because it's does just that - set's the item long clickable.I got solution, my friend helped me! Hope this information will helpful to someone. This is complete class code with ArrayAdapter and complex list layout and context menu.
let me know if someone will find better approach. Thanks!
I don't think you want to attach a context menu to the specific listView items. By calling registerForContextMenu(getListView()) you should get that functionality for free. I would hook your application up to a debugger after you remove the contextMenu hooks from the adapter code and set a breakpoint inside of onCreateContextMenu(). My suspicion is that it is getting called but the layout that is being inflated is not what you expect.
Following segments of code from nested class ComplexObjectAdapter, listed into Georgy Gobozov's answer, are not really needed:
It just works because inside the function setOnCreateContextMenuListener() from class View, it calls the function setLongClickable(true):
It means the problem can be solved setting the Long Clickable property for each child item, after it is created:
or it also can be solved setting this property in the XML layout file of the list view child elements, for example:
The basic problem is that the item is being drawn on by the second item.xml layout - so the root element (LinearLayout) is what is being long pressed rather than what the original ListView provided. As such, when you inflate the item.xml layout, you need to call the setOnCreateContextMenuListener as you have in fact done in the second example. The problem with this is that there is no way for the layout from item.xml (which is a LinearLayout) to communicate back to the Activity which position was chosen. This is because the LinearLayout does not override the getContextMenuInfo() method which in a ListView returns a AdapterView.AdapterContextMenuInfo (as everyone seems to coerce their ContextMenuInfo to).
So ideally, you want to create your own LinearLayout descendant that makes the getContextMenuInfo public, creates a fake one if there isn't one there, and when onCreateContextMenu is called in your custom adapter, it grabs it from your custom LinearLayout and puts the position/id in there, which your activity can pull out.
This is what I have done in my own application and it works very nicely and is a generic solution - you can in fact put anything you like in there as long as it implements the ContextMenuInfo interface (which is just a marker interface).
I don't now why, it is necessary to set a null OnCreateContextMenuListener on every list row (in addition to registerForContextMenu(...) and implement onCreateContextMenu(...) and onContextItemSelected(...)