How can I hide action bar for certain fragment?
I have searched for the answer at stackoverflow, but I have only found a solution, which involves disabling action bar for main activity in android manifest. Since I need to disable action bar for one fragment, this is not an option.
Any ideas? Thanks.
EDIT: min API level is 7, sherlock is not being used
If you are using AppCompatActivity (you should) then this is the solution that worked for me:
((AppCompatActivity) getActivity()).getSupportActionBar().hide();
You can add this in onCreate(). The support fragment's getActivity() returns a FragmentActivity, and this does not contain the getSupportActionBar() method. Using just getActionBar() gives null-pointer exception if you have AppCompatActivity.
Put this code in fragment in which you want to hide toolbar...
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
As it was already mentioned, actionbar may be hidden by (requireActivity() as AppCompatActivity).supportActionBar?.hide() call.
If you want to show it in some of your fragments and to hide it in some other fragments, it may be convenient to apply default (for your case) visibility in onViewCreated of your Base fragment:
abstract class BaseFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(requireActivity() as AppCompatActivity).supportActionBar?.show()
}
}
and to hide it in particular fragments:
class HiddenActionBarFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(requireActivity() as AppCompatActivity).supportActionBar?.hide()
}
}
This solution is more flexible than using onStart - onStop for visibility change because during the transition onStart of a different fragment will be called earlier than onStop of the current fragment. So the next fragment won't be able to 'override' actionar visibility applied in onStop of the current fragment.
getActionBar().hide() or getSupportActionBar().hide() (if using ActionBarCompat v7 lib).
Regards
Hide actionBar using this in the required fragment.
getActivity().getSupportActionBar().hide();
And Show actionBar with this in your next fragment.
getActivity().getActionBar().show();
Put getSupportActionBar().hide() before setContentView in the Activity that holds the fragments.
Also add this: ((AppCompatActivity) getActivity()).getSupportActionBar().hide() in the fragments before inflating layout. This works if you are using this ActionBarActivity.It also removes my lags in hiding action bar
You can simply put this into your Fragment Class createView method:-
View layout = inflater.inflate(R.layout.player_fragment, container, false);
((AppCompatActivity) getActivity()).getSupportActionBar().hide();
Paste the code in the fragments before inflating the layout to SHOW Action Bar `
//Kotlin statement
(activity as AppCompatActivity?)!!.supportActionBar!!.show()
Paste the code in the fragments before inflating the layout to Hide Action Bar `
//Kotlin statement
(activity as AppCompatActivity?)!!.supportActionBar!!.hide()
This works fine for me.
Have you tried getActivity().getSupportActionBar().hide() in the onCreate() of the fragment you wish the ActionBar to be hidden in?
I am assuming you are not using ActionBarSherlock.
If you're like me and have one main Activity and several Fragments, you can add a listener to your NavController in the main Activity's onCreate() method.
For instance, I only wanted it hidden in my Login Fragment, so I used this (Kotlin):
navController.addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.loginFragment) {
supportActionBar?.hide()
} else {
supportActionBar?.show()
}
}
This avoids having to add the call to show() in all the Fragments in which you do want the ActionBar.
This solution is for complex non-AppCompat applications that use native ToolBar when running Lollipop onwards and native ActionBar otherwise.
It assumes you want to hide the ActionBar whenever Fragments are visible.
Inside onCreate() in each of your Activities:
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
{
#Override
public void onBackStackChanged() {
U.ABkk(this, getFragmentManager().getBackStackEntryCount());
}
}
);
OR (much better) inside a 'singleton' class that implements Application.ActivityLifecycleCallbacks
#Override
public void onActivityCreated(final Activity A, Bundle savedInstanceState) {
A.getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
U.ABkk(A, A.getFragmentManager().getBackStackEntryCount());
}
});
}
Inside the utility class:
/** Show/hide ActionBar for KitKat devices */
public static void ABkk(Activity A, int count) {
if (lollipop()) return; // No problem when using Toolbar
ActionBar ab = A.getActionBar();
if (ab==null) return;
if (count==1) { ab.hide(); }
if (count==0) { ab.show(); }
}
/** Return true if API 21 or greater */
private static boolean lollipop() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
Using onActivityCreated() is a solution that requires no changes to your Fragments or Activities!
Related
At current implementation of my app I am using the Navigation component. In my main content I have a floating action button for all. And at the same time I have 7 different fragment which are automatically handled by the navigation controller when transition is needed.
mAppBarConfiguration =
new AppBarConfiguration.Builder( navigationDrawerFragmentIds ).setDrawerLayout( drawer ).build();
NavController navController = Navigation.findNavController( this, R.id.nav_host_fragment );
Till today I used the setUserVisibleHint(boolean isVisibleToUser) method to override different behaviour(on click listener) for my single fab in the each different fragment.
Like below
// FIXME: 2.11.2019 Fix deprecated methods.
#Override public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint( isVisibleToUser );
if (isVisibleToUser && isResumed()) {
//Only manually call onResume if fragment is already visible
//Otherwise allow natural fragment lifecycle to call onResume
onResume();
} else {
// current fragment not visible
floatingActionButton.setOnClickListener( null );
}
}
#Override public void onResume() {
super.onResume();
// FIXME: 2.11.2019 Fix deprecated methods.
if (!getUserVisibleHint()) {
return;
}
// Set listener for float action button which has been defined in main activity.
// Here we will override the listener which can be work for our current fragment.
floatingActionButton = getActivity().findViewById( R.id.fab );
floatingActionButton.setOnClickListener( new View.OnClickListener() {
#Override public void onClick(View view) {
// do some stuff here.
}
} );
}
Since setUserVisibleHint is deprecated anymore, I wanted to replace new behaviour instead this method like suggested in the release note.
Max Lifecycle: You can now set a max Lifecycle state for a Fragment by
calling setMaxLifecycle() on a FragmentTransaction. This replaces the
now deprecated setUserVisibleHint(). FragmentPagerAdapter and
FragmentStatePagerAdapter have a new constructor that allows you to
switch to the new behavior.
And also navigation controller has default FragmentNavigator as I understood but I could not understand is this help to me to set the fragments life cycle or behaviour like this post. If I can set the behaviour like mentioned post then I can basically use the onResume and onStart (I assume that will work like this because when I select the BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT then the next fragment will not be initiated. only onCreateView called I assume.)
As I explained above that I am using navigation component to handle transition between my fragments. That is why I do not have any special view pager. But I can still get the information via below code the current destination and callback will handle whenever transition is occured between fragments.
navController.addOnDestinationChangedListener( new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination,
#Nullable Bundle arguments) {
Log.i( TAG, "onDestinationChanged: " + destination.getLabel());
}
} );
Then on my main activity I can set the different behaviour for my fab for each fragment. Up to now this is okey for me. But I wanted to learn is there any way that I can set the max life cycle of the fragment while I am using the Navigation component ?
Thanks in advance.
I implemented the new NavigationView (from the support library) and a couple of Fragments, I then overrided the onBackPressed function and added this:
getFragmentManager().popBackStack();
which returns me to the previous fragment.
So what I need is this: how I can change the navigationview's current selected item to the Fragment it is popping back to?
Finally i got it,
Firstly, i made the instance of the navigation global and public.
public NavigationView navigationview;
I then added in the onCreate and onResume of my fragment:
NavigationView navigationView = ((MainActivity) getActivity()).navigationview;
navigationView.getMenu().getItem(index).setChecked(true);
and the onResume:
navigationView.getMenu().getItem(index).setChecked(true);
This solved my problem, Hope this helps someone.
I know this is a little late but I found a solution that is maybe a little faster to code for Activities that have a large amount of fragments.
(In your activity)
Implement FragmentManager.OnBackStackChangedListener
In onCreate() add fragmentManager.addOnBackStackChangedListener(this);
Add Method from interface...
#Override
public void onBackStackChanged() {
MainActivityFragment f = (MainActivityFragment) fragmentManager.findFragmentById(R.id.fragment_container);
//Log.v(TAG, "OnBackStackChanged to fragment with index: " + f.getMenuIndex());
navigationView.getMenu().getItem(f.getMenuIndex()).setChecked(true);
}
(Create an interface in a separate file, name it MainActivityFragment) or whatever your activity is named.
public interface MainActivityFragment {
int getMenuIndex();
}
(All fragments that are used in that Activity)
Implement MainActivityFragment
Add Method from interface...
#Override
public int getMenuIndex() {
return 2;
}
It may seem like some extra work but in the long run it makes it pretty easy as all you have to do for new Fragments is implement the Activity's Interface and return the index of it's menu item.
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.
I have a problem with use ActionBarSherlock, fragment, and indeterminateprogressBar.
I Have a sherlockFragmentActivity with my fragmentpageradapter and pagertabstrip.
I want to display the indeterminate progress Bar when I press button in a fragment.
I declared the
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
in the SherlockFragment Activity, but when, in the fragment, call
getSherlockActivity.getParent().setProgressBarIndeterminateVisibility(true)
i get an error.
If call in the sherlockFragmentActivity, the bar, work.
Sorry for my bad English.
Thanks
I solved the issue,
I create method in FragmentActivity
public void progressOn() {
setSupportProgressBarIndeterminateVisibility(true);
}
public void progressOff() {
setSupportProgressBarIndeterminateVisibility(false);
}
and and I have called them in the fragment with
((MainActivity) getSherlockActivity()).progressOn();
and
((MainActivity) getSherlockActivity()).progressOff();
thanks anyway
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();
...
}