I need to access the text in a ListView item through a long click selection. For old Android versions I have successfully done this with context menus with the code below.
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
String text = ((TextView) info.targetView).getText().toString();
switch (item.getItemId()) {
case R.id.getText:
getText(text);
return true;
default:
return super.onContextItemSelected(item);
}
}
For newer Android versions, however, I would like to do this with the Contextual Action Bar but can't figure out how to extract the selected text after having selected an item in the bar. The below code does not work.
myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
myListView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
String text = ((TextView) info.targetView).getText().toString();
switch (item.getItemId()) {
case R.id.contextDelete:
getText(text);
return true;;
default:
return false;
}
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
//Other actionmode methods...
});
The Contextual Action Bar shows up ok, but when picking an item from it I get a NullPointerException at the AdapterContextMenuInfo line, since this was obviously made for context menus and not action bars. Is there some equivalent for this for Action bars perhaps? Or how can I get the ListView item text in this case? Thanks.
getCheckedItemPositions() on ListView will return the item positions the user has checked, and getCheckedItemIds() will return their ID values if you are using something like CursorAdapter.
Here is a sample project demonstrating the use of CHOICE_MODE_MULTIPLE_MODAL on API Level 11+ and falling back to context menus on older devices.
I tried using the getCheckedItemIds() method on the ListView object and it returned nothing (I was not using a Cursor object). Turns out this is a common problem people have been facing. So I came up with a workaround for this. In my situation, I had to use the item IDs for creating notifications (just trying out some sample code) so this is what I did to get them:
I created an ArrayList to store the IDs of all the items that have been selected. Every time an item is checked, the onItemCheckedStateChanged(..) method is called. We can use this method to update the ArrayList of IDs based on the state change. Then we can use the IDs stored in this list when the user chooses an option and the onActionItemClicked() method is called. Here's the code:
lv.setMultiChoiceModeListener(new MultiChoiceModeListener() {
private ArrayList<Long> checkedIds = new ArrayList<Long>();
//Code omitted for brevity
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.add(0, 1, 0, R.string.context_create_notification);
return true;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch(item.getItemId()){
case 1:
for(long id : checkedIds){
createNotification(id+1);
}
mode.finish();
break;
}
return true;
}
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
if(checked){
checkedIds.add(id);
} else{
Iterator<Long> iter = checkedIds.iterator();
while(iter.hasNext()){
long stored = (Long) iter.next();
if(stored == id){
iter.remove();
}
}
}
}
});
Related
I have a navigation drawer and I would like to add a view (Button, etc) to the menu. I don't want to use XML, therefore I am not using an inflator. I tried the setActionView method based on these examples at https://www.codota.com/android/methods/android.view.MenuItem/setActionView but I am getting an empty menu. Is what I am trying to do is possible? Here is my relevant part of code:
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem item = menu.add("search");
SearchView sv = new SearchView(this);
item.setActionView(sv);
return true;
}
private static final int MENU_ITEM_ITEM1 = 1;
...
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, MENU_ITEM_ITEM1, Menu.NONE, "Item name");
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_ITEM1:
//your action
return true;
default:
return false;
}
}
I would like to create an app screen that include one ListView.
When the user performs long press on ListView item, I would like to show action mode. I implemented it with the following code and I got the result which I want.
One problem is that I would like to allow the user to select only one list item and select the context menu item in action mode to do the operation. The following code is allowed the user to select multiple list items.
Is android not support ListView.CHOICE_MODE_SINGLE_MODAL choice mode? I had spend a lot of time in Googling but can't find any reference to implement which allows a single choice mode with context action mode. Please help.
mTestListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mTestListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long l, boolean value) {
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_menu_test_single_choice_mode, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_done:
Toast.makeText(getActivity(), "Done", Toast.LENGTH_SHORT).show();
actionMode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
}
Add this code in your method. This code will check item count. If count exceed more than one, it will remove other item except the last one.
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
int selectCount = mList.getCheckedItemCount();
if(selectCount > 1){
SparseBooleanArray checkarr = mList.getCheckedItemPositions();
for(int i=0;i<dataList.size();i++){
/*
check item is checked
and not the last item
* */
if(checkarr.get(i) && position != i){
mList.setItemChecked(i, false);
break;
}
}
}
}
I tried in my app. It works. :). Hope this will help you.
I want to enable multiple view selection on longClick(). Should I declare an action mode object and call startActionMode()? Also, how would I change menu list for single item click? I used the documentation as reference, as shown.
ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Here you can do something when items are selected/de-selected,
// such as update the title in the CAB
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Respond to clicks on the actions in the CAB
switch (item.getItemId()) {
case R.id.menu_delete:
deleteSelectedItems();
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate the menu for the CAB
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context, menu);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// Here you can make any necessary updates to the activity when
// the CAB is removed. By default, selected items are deselected/unchecked.
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Here you can perform updates to the CAB due to
// an invalidate() request
return false;
}
});
To change menu list for single item click following is the code.
int count=0;
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
if (checked) {
count++;
} else {
count--;
}
mode.invalidate(); // Add this to Invalidate CAB so that it calls onPrepareActionMode
}
Now modify the onPrepareActionMode as follows
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
if (selCount == 1){
//show the menu here that you want if only 1 item is selected
} else {
//show the menu here that you want if more than 1 item is selected
}
}
Trying to activate CAB menu when clicking on MenuItem from ActionBar. Here is how I set the GridView for listening to Multi Choice. The multiModeChoiceListener is working fine when I long press on Any item in the GridView. It is working fine. Now I have a requirement to activate the CAB menu when do press on a menu item in Action Bar. Once it is pressed, the CAB menu should read that 0 items are selected. After that it should allow me to select items from GridView on single clicks. How can I achieve this feature?
GridView set listener:
gv.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
gv.setMultiChoiceModeListener(new MultiChoiceModeListener());
MultiChoiceModeListener.java
public class MultiChoiceModeListener implements
GridView.MultiChoiceModeListener {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.featured_multiselect, menu);
MenuItem mi = menu.findItem(R.id.close);
mi.setIcon(R.drawable.cancel);
mode.setTitle("Select Items");
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_SHORT).show();
if (item.getTitle().toString().equalsIgnoreCase("Close")) {
mode.finish();
}
return true;
}
public void onDestroyActionMode(ActionMode mode) {
new ChangeNotifier().changeOnFavoriteStore = true;
new AddFavorites().execute("add", device_id, dataArray);
if (notify == true) {
Toast.makeText(getApplicationContext(),
"Selected items are added to Favorites",
Toast.LENGTH_SHORT).show();
notify = false;
}
}
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
int selectCount = gridView.getCheckedItemCount();
if (selectCount > 0) {
notify = true;
dataArray.add(position);
switch (selectCount) {
case 1:
mode.setSubtitle("One item added to favorites");
break;
default:
mode.setSubtitle("" + selectCount
+ " items added to favorites");
break;
}
}
}
OnMenuItemClick method:
public boolean onPrepareOptionsMenu(final Menu menu) {
final MenuItem editItem = menu.findItem(R.id.editit);
editItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
//the CAB menu should be activated here. So that it reads that 0 items are selected in ActionBar
return false;
}
});
From your question I understand that you're trying to start the GridView associated CAB from clicking one of the menu items. I don't know if you can do this(but I may be mistaken) as the MultiChoiceModeListener expects an item to be checked to start. Depending on your layout and the overall appearance of the GridView, I think you could have a dummy item(as an extra item in the adapter) at the end of the GridView(with no content showing) and use setItemChecked(dummyItemPosition, true) to start the GridView CAB. Of course you'll need to have additional logic to take care of that extra item in your MultiChoiceModeListener:
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
if (position == theDummyPosition)
return; // so we start the CAB but there aren't any items checked
}
int selectCount = gridView.getCheckedItemCount();
if (selectCount > 0) {
notify = true;
dataArray.add(position);
// if you select another item you'll have two selected items(because of the dummy item) so you need to take care of it
switch (selectCount) {
case 1:
mode.setSubtitle("One item added to favorites");
break;
default:
mode.setSubtitle("" + selectCount
+ " items added to favorites");
break;
}
}
}
The solution above is a hack, most likely it would be much easier to lose the MultiChoiceModeListener and simply start an ActionMode that you can manipulate for both situations.
My XML menu definition sets the item R.id.menu_refresh's enabled state to false. When the app runs the menu item is greyed and disabled. Why is this code in the app not enabling the item?
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
MenuItem refresh = menu.getItem(R.id.menu_refresh);
refresh.setEnabled(true);
return true;
}
What am I missing?
Try menu.findItem() instead of getItem(). getItem() takes an index from [0, size) while findItem() takes an id.
this is what I do in my activity for the menu handling ...
//Android Activity Lifecycle Method
// This is only called once, the first time the options menu is displayed.
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}
//Android Activity Lifecycle Method
// Called when a panel's menu is opened by the user.
#Override
public boolean onMenuOpened(int featureId, Menu menu)
{
MenuItem mnuLogOut = menu.findItem(R.id.main_menu_log_out_id);
MenuItem mnuLogIn = menu.findItem(R.id.main_menu_log_in_id);
MenuItem mnuOptions = menu.findItem(R.id.main_menu_options_id);
MenuItem mnuProfile = menu.findItem(R.id.main_menu_profile_id);
//set the menu options depending on login status
if (mBoolLoggedIn == true)
{
//show the log out option
mnuLogOut.setVisible(true);
mnuLogIn.setVisible(false);
//show the options selection
mnuOptions.setVisible(true);
//show the edit profile selection
mnuProfile.setVisible(true);
}
else
{
//show the log in option
mnuLogOut.setVisible(false);
mnuLogIn.setVisible(true);
//hide the options selection
mnuOptions.setVisible(false);
//hide the edit profile selection
mnuProfile.setVisible(false);
}
return true;
}
//Android Activity Lifecycle Method
// called whenever an item in your options menu is selected
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle item selection
switch (item.getItemId())
{
case R.id.main_menu_log_in_id:
{
ShowLoginUI();
return true;
}
case R.id.main_menu_log_out_id:
{
ShowGoodbyeUI();
return true;
}
case R.id.main_menu_options_id:
{
ShowOptionsUI();
return true;
}
case R.id.main_menu_profile_id:
{
ShowProfileUI();
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
I like this approach because it makes the code nice and modular
Use menu.findItem() instead of getItem().
because findItem is used to find item by id.