MenuItemCompat.getActionView(menuItem) returns null - java

I am trying to get the View of the MenuItem.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
View miView = MenuItemCompat.getActionView(item);
if (miView == null) {
Log.e(X, "mView is null");
}
}
but everytime miView is null.
Here's my onCreateOptionsMenu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, R.string.Foo);
return true;
}
I know that MenuItemCompat returns null because the created Menu is not a from support library, so the MenuItem can't be handled by the MenuItemCompat class, isn't?
1) I am looking for some method like onCreateOptionsMenuCompat, is there any method like that?
2) How can i get ActionView from MenuItemCompat class?
and What am i doing wrong ?
PS: my project's minSdkVersion is 9

To get an ActionView from a menu item, you will need to set an ActionView on it first. Normal menu items do not come with ActionViews. ActionViews are used when you need to do something extra in your menu (outside of a normal icon and/or text).
Why are you trying to get a View from the menu item? What are you trying to do with your menu item?

Related

Android: Inflate menu (add items to action bar) only on click of a button

I am trying to inflate a menu only onclick of a button in android. How do i achieve it without creating it automatically by calling onCreateOptionsMenu.
I want the menu to appear only after button is click.
First add this icon in you action R.menu... file and set the visibility as false.
Have a boolean instance variable in our java file.
private boolean isTickVisible = false;
Then you need to override OnPrepareOptions menu like below and set the visibility of the tick menu.
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem someMenuItem = menu.findItem(R.id.tick_menu_item);
someMenuItem.setVisible(isTickVisible);
}
Finally onClick event of your button do the following :
isTickVisible = true;
invalidateOptionsMenu(); //this will redraw your menu.
I fixed this issue by setting the visibility.Inflate the layout and make it visible only on clicking the button.Add a flag inside onClickListener
eg:Hide=true;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_search, menu);
for (int i = 0; i < menu.size(); i++)
if(Hide){
menu.getItem(i).setVisible(true);
}
}

How to call public boolean onPrepareOptionsMenu(Menu menu)

