How to implement onCreateOptionsMenu using AppCompat / Toolbar and Fragments - android

I have an Activity that extends ActionBarActivity and uses the new Toolbar, within the activity i populate my Context menu and when it shows Toolbar is correctly hidden because i use the following:
<item name="windowActionModeOverlay">true</item>
Then i create a Fragment dynamically, and the Fragment also has options using:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
...
}
Then since i have a list i add a contextmenu this way:
mListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
...
}
The problem is that the Fragment Context menu seems to behave differently, i need to use "android:windowActionModeOverlay" in order to hide the Toolbar automatically and also its ignoring the appcompat parameters like "app:showAsAction".
How can i correctly implement appcompact Context menu within a Fragment? I saw that in the sources of the Appcompat library there was an ActionBarFragment once but its not in the master branch or in the released library.
I am not using a drawer (yet).

Found the issue myself, instead of using:
mActionMode = getActivity().startActionMode(contextMenuListener);
I had to use:
mActionMode = getActivity().getSupportActionBar().startActionMode(contextMenuListener);
And off course implement support library ActionMode instead of the builtin one.

Related

How to differentiate action for SearchView submit based on Fragment?

I have multiple fragments in my app. I want to add search function to may app. When i add search view in toolbar, the listener is in MainActivity. The problem is when i submit the query, the action for every fragment is same. Can i differentiate the action for every fragment ?
How to do that?
First of all, I guess you have added the SearchView in Activity through menu.
If so then you can implement the menu inside each fragment instead of Activity. Then you can get Search functionality for each fragment.
To enable Option Menu for fragment you have to override onCreate like below:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
Then you have to inflate your menu in
onCreateOptionsMenu like below:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Add your menu entries here
super.onCreateOptionsMenu(menu, inflater);
}

How to remove a specific android SubMenu from toolbar?

I have a Fragment that, when added to a view, should have certain accompanying menu items in the toolbar. So when the Fragment is created, I add a submenu to the activity's toolbar menu.
The problem is that if I leave and return to the fragment, then I get multiple instances of that submenu. So what I'd like to do is remove a specific submenu from the toolbar menu. All I've been able to find is a way to remove all items from the menu, but I don't want that either as there's one other item I'd like to retain.
Does anybody have a strategy for removing a specific submenu?
The sub menu should not be created twice if you do correctly.
In your fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true); //this line is important
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Add your sub menu entries here
super.onCreateOptionsMenu(menu, inflater);
}

Toolbar.inflateMenu seems to do nothing

Im currently messing arround with the new AppCompat library bringing material design to older devices.
Setting a toolbar as actionbar works fine for me, but the toolbar seems to not do anything on calling inflateMenu(int resId). From the docs, i thought this is to replace getMenuInflater().inflate(int resId) called from onCreateOptionsMenu.
If I do the latter, the menu items are correctly inflated and added to the toolbar, but inflateMenu seems to to nothing.
What am I missing?
Activity Code:
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.inflateMenu(R.menu.main); // this does nothing at all
setSupportActionBar(toolbar);
}
// this works
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Thanks in advance!
If you are calling setSupportActionBar() you don't need to use toolbar.inflateMenu() because the Toolbar is acting as your ActionBar. All menu related callbacks are via the default ones. The only time you need to call toolbar.inflateMenu() is when you are using the Toolbar as a standalone widget. In this case you will also have to handle menu item click events via
toolbar.setOnMenuItemClickListener(
new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// Handle menu item click event
return true;
}
});

getSupportActionBar from inside of Fragment ActionBarCompat

I'm starting a new project that uses the AppCompat/ActionBarCompat in v7 support library. I'm trying to figure out how to use the getSupportActionBar from within a fragment. My activity that hosts the fragment extends ActionBarActivity, but I don't see a similar support class for Fragments.
From within my fragment
public class CrimeFragment extends Fragment {
//...
getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment
//...
}
The google page for using it (http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html) says there should be no changes for the v4 fragment. Do I need to cast all my getActivity() calls to an ActionBarActivity? That seems like poor design.
After Fragment.onActivityCreated(...) you'll have a valid activity accessible through getActivity().
You'll need to cast it to an ActionBarActivity then make the call to getSupportActionBar().
((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
You do need the cast. It's not poor design, it's backwards compatibility.
While this question has an accepted answer already, I must point out that it isn't totally correct: calling getSupportActionBar() from Fragment.onAttach() will cause a NullPointerException when the activity is rotated.
Short answer:
Use ((ActionBarActivity)getActivity()).getSupportActionBar() in onActivityCreated() (or any point afterwards in its lifecycle) instead of onAttach().
Long answer:
The reason is that if an ActionBarActivity is recreated after a rotation, it will restore all Fragments before actually creating the ActionBar object.
Source code for ActionBarActivity in the support-v7 library:
#Override
protected void onCreate(Bundle savedInstanceState) {
mImpl = ActionBarActivityDelegate.createDelegate(this);
super.onCreate(savedInstanceState);
mImpl.onCreate(savedInstanceState);
}
ActionBarActivityDelegate.createDelegate() creates the mImpl object depending on the Android version.
super.onCreate() is FragmentActivity.onCreate(), which restores any previous fragments after a rotation (FragmentManagerImpl.dispatchCreate(), &c).
mImpl.onCreate(savedInstanceState) is ActionBarActivityDelegate.onCreate(), which reads the mHasActionBar variable from the window style.
Before mHasActionBar is true, getSupportActionBar() will always return null.
Source for ActionBarActivityDelegate.getSupportActionBar():
final ActionBar getSupportActionBar() {
// The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
// could change after onCreate
if (mHasActionBar || mOverlayActionBar) {
if (mActionBar == null) {
... creates the action bar ...
}
} else {
// If we're not set to have a Action Bar, null it just in case it's been set
mActionBar = null;
}
return mActionBar;
}
If someone uses com.android.support:appcompat-v7: and AppCompatActivity as activity then this will work
((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
For those using kotlin,
(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
As an updated answer for Pierre-Antoine LaFayette's answer
ActionBarActivity is deprecated; use AppCompatActivity instead
((AppCompatActivity)getActivity()).getSupportActionBar();
in your fragment.xml add Toolbar Tag from support library
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
Now how we can control it from MyFragment class? let's see
inside onCreateView function add the following
mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
//add this line if you want to provide Up Navigation but don't forget to to
//identify parent activity in manifest file
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
and if you want to add items to the toolbar within MyFragment
you must add this line inside onCreateView function
setHasOptionsMenu(true);
this line is important, if you forget it, android will not populate your menu Items.
assume we identify them in menu/fragment_menu.xml
after that override the following functions
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_1:
// do stuff
return true;
case R.id.action_2:
// do more stuff
return true;
}
return false;
}
hope this helps
As an addendum to GzDev's answer, if you already have the string, you can use kotlin's auto-setter:
(activity as AppCompatActivity).supportActionBar?.subtitle = my_string
And you can turn it off by simply using an empty string.
Note that this works for both the title and the subtitle.

Android: Change ActionBar Menu Items from Fragment

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();
...
}

Categories

Resources