检测哪个选定项(在ListView中)产生了ContextMenu(Android)

时间:2023-01-19 11:23:25

I have a ListView that will allow the user to long-press an item to get a context menu. The problem I'm having is in determining which ListItem they long-pressed. I've tried doing this:

我有一个ListView,允许用户长按项目以获取上下文菜单。我遇到的问题是确定他们长按哪个ListItem。我试过这样做:

myListView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
  @Override public void onCreateContextMenu(ContextMenu menu, final View v, ContextMenuInfo menuInfo) {
   menu.add("Make Toast")
    .setOnMenuItemClickListener(new OnMenuItemClickListener() {
     @Override public boolean onMenuItemClick(MenuItem item) {
      String toastText = "You clicked position " + ((ListView)v).getSelectedItemPosition();
      Toast.makeText(DisplayScheduleActivity.this, toastText, Toast.LENGTH_SHORT).show();
      return true;
     }
    });
  } 
 });

but it just hangs until an ANR pops up. I suspect that after the menu is created the ListItem is no longer selected.

但它只是挂起,直到ANR弹出。我怀疑在创建菜单后,不再选择ListItem。

It looks like you could monitor for clicks or long-clicks then record the clicked item there:

看起来您可以监控点击或长按,然后在那里记录点击的项目:

 mArrivalsList.setOnItemLongClickListener(new OnItemLongClickListener() {
  @Override public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
   // record position/id/whatever here
   return false;
  }
 });

but that feels majorly kludgey to me. Does anyone have any better solutions for this?

但这对我来说感觉很重要。有没有人有更好的解决方案呢?

8 个解决方案

#1


75  

I do exactly this. In my onCreateContextMenu(...) method, I cast the ContextMenu.ContextMenuInfo to AdapterView.AdapterContextMenuInfo. From there, you can get the targetView, which you cast again to the widget. The complete code is available in HomeActivity.java, look for the onCreateContextMenu(...) method.

我这样做。在我的onCreateContextMenu(...)方法中,我将ContextMenu.ContextMenuInfo转换为AdapterView.AdapterContextMenuInfo。从那里,您可以获得targetView,然后再将其投射到窗口小部件。完整的代码在HomeActivity.java中可用,查找onCreateContextMenu(...)方法。

@Override
public void onCreateContextMenu(ContextMenu contextMenu,
                                View v,
                                ContextMenu.ContextMenuInfo menuInfo) {
    AdapterView.AdapterContextMenuInfo info =
            (AdapterView.AdapterContextMenuInfo) menuInfo;
    selectedWord = ((TextView) info.targetView).getText().toString();
    selectedWordId = info.id;

    contextMenu.setHeaderTitle(selectedWord);
    contextMenu.add(0, CONTEXT_MENU_EDIT_ITEM, 0, R.string.edit);
    contextMenu.add(0, CONTEXT_MENU_DELETE_ITEM, 1, R.string.delete);
}

Note that I store the selected text as well as the select id in private fields. Since the UI is thread confined, I know the selectedWord and selectedWordId fields will be correct for later actions.

请注意,我将所选文本以及选择ID存储在私有字段中。由于UI是线程限制的,我知道selectedWord和selectedWordId字段对于以后的操作是正确的。

#2


65  

First of all, I'm wondering if you're making things a little overly complicated by using View.setOnCreateContextMenuListener(). Things get a lot easier if you use Activity.registerForContextMenu(), because then you can just use Activity.onCreateContextMenu() and Activity.onContextItemSelected() to handle all of your menu events. It basically means you don't have to define all these anonymous inner classes to handle every event; you just need to override a few Activity methods to handle these context menu events.

首先,我想知道你是否通过使用View.setOnCreateContextMenuListener()使事情变得过于复杂。如果使用Activity.registerForContextMenu(),事情会变得容易得多,因为这样你就可以使用Activity.onCreateContextMenu()和Activity.onContextItemSelected()来处理所有的菜单事件。它基本上意味着您不必定义所有这些匿名内部类来处理每个事件;您只需要覆盖一些Activity方法来处理这些上下文菜单事件。

