I have a ListView where I show a menu on the long click. In onContextItemSelected I have a logic to handle the action. I need to know what item in ListView is selected.
If a user selects item that isn't a submenu, I can use MenuItem.getMenuInfo().
But if a user selects a submenu, MenuItem.getMenuInfo() returns null.
What is the correct way how to determine the selected item if there's a submenu ?
The menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/Edit" android:title="Edit" />
<item android:id="#+id/Settings" android:title="Settings">
<menu>
<item android:id="#+id/V1" android:title="V1" />
...
</menu>
</item>
</menu>
onContextItemSelected:
#Override
public boolean onContextItemSelected(MenuItem Item) {
AdapterView.AdapterContextMenuInfo AdapterInfo = (AdapterView.AdapterContextMenuInfo)Item.getMenuInfo(); // getMenuInfo returns null if V1 is selected (submenu) but works if selected item isn't submenu, e.g., 'Edit' as per above XML
UserItem SelectedItem = MyAdapter.getItem(AdapterInfo.position); // MyAdapter is the instance of class that inherits from ArrayAdapter<UserItem> i.e. adapter for ListView
}
you need to do 3 things
1.provide a default section in your switch statement that handles your menu items
2.save off the info.position to a member variable in your Activity
3.when you detect that info is null, use the var you created in step 2
private int mParentContextMenuListIndex;
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfo", e);
return false;
}
//if info == null, it means we have a submenu to deal with, use the saved info.position
int idxOfList = (info!=null) ? info.position : this.mParentContextMenuListIndex;
...
switch (item.getItemId()) {
case R.id.context_menu_item_1:
... //use idxOfList instead of info.position
return true;
case R.id.context_menu_item_2:
... //use idxOfList instead of info.position
return true;
case R.id.context_menu_item_3:
... //use idxOfList instead of info.position
return true;
case R.id.context_submenu_item_1:
... //use idxOfList instead of info.position
return true;
case R.id.context_submenu_item_2:
... //use idxOfList instead of info.position
return true;
default: //can handle submenus if we save off info.position
this.mParentContextMenuListIndex = idxOfList;
}//switch
return super.onContextItemSelected(item);
}
Why don't you use onItemClickLitener() for all the items in you listview without dividing them on munu items and submenu items?
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String s = listView.getItemAtPosition(i).toString();
}
});
So i will be your item position.
If you still want to work with submenu items you need to implement onOptionsItemSelected(MenuItem item) method and catch onclick events based on the id of submenu items .
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case 10:
//do smth here
return true;
case 15:
//do smth here
return true;
case 20:
//do smth here
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Related
I have problems with implementing a dropdown (like a spinner) list in my customized ActionBar. I've tried several solutions, including getActionView() but it doesn't work :/
Here is my code; #Override public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.planner_menu, menu);
MenuItem category_item = menu.findItem(R.id.CategoryAppointment);
Spinner spinner =(Spinner) category_item.getActionView();
String[] categories = new String[]{"meeting","training","puls","medicin","bloodsample"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item,categories);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
parent.setSelection(position);
switch (position) {
case 0:
String category = parent.getSelectedItem().toString();
Toast.makeText(parent.getContext(),
"OnItemSelectedListener : " + category, Toast.LENGTH_SHORT).show();
// Take string and compare it in database.
DB.getAllAppointmentsByCategory(category);
break;
case 1:
// Take string and compare it in database.
break;
case 2:
// Take string and compare it in database.
break;
case 3:
// Take string and compare it in database.
break;
case 4:
// Take string and compare it in database.
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
for (int j = 0; j < menu.size(); j++) {
MenuItem item = menu.getItem(j);
Log.d("TAG", "set flag for " + item.getTitle());
item.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
return true;}
And here is the the options from the meny.
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.AllAppointments:
//DB.getUsersAppointment();
return true;
case R.id.WeekAppointment:
//DB.getUsersAppointmentByWeek(date);
return true;
case R.id.CategoryAppointment:
// setupSpinner();
//DB.getUsersAppointmentByCategory(category);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
The code from the XML file.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".Planning">
<item android:id="#+id/AllAppointments" android:title="All"
android:orderInCategory="10"
app:showAsAction="always|withText">
</item>
<item android:id="#+id/WeekAppointment"
android:title="Week"
android:orderInCategory="10"
app:showAsAction="always|withText"
>
</item>
<item android:id="#+id/CategoryAppointment"
android:title="Cathegories"
android:orderInCategory="10"
app:showAsAction="always|withText"
>
</item>
`
In item id -> CategoryAppointment I want to show a dropdown meny where the user can choose between diffent categories and then list out the data from the database.
I've been working with this for the past hours but I can't seem to fix it. Can someone please explain to me what I have to do and what it is that i'm doing wrong here.
Thank you.
I want custom ListView layout which has multiple selection , so I am doing custom adapter but how I can allow user to select multiple . In default ListView we are given choice mode but I want layout different not checkbook
<Imageview>
<Textview>
Do I have to manage in onItemClick or any method is der ? Small snippet will help
For this you need ListView.CHOICE_MODE_MULTIPLE_MODAL. See the following code snippet,
First create a ListView and it's adapter,
listView = (ListView) findViewById(R.id.listView);
adapter = new AttendanceListAdapter(this, attendanceList);
Set the List choice mode to multiple and add a Multi choice listener,
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new ModeCallback());
listView.setAdapter(adapter);
Your Multi choice listener should look something like this,
private class ModeCallback implements ListView.MultiChoiceModeListener {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.list_select_menu, menu);
mode.setTitle("Select Items");
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.share:
Toast.makeText(AddAttendanceActivity.this, "Shared " + listView.getCheckedItemCount() +
" items", Toast.LENGTH_SHORT).show();
mode.finish();
break;
default:
Toast.makeText(AddAttendanceActivity.this, "Clicked " + item.getTitle(),
Toast.LENGTH_SHORT).show();
break;
}
return true;
}
public void onDestroyActionMode(ActionMode mode) {
}
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
final int checkedCount = listView.getCheckedItemCount();
switch (checkedCount) {
case 0:
mode.setSubtitle(null);
break;
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + checkedCount + " items selected");
break;
}
}
}
Now if you want the selected rows to highlighted add this style to the root element of your list items layout.
<style name="activated" parent="AppTheme">
<item name="android:background">?android:attr/activatedBackgroundIndicator</item>
</style>
I think you you want something like whatsup select for that on long click listener you can change color of custom listview items(rows)
Ok I'm sure this is a dumb question but I couldn't find the answer online. I want to register one of the menu Items for a context Menu, but I don't know how to can't figure out how to access the MenuItem as a view. So when I click one of the buttons on the ActionBar of my application, I want a context menu to pop up. I'm guessing this has to be done in OnCreateOptionsMenu?
Edit: Update... Adding this code works partially but overrides my Drawable.
XML
<item android:id="#+id/Favorites"
android:title="favorite_label"
android:icon="#android:drawable/ic_menu_myplaces"
android:actionViewClass="android.widget.ImageButton"
android:showAsAction="always"
/>
Main Activity
FavoriteButton = (ImageButton) menu.findItem(R.id.Favorites).getActionView();
FavoriteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
registerForContextMenu(v);
}
});
Hi follow below link exmple link
ListView list = (ListView)findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listitem, Countries);
list.setAdapter(adapter);
registerForContextMenu(list);
change registerForContextMenu(list); to registerForContextMenu(buttonname);
i hope it useful to you.
In the resource/menu/main.xml add the below code:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<menu>
<item
android:id="#+id/gray"
android:title="#string/gray" />
<item
android:id="#+id/green"
android:title="#string/green" />
<item
android:id="#+id/red"
android:title="#string/red" />
<item
android:id="#+id/orange"
android:title="#string/orange" />
<item
android:id="#+id/purple"
android:title="#string/dark_blue" />
</menu>
</item>
</menu>
and in the main activity you can access this by overridding the belo method:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.gray:
color = Color.parseColor("#FF666666");
return true;
case R.id.green:
color = Color.parseColor("#FF96AA39");
return true;
case R.id.orange:
color = Color.parseColor("#FFF4842D");
return true;
case R.id.purple:
color = Color.parseColor("#FF5161BC");
return true;
}
return super.onOptionsItemSelected(item);
}
Here is what I have made:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// "menu_main" is the menubar of my actionbar menu
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
// "item" is the menu button I have pressed
int id = item.getItemId();
// "Settings" button
if (id == R.id.action_settings) {
return true;
}
// Difficulty button to change the difficulty of my game
else if (id == R.id.action_difficulty) {
View view = findViewById(R.id.action_difficulty);
registerForContextMenu(view);
openContextMenu(view);
}
return super.onOptionsItemSelected(item);
}
This works fine for me!
BUT! If your menubar button is behind the "three dots" button, the line
registerForContextMenu(view);
will crash your application. I'm figuring out why..
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.
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();
}
}
}
}
});