Retrieve action layout from ActionBar, inside fragment - android

How do I retrieve a action layout for an item inside the ActionBar, from
a Fragment. I have tried to access the layout directly via getActivity().findViewById,
and via getActivity().findViewById(MenuItem).findViewById(ActionLayout).
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
MenuItem commentMenuItem = (MenuItem) getActivity().findViewById(R.id.menu_item_comment);
View actionView = commentMenuItem.getActionView();
TextView commentTextView = (TextView)
actionView.findViewById(R.id.action_bar_comment_item_textview);
commentTextView.setText(article.getArticle_comment_count());
}

Call getActionView() on the MenuItem corresponding to that action layout. You get the MenuItem from findItem() on the Menu, which you get in onCreateOptionsMenu().

Related

OnCreateOptionsMenu is not called during fragment transaction

I have a fragment that contains a search menu in the toolbar. when user first time click on navigation item, Fragment is added in activity which uses add method of FragmentManager and then it will be show, hide or remove from fragment container according to the logic.
My problem is when the first time I click on navigation item search menu is displayed in the toolbar but afterwards when I come back to this fragment, sometimes there will be blank toolbar without search menu. How can I solve this?
Here is the main part code of fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_search, container, false);
searchFragmentInstance = this;
filterManager = new FilterManager();
//set toolbar
Toolbar toolbar = view.findViewById(R.id.toolbar_search);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
//other code...
return view;
}
Display search menu in toolbar using this:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onPrepareOptionsMenu(menu);
inflater.inflate(R.menu.search, menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchManager searchManager = (SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) item.getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
searchView.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
//other code...
}
I solved this problem by using adding this code:
//this method is called when the hidden state of the fragment is changed
//so when fragment is beign displayed using show method of fragment transaction
//this will be called
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if(!hidden){
//when fragment is not hidden anymore
//convert the toolbar into actionbar
Toolbar toolbar=(Toolbar)(((AppCompatActivity)getActivity()).findViewById(R.id.toolbar_search));
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
}
}

How to change Menu Item icon from fragment?

How can I access my Menu from my fragment and then change the icon of one of the menu items there?
What I am doing is querying my local DB to see if a certain entry exists when the fragment is shown. If it does display a solid icon, if not, display an outlined icon.
In your fragments onCreate() method you can use setHasOptionsMenu(true) to allow your fragment to handle different menu items than it's root Activity.
So you could do something like this in your fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
And then, you can override any of the menu life-cycle methods in your fragment:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_fragment, menu);
// You can look up you menu item here and store it in a global variable by
// 'mMenuItem = menu.findItem(R.id.my_menu_item);'
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem menuItem = menu.findItem(R.id.menu_item_to_change_icon_for); // You can change the state of the menu item here if you call getActivity().supportInvalidateOptionsMenu(); somewhere in your code
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
// Handle actions based on the id field.
}
I found a simpler way of doing it than in the provided answer:
Toolbar toolbar = requireActivity().findViewById(R.id.toolbar);
Menu menu = toolbar.getMenu();
MenuItem item = menu.findItem(R.id.item_settings);
item.setIcon(R.drawable.ic_settings);
Access the menu from the toolbar.

Show navigation drawer menu item only when a Fragment is shown

I am trying to show a button in the actionbar when a Fragment is shown and to hide the button when the other Fragment are shown.
I Override the onCreateOptionsMenu method:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
MenuItem item= menu.findItem(R.id.action_example);
item.setVisible(true);
super.onCreateOptionsMenu(menu,inflater);
}
And use setHasOptionMenu(true):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
I have done a test and I noticed that initially the button doesn't appear in the other Fragment , but after I open the Fragment in which I put this code above, the button is shown also in the other Fragment.
What you are missing is removing the optionsMenu in the onDestroy of the fragment. The behaviour you describe is logical with your code: when the Fragment is created you also create the options menu. It will not automatically be destroyed when the Fragment is destroyed.

Access Fragment's Menu within a FragmentStatePagerAdapter