I am using Java and Android Studio. I need to change an image on the actionbar. What I need to do is to change the image I am displaying on the actionbar based on a reading received from a remote sensor. Therefore, I cannot use a clickable method but instead I have some code that activates when the data is received from the sensor. The code then analyzes the data and decides which of several images to display. The program then needs to update the actionbar image. This is the part I need your help on. I think I should use onPrepareOptionsMenu to update the image. However, I cannot seem to get the code correct to call onPrepareOptionsMenu. In particular, onPrepareOptions uses parameters (Menu menu). I cannot seem to specify the second menu properly as it always gives an error. The code below gives:
"required android.view.Menu found int". If I initialize menu with null I get a null reference error. Any suggestions how to correct my code or maybe do something totally different to be able to update the image? Thanks. Below is my java code.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear(); // Clear the menu first
Log.d(TAG, " Before inflation");
getMenuInflater().inflate(R.menu.gatt_services, menu);
Log.d(TAG, "Before the findItem");
menu.findItem(R.id.menu_batlevel).setIcon(R.drawable.low25);
return super.onPrepareOptionsMenu(menu);
}
Code to call the onPrepareOptionsMenu with:
...
else if (dataType == 2.0) {
Menu menu = (R.menu.gatt_services);
getMenuInflater().inflate(R.menu.gatt_services, menu);
onPrepareOptionsMenu(Menu menu);
...
XML code for the action bar. The image I am trying to change is item id/menu_batlevel:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu_refresh"
android:checkable="false"
android:orderInCategory="1"
android:showAsAction="ifRoom"/>
<item android:id="#+id/menu_batlevel"
android:checkable="false"
android:icon="#drawable/discharged"
android:title="BatLev"
android:orderInCategory="2"
android:showAsAction="ifRoom"/>
<item android:id="#+id/menu_connect"
android:title="#string/menu_connect"
android:orderInCategory="100"
android:showAsAction="ifRoom|withText"/>
<item android:id="#+id/menu_disconnect"
android:title="#string/menu_disconnect"
android:orderInCategory="101"
android:showAsAction="ifRoom|withText"/>
</menu>
My solution is shown below. I put the if statements that update the image into the onCreateOptionsMenu:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.d(TAG, "onCreateOptions Before inflation");
getMenuInflater().inflate(R.menu.gatt_services, menu);
...
if (dataType == 2.0){
if (bat_level < 10) {
MenuItem batItem = menu.findItem(R.id.menu_batlevel);
batItem.setIcon(R.drawable.discharged);
}
...
I added a class:
class VersionHelper
{
static void refreshActionBarMenu(Activity activity)
{
activity.invalidateOptionsMenu();
}
}
I call the class from my program:
...
else if (dataType == 2.0) {
VersionHelper.refreshActionBarMenu(DeviceControlActivity.this);
...
The above code is working. As you can tell, I am new to java so if you see a problem with this code or have a better method, please let me know.
If you want to change the image on an existing menu item, you can save a reference to the menu item when it's created, something like this:
private MenuItem photoMenuItem;
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
inflater.inflate(R.menu.menu_end_details, menu);
// find the photo menu and save it
photoMenuItem = menu.findItem(R.id.photoMenuItem);
}
Then when it's time to update the menu item, just call setIcon:
if (photoMenuItem != null)
{
photoMenuItem.setIcon(R.drawable.camera_active);
}
If you want to decide whether or not to show a particular menu item, you can call setVisible instead of setIcon on the items whose presence may change.

Is there a difference between `listView.invalidate()` and `adapter.notifyDataHasChanged()`?

I have a list of items.
I want to delete an item in a long push.
I saw this post and it worked for me.
just out of curiosity i wonder why other solution didn't work for me:
sol 1
I register the list to context menu:
registerForContextMenu(listView);
and then:
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
if (v.getId()==R.id.comments_list) {
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.phone_list_contextual_menu, menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch(item.getItemId()) {
case R.id.edit: {
return true;
}
case R.id.delete: {
comments.remove(info.id);
listView.invalidate();
return true;
}
default: {
return super.onContextItemSelected(item);
}
}
}
Is there a difference between
listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?
what am I missing in order for the remove to work?
sol 2
listView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
int position = (int) v.getTag();
comments.remove(position);
listView.invalidate();
return true;
}
});
instead of
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
comments.remove(pos);
//listView.invalidate();
arrayAdapter.notifyDataSetChanged();
return true;
}
});
I understand setOnItemLongClickListener is more suitable for my need than setOnLongClickListener but yet
why didn't this worked for me?
Is there a difference between
listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?
To my understanding adapter.notifyDataHasChanged() will do what listView.invalidate() plus more. That means it will also include change in number of items, and possibly inform other observers of data change. Relevant code is here:
http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AdapterView.java#798
this is for notifyDataHasChanged(), as you can see mItemCount is udpated with new value. This means if you add more items to your arrayadapter, then invalidate, or better invalidateViews will not show them, at least at the end of list. One thing I have noticed is that above code has no invalidate call - maybe its called by some other methods.
Below is source code for invalidateViews (which is I think more proper than Invalidate):
http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#5078
It has no code to update count of item.
If you search source code for android sources, you will find only few cases when invalidateViews is called, some of those places are optimization hacks.
The difference is that invalidate causes all your views in the list to be scrapped and redrawn. Note I said views so that is what you are actually seeing on the screen (for example you can have 3 views on screen but 20 items in your list)
notifyDataHasChanged on the other hand tells the adapter that the contents have changed and the adapter needs to re-run its methods on the content to refresh the list.
You almost always want to use notifyDataHasChanged but it depends on exactly what you are trying to accomplish.
Hope that helps.

Camera Preview Example