Second, there's definitely easier ways to retrieve the currently selected item. All you need to do is keep a reference either to the ListView or to the Adapter used to populate it. You can use the ContextMenuInfo as an AdapterContextMenuInfo to get the position of the item; and then you can either use ListView.getItemAtPosition() or Adapter.getItem() to retrieve the Object specifically linked to what was clicked. For example, supposing I'm using Activity.onCreateContextMenu(), I could do this:

其次,检索当前所选项目的方法肯定更简单。您需要做的就是保持对ListView或用于填充它的Adapter的引用。您可以使用ContextMenuInfo作为AdapterContextMenuInfo来获取项目的位置;然后您可以使用ListView.getItemAtPosition()或Adapter.getItem()来检索专门链接到所点击内容的Object。例如,假设我正在使用Activity.onCreateContextMenu(),我可以这样做:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);

    // Get the info on which item was selected
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;

    // Get the Adapter behind your ListView (this assumes you're using
    // a ListActivity; if you're not, you'll have to store the Adapter yourself
    // in some way that can be accessed here.)
    Adapter adapter = getListAdapter();

    // Retrieve the item that was clicked on
    Object item = adapter.getItem(info.position);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    // Here's how you can get the correct item in onContextItemSelected()
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    Object item = getListAdapter().getItem(info.position);
}

#3


4  

this is another way on how to create context menu n how to delete the item selected here is the whole code

这是另一种关于如何创建上下文菜单的方法n如何删除这里选择的项目是整个代码

     public class SimpleJokeList extends Activity {
public static final int Upload = Menu.FIRST + 1;
public static final int Delete = Menu.FIRST + 2;
int position;
ListView lv;
EditText jokeBox;
Button addJoke;
MyAdapter adapter;
private ArrayAdapter<String> mAdapter;
private ArrayList<String> mStrings = new ArrayList<String>();
String jokesToBeAdded;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.simplejokeui);



    lv=(ListView)findViewById(R.id.jokelist);
    addJoke=(Button)findViewById(R.id.addjoke);
    jokeBox=(EditText)findViewById(R.id.jokebox);


    mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);


    registerForContextMenu(lv);
    listItemClicked();
    addJokes();

private void addJokes() {
    // TODO Auto-generated method stub
    addJoke.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            jokesToBeAdded=jokeBox.getText().toString();
            if(jokesToBeAdded.equals("")){
            Toast.makeText(getApplicationContext(), "please enter some joke", Toast.LENGTH_LONG).show();
            }
            else{
                lv.setAdapter(mAdapter);
                mAdapter.add(jokesToBeAdded);
                jokeBox.setText(null);
            }   
        }
    });
}
private void listItemClicked() {
    // TODO Auto-generated method stub
    lv.setOnItemLongClickListener(new OnItemLongClickListener() {

        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            // TODO Auto-generated method stub
            position=arg2;
            return false;
        }
    });
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
        ContextMenuInfo menuInfo) {
    // TODO Auto-generated method stub
    super.onCreateContextMenu(menu, v, menuInfo);
    populateMenu(menu);
    menu.setHeaderTitle("Select what you wanna do");

}
private void populateMenu(ContextMenu menu) {
    // TODO Auto-generated method stub
     menu.add(Menu.NONE, Upload, Menu.NONE, "UPLOAD");
        menu.add(Menu.NONE, Delete, Menu.NONE, "DELETE");
}
 @Override
    public boolean onContextItemSelected(MenuItem item) 
    {
     return (applyMenuChoice(item) || super.onContextItemSelected(item));
    }


private boolean applyMenuChoice(MenuItem item) {
    // TODO Auto-generated method stub
    switch (item.getItemId()) 
    {   
         case Delete:

             String s=mAdapter.getItem(position);
             mAdapter.remove(s);
            // position--;
             Toast.makeText(getApplicationContext(),"Congrats u HAve Deleted IT", Toast.LENGTH_LONG).show();
        return (true);
    }
    return false;
}