I use a FragmentStatePagerAdapter to display fragments inside a ViewPager.
These fragments display 2 additional icons on top of the ones coming from the parent Activity.
These 2 icons are showed/hidden according to fragment displayed, so I tried to keep the Menu inflated in memory in order to modify it dynamically.
On my ViewPager, 3 fragments are always loaded, only the middle one is displayed.
The problem is the following: it seems that onCreateOptionsMenu and onPrepareOptionsMenu are called only for the first Fragment created, because of this, I get null pointers when I try to get the menu on the other fragments. Please see the code below:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//Get the 2 icons for the rates
inflater.inflate(R.menu.rate_fragment, menu);
//Get activity's icons
super.onCreateOptionsMenu(menu, inflater);
mMenu = menu;
}
Here are the functions I use to hide/show the menu items:
private void hideOption(int id){
MenuItem item = mMenu.findItem(id);
if(item != null){
item.setVisible(false);
}
}
private void showOption(int id){
MenuItem item = mMenu.findItem(id);
if(item != null){
item.setVisible(true);
}
}
But these functions fail as soon as the system tries to load the second Fragment.
My guess is that the menu is only created once for the FragmentStatePagerAdapter, but then how can I modify dynamically the menu? Do I have to modify it using the Activity?
Thanks!

Android : Get view Reference to a Menu Item

I plan to use quick actions UI pattern in my application. Android Quick Actions UI Pattern . The quick action window needs a pivot view to stick to.
quickAction.show(View pivotView);
I intend to use quick action for the menu Item, I can get access to the item that is clicked.
But the problem is i need to reference a view from the menu item so that i can pass it to the quick action.
How can i get reference to a view in the menuItem that is selected.
You can achieve this by providing your menu item with an actionViewClass property in xml and then you will be able to get the pivot view u wanted. The code would be something like this
<item
android:id="#+id/menu_find"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.ImageButton"
/>
In your OnCreateOptionsMenu do this
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_search, menu);
locButton = (ImageButton) menu.findItem(R.id.menu_find).getActionView();
locButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
createPopup();
mQuickAction.show(v);
}
});
return true;
}
Old question, but I ran into some issues with the actionViewClass attribute. For anyone who runs into this later...
Calling findViewById(R.id.mnu_item) in onOptionsItemSelected will return a View anchor.
QuickActions on the MenuItems aren't good design, but I found that they are the simplest way to implement submenus with custom backgrounds.
Inorder to get reference Views of menu items we need to do this,
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.section, menu);
new Handler().post(new Runnable() {
#Override
public void run() {
final View menuItemView = findViewById(R.id.action_preview);
// SOME OF YOUR TASK AFTER GETTING VIEW REFERENCE
}
});
return true;
}
An update for anyone that want to find the menu view item for other reasons (like I wanted).
If you have access to and use AppCompat's Toolbar there is a way. It's not the most efficient way, but it's the easiest way I've found to access the menu item's view.
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
// Find Menu
for (int toolbarChildIndex = 0; toolbarChildIndex < toolbar.getChildCount(); toolbarChildIndex++) {
View view = toolbar.getChildAt(toolbarChildIndex);
// Found Menu
if (view instanceof ActionMenuView) {
ActionMenuView menuView = (ActionMenuView) view;
// All menu items
for (int menuChildIndex = 0; menuChildIndex < menuView.getChildCount(); menuChildIndex++) {
ActionMenuItemView itemView = (ActionMenuItemView) menuView.getChildAt(menuChildIndex);
// Do something to itemView...
}
}
}
}
Universal code which also works on Android 10
/**
* pass toolbar and menu item id, i.e. R.id.menu_refresh
*/
#Nullable
#Throws(
IllegalAccessException::class,
NoSuchFieldException::class
)
fun getMenuItemView(toolbar: Toolbar?, #IdRes menuItemId: Int): View? {
val mMenuView: Field = Toolbar::class.java.getDeclaredField("mMenuView")
mMenuView.setAccessible(true)
val menuView: Any? = mMenuView.get(toolbar)
(menuView as ViewGroup).children.forEach {
if(it.id == menuItemId) {
return it
}
}
return null
}
in the main activity class, best to override the onOptionsItemSelected(...) method; should be something as below:
public boolean onOptionsItemSelected(MenuItem item) {
// the id is of type int
int someId = item.getItemId();
// can use an if() or switch() statement to check if id is selected
//a Toast message can be used to show item is selected
}
Kotlin!!
override fun onCreateOptionsMenu(Menu menu): Boolean {
/*Adding menu items to action bar*/
menuInflater.inflate(R.menu.main, menu)
/*Getting menu item*/
val locButton: MenuItem = menu.findItem(R.id.menu_find)
/*Creating click listener*/
locButton.setOnMenuItemClickListener{
/*TODO: Handle it*/
true
}
return true;
}

Categories

Resources