I know this is really basic but it is a error that I cannot find a solution to.
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
I have 2 errors and I dont know what Im doning wrong.
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
Im getting an error at "menu" in "R.menue..."
error 2:
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
/**builder.setMessage(this.getString(R.string.camera_alert))
.setNeutralButton("Close", null);*/
AlertDialog alert = builder.create();
alert.show();
return true;
}
Im getting an error on "id" in "case R.id..."
Thanks
First, do you have : <uses-permission android:name="android.permission.CAMERA" />in your AndroidManifest.xml ?
You can try to check a full Camera preview here for Android : Camera Preview Android
Another good website with source files : Using Camera API with SourceFile
You most likely just copied the source file you linked above into your project. You also have to add res/menu/camera_menu.xml. This defines the options menu that comes up when you press the menu button. See the menu doc for more information how that works if you're interested.
If you don't do that the tools notice that you miss a file that you reference in code but that's not actually there, which results the first error. The second error is also caused by this in an indirect way. The missing ID is also created within the menu file.

How to change menu item text dynamically in Android

I'm trying to change the title of a menu item from outside of the onOptionsItemSelected(MenuItem item) method.
I already do the following;
public boolean onOptionsItemSelected(MenuItem item) {
try {
switch(item.getItemId()) {
case R.id.bedSwitch:
if(item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
break;
}
} catch(Exception e) {
Log.i("Sleep Recorder", e.toString());
}
return true;
}
however I'd like to be able to modify the title of a particular menu item outside of this method.
I would suggest keeping a reference within the activity to the Menu object you receive in onCreateOptionsMenu and then using that to retrieve the MenuItem that requires the change as and when you need it. For example, you could do something along the lines of the following:
public class YourActivity extends Activity {
private Menu menu;
private String inBedMenuTitle = "Set to 'In bed'";
private String outOfBedMenuTitle = "Set to 'Out of bed'";
private boolean inBed = false;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Create your menu...
this.menu = menu;
return true;
}
private void updateMenuTitles() {
MenuItem bedMenuItem = menu.findItem(R.id.bedSwitch);
if (inBed) {
bedMenuItem.setTitle(outOfBedMenuTitle);
} else {
bedMenuItem.setTitle(inBedMenuTitle);
}
}
}
Alternatively, you can override onPrepareOptionsMenu to update the menu items each time the menu is displayed.
As JxDarkAngel suggested, calling this from anywhere in your Activity,
invalidateOptionsMenu();
and then overriding:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.bedSwitch);
if (item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
return super.onPrepareOptionsMenu(menu);
}
is a much better choice. I used the answer from https://stackoverflow.com/a/17496503/568197
you can do this create a global "Menu" object then assign it in onCreateOptionMenu
public class ExampleActivity extends AppCompatActivity
Menu menu;
then assign here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
this.menu = menu;
return true;
}
Then later use assigned Menu object to get required items
menu.findItem(R.id.bedSwitch).setTitle("Your Text");
Create a setOptionsTitle() method and set a field in your class. Such as:
String bedStatus = "Set to 'Out of Bed'";
...
public void setOptionsTitle(String status)
{
bedStatus = status;
}
Now when the menu gets populated, change the title to whatever your status is:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(bedStatus);
// Return true so that the menu gets displayed.
return true;
}
You better use the override onPrepareOptionsMenu
menu.Clear ();
if (TabActual == TabSelec.Anuncio)
{
menu.Add(10, 11, 0, "Crear anuncio");
menu.Add(10, 12, 1, "Modificar anuncio");
menu.Add(10, 13, 2, "Eliminar anuncio");
menu.Add(10, 14, 3, "Actualizar");
}
if (TabActual == TabSelec.Fotos)
{
menu.Add(20, 21, 0, "Subir foto");
menu.Add(20, 22, 1, "Actualizar");
}
if (TabActual == TabSelec.Comentarios)
{
menu.Add(30, 31, 0, "Actualizar");
}
Here an example
I use this code to costum my bottom navigation item
BottomNavigationView navigation = this.findViewById(R.id.my_bottom_navigation);
Menu menu = navigation.getMenu();
menu.findItem(R.id.nav_wall_see).setTitle("Hello");
Declare your menu field.
private Menu menu;
Following is onCreateOptionsMenu() method
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
try {
getMenuInflater().inflate(R.menu.menu_main,menu);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "onCreateOptionsMenu: error: "+e.getMessage());
}
return super.onCreateOptionsMenu(menu);
}
Following will be your name setter activity. Either through a button click or through conditional code
public void setMenuName(){
menu.findItem(R.id.menuItemId).setTitle(/*Set your desired menu title here*/);
}
This worked for me.
You can do it like this, and no need to dedicate variable:
Toolbar toolbar = findViewById(R.id.toolbar);
Menu menu = toolbar.getMenu();
MenuItem menuItem = menu.findItem(R.id.some_action);
menuItem.setTitle("New title");
Or a little simplified:
MenuItem menuItem = ((Toolbar)findViewById(R.id.toolbar)).getMenu().findItem(R.id.some_action);
menuItem.setTitle("New title");
It works only - after the menu created.
You can Change Menu Item text using below Code: -
fun showPopup(v: View) {
popup = PopupMenu(context, v)
val inflater = popup?.menuInflater
popup?.setOnMenuItemClickListener(this)
inflater?.inflate(R.menu.menu_main, popup?.menu)
val menu: Menu = popup!!.menu
val item = menu.findItem(R.id.name)
if (item.title.equals("Name")) {
item.title = "Safal Bhatia"
}
}
It seems to me that you want to change the contents of menu inside a local method, and this method is called at any time, whenever an event is occurred, or in the activity UI thread.
Why don't you take the instance of Menu in the global variable in onPrepareOptionsMenu when this is overridden and use in this method of yours. Be sure that this method is called whenever an event is occurred (like button click), or in the activity UI thread, handler or async-task post-execute.
You should know in advance the index of this menu item you want to change. After clearing the menu, you need to inflate the menu XML and update your item's name or icon.
For people that need the title set statically.
This can be done in the AndroidManifest.xml
<activity
android:name=".ActivityName"
android:label="Title Text" >
</activity>
I needed to change the menu icon for the fragment. I altered Charles’s answer to this question a bit for the fragment:
private Menu top_menu;
//...
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
//...
rootview = inflater.inflate(R.layout.first_content,null);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
this.top_menu = menu;
}
// my procedure
private void updateIconMenu() {
if(top_menu!= null) {
MenuItem nav_undo = top_menu.findItem(R.id.action_undo);
nav_undo.setIcon( R.drawable.back);
}
}
I hit this problem too. In my case I wanted to set the string to
reflect additional information using getString.
As stated above you need to find the correct menuItem in the menu and set it in the onPrepareOptionsMenu method. The solutions above didn't handle the case where the item was in a sub menu and for this you need to search the submenu for the item. I wrote a little Kotlin recursive function to allow me to this for multiple items. Code below...
override fun onPrepareOptionsMenu(menu: Menu) {
...
menu.menuSetText(R.id.add_new_card,
getString(R.string.add_card, currentDeck.deckName))
...
}
private fun Menu.getMenuItem(idx: Int, itemId: Int): MenuItem? {
Log.d(TAG, "getMenuItem: $idx of ${this.size()}")
if (idx >= size()) return null
val item = getItem(idx)
if (item.hasSubMenu()) {
val mi = item.subMenu.getMenuItem(0, itemId)
// mi non-null means we found item.
if (mi != null)
return mi
}
if (item != null && item.itemId == itemId)
return item
return getMenuItem(idx + 1, itemId)
}
fun Menu.menuSetText(itemId: Int, title: String) {
val menuItem = getMenuItem(0, itemId)
if (menuItem != null)
menuItem.title = title
else
Log.e(TAG,
"menuSetText to \"$title\": Failed to find ${
"itemId:0x%08x".format(itemId)}"
)
}

Categories

Resources