I have a Fragment A which shows a MenuItem Mi in the toolbar. On clicking Mi, I am showing a DialogFragment Df to the user to set a value V.
I am passing this value to fragment A by implementing a callback listener interface.
Once the value is set, I want to hide Mi from toolbar menu of fragment A.
I wanted to handle this inside onPause() and onResume() of fragment A, but showing a DialogFragment doesn't change the lifecycle of fragment. I was wondering how to approach this problem.
How can I achieve this thing?
I did this using a callback listener in my fragment A which listens to DialogFragment Df. Once the value V is set, this callback method in A is invoked. Inside this method, I am using V and setting a flag to indicate V has been set and then calling invalidateOptionsMenu().
Refer this for implementing your own callback.
How to send data from DialogFragment to a Fragment?
public void myCallback(int V){
//Use V according to my logic
vIsSet = Boolean.TRUE;
getActivity().invalidateOptionsMenu();
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
super.onCreateOptionsMenu(menu,inflater);
if(vIsSet) {
menu.removeItem(MENU_ITEM_ID);//item id of Mi
}
}
Related
In my case, I have activity with 2 containers for fragments.
One container show Fragment with list, second show detail information on the selected list item. Second container GONE by default.
In activity I have SearchView, which instance I get from fragment like that:
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
rxSearchView = (RxSearchView) searchMenuItem.getActionView();
rxSearchView.setSearchListener(taskListPresenter);
rxSearchView.setOnCloseListener(() -> {
taskListPresenter.clearSearch();
return false;
});
}
and, I use method setHasOptionsMenu(true); in OnCreateView();
Problem case:
1.User click on the searchView, and get filtered element:
2. User click on the element, calling next method:
`((MainActivity)getActivity()).showSecondaryFragment(TaskDetailFragment.newInstance();`
In MainActivity it's look like that:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.ltRightContainer, baseFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
After that, searchView automatically closed, like screen below.
How fix that moment? I don't want it automatically closing.
RxSearchView just wrapper with RxJava implementation, without ovverride methods.
Second fragment just call method setupMenu(R.menu.menu_my_task);
It makes searchView from first fragment close.
I am developing a application that should support on both phone and tablet.
In this application i am using fragments from android.
Now the flow of the application is like
MainActivity --> Fragment1 --> Fragment2
In this application , i want a menu item that should show only in Fragment2 along with activity's menu items.
So i have tried one solution like adding globle menu items in MainActivity and in Fragment2 replacing the whole MainActivity's menu with Fragment2 specific Menu.
setHasOptionsMenu(true);
inside onCreateView , and implement this method.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_f, menu);
super.onCreateOptionsMenu(menu,inflater);
}
Now its work exactly fine for phone layout , but when its come to tablet problem arise.
Here is my ScreenShots.
Fragment 1
Fragment 1 and Fragment 2 combination when pressing 9 in keybord(Tablet mode ).
And Finally when i pressed 9 again to come back to pHone view it shows me extra menu item.
I just marked a extra menu item in Image. So why this me coming and how can i resolve it ?
You need to hide the menu group like this in your fragment 1
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
it'll make a call to onPrepareOptionsMenu where you can hide your menu group added by fragment2
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.setGroupVisible(0, false);
}
Strange, neither Fragment nor v4.Fragment implemented the "onContextMenuClosed". Other events are there, like onCreateContextMenu and onContextItemSelected.
I need to clean up something when the context menu is dismissed, which can be activated by back button, tapping on the blank area on screen, or select one menu item in the context menu.
How do I monitor the dismissal of a context menu in a fragment then?
The menu close event in a fragment will also trigger its parent activity's "onContextMenuClosed". So I just override the event and pass it to a self implemented event handling function in the fragment.
// The parent activity.java:
#Override
public void onContextMenuClosed(Menu menu) {
super.onContextMenuClosed(menu);
childFragment.onContextMenuClosed(menu);
}
// The child fragment.java:
public void onContextMenuClosed(Menu menu) {
// Do you business here.
}
When an AsynctaskLoader is initiated from Activity's OnCreate(), it finishes its work and calls onLoaderFinished() before action bar menu is inflated, that is before onCreateOptionsMenu() is called.
I need to alter some action menu items depending on results of loader. What approach might resolve this ?
UPDATE:
This happens On orientation change. I'm Observing this sequence in debugger:
Application Start: onCreate() -> onCreateOptionsMenu() -> onLoadFinished()
Rotate to landscape: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()
Rotate back to portrait: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()
I ran into the same scenario when trying to call shareActionProvider.setShareIntent() in onLoadFinished() which was dependent on shareActionProvider being initalized in onCreateOptionsMenu().
My solution was to scope both my Intent and ShareActionProvider to the Fragment, and then within each method initialize the appropriate field and set the other if it had already been defined. That way it works no matter which is called first without invalidating the menu.
Here's basically what it looks like
public class myFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
...
private ShareActionProvider shareActionProvider;
private Intent shareIntent;
...
onCreateOptionsMenu()
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_my_fragment, menu);
MenuItem menuItem = menu.findItem(R.id.action_share);
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
//in the case where onLoadFinished is called first, simply set the share intent here.
if (null != shareIntent)
{
shareActionProvider.setShareIntent(shareIntent);
}
}
onLoadFinished()
#Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
... <get some data from cursor> ...
shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text)+data);
//shareActionProvider may be null due to onLoadFinished called before onCreateOptionsMenu
if (null != shareActionProvider)
{
shareActionProvider.setShareIntent(shareIntent);
}
I need to alter some action menu items depending on results of loader. What approach might resolve this ?
Your scenarios #2 and #3 should be perfectly fine for you, then. By the time onCreateOptionsMenu() is called, you have your Cursor (or whatever) from your Loader and can tailor what you do in onCreateOptionsMenu().
With regards to scenario #1, have onCreateOptionsMenu() do the most likely thing, and if you determine in onLoadFinished() that this is incorrect, call invalidateOptionsMenu() to force another call to onCreateOptionsMenu(), I suppose.
This particular approach avoids invalidating entire menu.
Define one boolean flag, and one MenuItem variable for each item you want to control based on outcomes of loader results:
Let's say you want to enable New action only if loader returns any success:
private boolean mEnableNew = false;
private MenuItem mItemNew;
Save the menu item to variable when menu is created, also, apply state:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.manage_menu, menu);
mItemNew = menu.findItem(R.id.itm__manage_menu__new);
mItemNew.setEnabled(mEnableNew);
return super.onCreateOptionsMenu(menu);
}
Finally, obtain new settings based on Loader's results, and enable disable menu item:
#Override
public void onLoadFinished(Loader<BI_Result> loader, Result result) {
//--If onCreateOptionsMenu is not yet executed,it will use this boolean value when it does
mEnableNew = result.isSuccess();
//--If onCreateOptionsMenu has executed, we apply state here
if (mItemNew != null) {
mItemNew.setEnabled(mEnableNew);
}
}
Can anyone give a quick example of how to change the contents of an Activity action bar based on something that takes place in a fragment? My intent:
Normal menu items -> Something in the fragment is moved -> menu items change to save / discard buttons.
My first impulse is to setup Broadcast Receivers in both the activity and the fragment to cross talk, but I am not sure if this is correct.
Fragments can change menu in actionbar. For that you have to add necessary flag in fragment's oncreate() using method setHasOptionsMenu(true);
When your fragment is loaded you will get call at onCreateOptionsMenu(Menu menu, MenuInflater inflater) just like in an activity. Then do necessary changes to your menu.
Save you menu as global in fragment, and whenever you want to make a change, apply on it.
The following works for me. I have a custom class that implements ListView.MultiChoiceModeListener inside a Fragment:
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
// Choose the correct Action Bar menu to display
int menu = myCondition == true ? R.menu.my_default_menu : R.menu.my_menu_2;
// Configure to use the desired menu
mode.getMenu().clear();
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(menu);
}
Given how you detect 'something in the fragment has moved', extending ListView.MultiChoiceModeListener may not work for you, but hopefully this illustrates how to change the menu. The key is to get access to a ActionMode instance.
I think you want to use a contextual action mode. On the drag event, you will start a new ActionMode which can replace the contents of the action bar with menu items specific to what you want to allow the user to do. Once the user chooses an action, you finish the action mode and the action bar returns to its previous state.
Not sure if an ActionBar instance would help with the menu you but would surely be useful.. Here's a way to get about it
Try this to get the ActionBar from the FragmentActivity using the onAttach(Activity activity) method in the Fragment.
First of all make a global object of your FragmentActivity in the Fragment like this
public class YourFragment extends Fragment {
private YourFragmentActivity context;
}
Override this in the YourFragment class
#Override
public void onAttach(Activity activity){
context = (YourFragmentActivity)activity;
super.onAttach(activity);
}
Then in the OnCreate method in the YourFragment do this
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
...
android.support.v7.ActionBar actionBar = context.getSupportActionBar();
...
}