#4


3  

And don't forget to put this

别忘了这个

registerForContextMenu(listview);

in your onCreate method to get your context Menu visible.

在onCreate方法中,以使您的上下文菜单可见。

#5


2  

We have used with success:

我们成功地使用了:

@Override
public boolean onContextItemSelected
(
MenuItem item
)
    {
    if (!AdapterView.AdapterContextMenuInfo.class.isInstance (item.getMenuInfo ()))
        return false;

    AdapterView.AdapterContextMenuInfo cmi =
        (AdapterView.AdapterContextMenuInfo) item.getMenuInfo ();

    Object o = getListView ().getItemAtPosition (cmi.position);

    return true;
    }

#6


2  

Isn't the view argument the actual selected row's view, or am I missing the question here?

视图参数不是实际选中的行的视图,还是我在这里错过了这个问题?

ListView lv;
private OnItemLongClickListener onLongClick = new OnItemLongClickListener() {
    public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
            int arg2, long arg3) {
        lv.showContextMenuForChild(arg1);
        lv.showContextMenu();
        return false;
    }
};

#7


1  

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    View TargetV=(View) info.targetView;
    text1 = (String) ((TextView) TargetV.findViewById(R.id.textView1)).getText();
    text2 = (String) ((TextView) TargetV.findViewById(R.id.textView2)).getText();
    if(List3Ok){
        text3 = (String) ((TextView) TargetV.findViewById(R.id.textView3)).getText();   
    }
    selectedWord = text1 + "\n" + text2 + "\n" + text3;
    selectedWordId = info.id;
    menu.setHeaderTitle(selectedWord);
    MenuInflater inflater = this.getActivity().getMenuInflater();
    inflater.inflate(R.menu.list_menu, menu);
}

#8


0  

I case you are using SimpleCursorAdapder you may do it like this

我说你使用的是SimpleCursorAdapder,你可以这样做

    @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    getActivity().getMenuInflater().inflate(R.menu.project_list_item_context, menu);

    // Getting long-pressed item position
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
    int position = info.position;

    // Get all records from adapter 
    Cursor c = ((SimpleCursorAdapter)getListAdapter()).getCursor();                     

    // Go to required position
    c.moveToPosition(position);

    // Read database fields values associated with our long-pressed item
    Log.d(TAG, "Long-pressed-item with position: " + c.getPosition());
    Log.d(TAG, "Long-pressed-item _id: " + c.getString(0));
    Log.d(TAG, "Long-pressed-item Name: " + c.getString(1));
    Log.d(TAG, "Long-pressed-item Date: " + c.getString(2));
    Log.d(TAG, "Long-pressed-item Path: " + c.getString(3));

    // Do whatever you need here with received values

}

#1


75  

I do exactly this. In my onCreateContextMenu(...) method, I cast the ContextMenu.ContextMenuInfo to AdapterView.AdapterContextMenuInfo. From there, you can get the targetView, which you cast again to the widget. The complete code is available in HomeActivity.java, look for the onCreateContextMenu(...) method.

我这样做。在我的onCreateContextMenu(...)方法中,我将ContextMenu.ContextMenuInfo转换为AdapterView.AdapterContextMenuInfo。从那里,您可以获得targetView,然后再将其投射到窗口小部件。完整的代码在HomeActivity.java中可用,查找onCreateContextMenu(...)方法。

@Override
public void onCreateContextMenu(ContextMenu contextMenu,
                                View v,
                                ContextMenu.ContextMenuInfo menuInfo) {
    AdapterView.AdapterContextMenuInfo info =
            (AdapterView.AdapterContextMenuInfo) menuInfo;
    selectedWord = ((TextView) info.targetView).getText().toString();
    selectedWordId = info.id;

    contextMenu.setHeaderTitle(selectedWord);
    contextMenu.add(0, CONTEXT_MENU_EDIT_ITEM, 0, R.string.edit);
    contextMenu.add(0, CONTEXT_MENU_DELETE_ITEM, 1, R.string.delete);
}

Note that I store the selected text as well as the select id in private fields. Since the UI is thread confined, I know the selectedWord and selectedWordId fields will be correct for later actions.

请注意,我将所选文本以及选择ID存储在私有字段中。由于UI是线程限制的,我知道selectedWord和selectedWordId字段对于以后的操作是正确的。

#2


65  

First of all, I'm wondering if you're making things a little overly complicated by using View.setOnCreateContextMenuListener(). Things get a lot easier if you use Activity.registerForContextMenu(), because then you can just use Activity.onCreateContextMenu() and Activity.onContextItemSelected() to handle all of your menu events. It basically means you don't have to define all these anonymous inner classes to handle every event; you just need to override a few Activity methods to handle these context menu events.

首先,我想知道你是否通过使用View.setOnCreateContextMenuListener()使事情变得过于复杂。如果使用Activity.registerForContextMenu(),事情会变得容易得多,因为这样你就可以使用Activity.onCreateContextMenu()和Activity.onContextItemSelected()来处理所有的菜单事件。它基本上意味着您不必定义所有这些匿名内部类来处理每个事件;您只需要覆盖一些Activity方法来处理这些上下文菜单事件。

Second, there's definitely easier ways to retrieve the currently selected item. All you need to do is keep a reference either to the ListView or to the Adapter used to populate it. You can use the ContextMenuInfo as an AdapterContextMenuInfo to get the position of the item; and then you can either use ListView.getItemAtPosition() or Adapter.getItem() to retrieve the Object specifically linked to what was clicked. For example, supposing I'm using Activity.onCreateContextMenu(), I could do this:

其次,检索当前所选项目的方法肯定更简单。您需要做的就是保持对ListView或用于填充它的Adapter的引用。您可以使用ContextMenuInfo作为AdapterContextMenuInfo来获取项目的位置;然后您可以使用ListView.getItemAtPosition()或Adapter.getItem()来检索专门链接到所点击内容的Object。例如,假设我正在使用Activity.onCreateContextMenu(),我可以这样做:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);

    // Get the info on which item was selected
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;

    // Get the Adapter behind your ListView (this assumes you're using
    // a ListActivity; if you're not, you'll have to store the Adapter yourself
    // in some way that can be accessed here.)
    Adapter adapter = getListAdapter();

    // Retrieve the item that was clicked on
    Object item = adapter.getItem(info.position);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    // Here's how you can get the correct item in onContextItemSelected()
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    Object item = getListAdapter().getItem(info.position);
}

#3


4  

this is another way on how to create context menu n how to delete the item selected here is the whole code

这是另一种关于如何创建上下文菜单的方法n如何删除这里选择的项目是整个代码

     public class SimpleJokeList extends Activity {
public static final int Upload = Menu.FIRST + 1;
public static final int Delete = Menu.FIRST + 2;
int position;
ListView lv;
EditText jokeBox;
Button addJoke;
MyAdapter adapter;
private ArrayAdapter<String> mAdapter;
private ArrayList<String> mStrings = new ArrayList<String>();
String jokesToBeAdded;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.simplejokeui);



    lv=(ListView)findViewById(R.id.jokelist);
    addJoke=(Button)findViewById(R.id.addjoke);
    jokeBox=(EditText)findViewById(R.id.jokebox);


    mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);


    registerForContextMenu(lv);
    listItemClicked();
    addJokes();

private void addJokes() {
    // TODO Auto-generated method stub
    addJoke.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            jokesToBeAdded=jokeBox.getText().toString();
            if(jokesToBeAdded.equals("")){
            Toast.makeText(getApplicationContext(), "please enter some joke", Toast.LENGTH_LONG).show();
            }
            else{
                lv.setAdapter(mAdapter);
                mAdapter.add(jokesToBeAdded);
                jokeBox.setText(null);
            }   
        }
    });
}
private void listItemClicked() {
    // TODO Auto-generated method stub
    lv.setOnItemLongClickListener(new OnItemLongClickListener() {

        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            // TODO Auto-generated method stub
            position=arg2;
            return false;
        }
    });
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
        ContextMenuInfo menuInfo) {
    // TODO Auto-generated method stub
    super.onCreateContextMenu(menu, v, menuInfo);
    populateMenu(menu);
    menu.setHeaderTitle("Select what you wanna do");

}
private void populateMenu(ContextMenu menu) {
    // TODO Auto-generated method stub
     menu.add(Menu.NONE, Upload, Menu.NONE, "UPLOAD");
        menu.add(Menu.NONE, Delete, Menu.NONE, "DELETE");
}
 @Override
    public boolean onContextItemSelected(MenuItem item) 
    {
     return (applyMenuChoice(item) || super.onContextItemSelected(item));
    }


private boolean applyMenuChoice(MenuItem item) {
    // TODO Auto-generated method stub
    switch (item.getItemId()) 
    {   
         case Delete:

             String s=mAdapter.getItem(position);
             mAdapter.remove(s);
            // position--;
             Toast.makeText(getApplicationContext(),"Congrats u HAve Deleted IT", Toast.LENGTH_LONG).show();
        return (true);
    }
    return false;
}

#4


3  

And don't forget to put this

别忘了这个

registerForContextMenu(listview);

in your onCreate method to get your context Menu visible.

在onCreate方法中,以使您的上下文菜单可见。

#5


2  

We have used with success:

我们成功地使用了:

@Override
public boolean onContextItemSelected
(
MenuItem item
)
    {
    if (!AdapterView.AdapterContextMenuInfo.class.isInstance (item.getMenuInfo ()))
        return false;

    AdapterView.AdapterContextMenuInfo cmi =
        (AdapterView.AdapterContextMenuInfo) item.getMenuInfo ();

    Object o = getListView ().getItemAtPosition (cmi.position);

    return true;
    }

#6


2  

Isn't the view argument the actual selected row's view, or am I missing the question here?

视图参数不是实际选中的行的视图,还是我在这里错过了这个问题?

ListView lv;
private OnItemLongClickListener onLongClick = new OnItemLongClickListener() {
    public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
            int arg2, long arg3) {
        lv.showContextMenuForChild(arg1);
        lv.showContextMenu();
        return false;
    }
};

#7


1  

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    View TargetV=(View) info.targetView;
    text1 = (String) ((TextView) TargetV.findViewById(R.id.textView1)).getText();
    text2 = (String) ((TextView) TargetV.findViewById(R.id.textView2)).getText();
    if(List3Ok){
        text3 = (String) ((TextView) TargetV.findViewById(R.id.textView3)).getText();   
    }
    selectedWord = text1 + "\n" + text2 + "\n" + text3;
    selectedWordId = info.id;
    menu.setHeaderTitle(selectedWord);
    MenuInflater inflater = this.getActivity().getMenuInflater();
    inflater.inflate(R.menu.list_menu, menu);
}

#8


0  

I case you are using SimpleCursorAdapder you may do it like this

我说你使用的是SimpleCursorAdapder,你可以这样做

    @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    getActivity().getMenuInflater().inflate(R.menu.project_list_item_context, menu);

    // Getting long-pressed item position
    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
    int position = info.position;

    // Get all records from adapter 
    Cursor c = ((SimpleCursorAdapter)getListAdapter()).getCursor();                     

    // Go to required position
    c.moveToPosition(position);

    // Read database fields values associated with our long-pressed item
    Log.d(TAG, "Long-pressed-item with position: " + c.getPosition());
    Log.d(TAG, "Long-pressed-item _id: " + c.getString(0));
    Log.d(TAG, "Long-pressed-item Name: " + c.getString(1));
    Log.d(TAG, "Long-pressed-item Date: " + c.getString(2));
    Log.d(TAG, "Long-pressed-item Path: " + c.getString(3));

    // Do whatever you need here with received values

}