Switch fragments without replacing Android - android

I have three fragments and a Navigation drawer in my app viz, HomeFragment,DetailFragment and CountryFragment. Now when Iam in HomeFragment(Default fragment), I check a condition, if it returns false, I want to redirect to the CountryFragment without replacing the fragment.
Initially, in the host activity Iam doing something like this:-
HomeActivity.
private Android.Support.V4.App.Fragment mCurrentFragment = new SupportFragment();
private Stack<Android.Support.V4.App.Fragment> mStackFragments;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.homelayout);
Android.Support.V4.App.FragmentTransaction tx = SupportFragmentManager.BeginTransaction();
tx.Add(Resource.Id.main, homeFragment);
tx.Add(Resource.Id.main, countryFragment);
tx.Hide(countryFragment);
tx.Add(Resource.Id.main, detailFragment);
tx.Hide(detailFragment);
CurrentFragment = homeFragment;
tx.Commit();
}
void MenuListView_ItemClick (object sender, AdapterView.ItemClickEventArgs e)
{
Android.Support.V4.App.Fragment fragment = null;
switch (e.Id)
{
case 0:
ShowFragment(homeFragment);
break;
case 1:
ShowFragment(countryFragment);
break;
case 2:
ShowFragment(detailFragment);
break;
}
}
public void ShowFragment(SupportFragment fragment)
{
if (fragment.IsVisible)
{
return;
}
var trans = SupportFragmentManager.BeginTransaction();
fragment.View.BringToFront();
mCurrentFragment.View.BringToFront();
trans.Hide(mCurrentFragment);
trans.Show(fragment);
trans.AddToBackStack(null);
mStackFragments.Push(mCurrentFragment);
trans.Commit();
mCurrentFragment = fragment;
}
Next in HomeFragment Iam doing something like :-
public void BtnCompleteSubmit_Click(object sender, EventArgs e)
{
dlgAlert.Dismiss();
CountryFragment countryFrag = new CountryFragment ();
// Create new fragment and transaction
var myActivity = (HomeActivity)this.Activity;
myActivity.ShowFragment(countryFrag );
}
This does go to the ShowFragment() of the HomeActivity, but the view for the fragment is null even thought the View was created initially while the NavigationDrawer was created. How do I solve this? any help is appreciated.

What you can do is create all fragment with a String Tag name associated.
Then add it your fragment transcation using fragment manager.
After if you want to shift between the fragments, then write an if else statement and find the fragment by tag method.
if (mFragManager.findFragmentByTag("FRAG_HOME") != null)
showFragment(mFragManager.findFragmentByTag("FRAG_HOME"));
else
showFragment(new homeFragment(), "FRAG_HOME");
In you show Fragment method:
public void ShowFragment(Fragment fragment, String tag)
{
mFragTransaction= mFragManager.BeginTransaction();
if (fragment.isAdded())
mFragTransaction.show(fragment);
else
mFragTransaction.add(ResId, fragment, tag).setBreadCrumbShortTitle(tag);
mFragTransaction.addToBackStack(tag);
mFragTransaction.commit();
}

Related

How to show a fragment inside a specific Fragment Container in Android

Whenever I want to change fragment depending on the item selected I use:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
But now I want to make it so that I can simply show the different fragments instead of creating new ones every time I re-select them, so I found .show instead of .replace, but the problem with .show is that I can not declare where I want that fragment to be shown... or perhaps I'm maybe doing it wrong:
getSupportFragmentManager().beginTransaction().show(fragment).commit();
If you want to use show/hide method, you need to add a fragment before this, as you can see the container is available here. I just showed an example of how to show or hide one fragment. If you have a lot of fragments you can for example save the list and then hide others in the loop. If interested, I added from below.
public void showFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.add(R.id.container, fragment);
}
fragmentTransaction.commit();
}
public void hideFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) {
fragmentTransaction.hide(fragment);
}
fragmentTransaction.commit();
}
If there are many fragments
public class MainActivity extends AppCompatActivity {
HashMap<String, Fragment> fragments = new HashMap<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/*
* call this method when you want to add a new fragment
* Example: addFragment(new A(), "TAG_A")
* */
public void addFragment(Fragment fragment, String fragmentTag) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
/*Before add fragment we hide others*/
for (String fTag : fragments.keySet()) {
Fragment fragmentInStack = fragments.get(fTag);
if (fragmentInStack.isAdded() && !fragmentInStack.isHidden()) {
fragmentTransaction.hide(fragmentInStack);
}
}
if (!fragment.isAdded()) {
fragments.put(fragmentTag, fragment);
fragmentTransaction.add(R.id.container, fragment, fragmentTag);
} else {
fragmentTransaction.show(fragment);
}
fragmentTransaction.commit();
}
/*
* call this method when you want to show fragment which are on the list
* Example: We have current fragment C and you want to show fragment A, that to call showFragment("TAG_A")
* */
public void showFragment(String fragmentTag) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
/*hide others fragment besides the one we need to show*/
for (String fTag : fragments.keySet()) {
Fragment fragmentInStack = fragments.get(fTag);
if (!fTag.equals(fragmentTag) && fragmentInStack.isAdded()) {
fragmentTransaction.hide(fragmentInStack);
}
}
Fragment fragment = fragments.get(fragmentTag);
if (fragment != null && fragment.isAdded()) {
fragmentTransaction.show(fragment);
}
fragmentTransaction.commit();
}
}

How to use findFragmentByTag inside nested Fragments with TabLayout

Here I've nested TabLayouts inside a Fragment which is working so fine for me but not I just want to know how I can switch Tabs of TabLayouts when MainTabFragment is not in front of app. I searched for a long time and I found it's possible with findFragmentByTag but I don't know how I should use it in my case where I have to switch Tabs too. For more I'm writing my code too.
In MainActivity I'm switching Tabs when MainTabFragment is in front and calling that Fragment when it's not in front like:
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.frame_container);
if (currentFragment instanceof MainTabFragment) {
//Main Fragment
MainTabFragment.pager.setCurrentItem(1);
// Child Fragment of Main Fragment
TopAdvisoryPagerFragment.pager.setCurrentItem(2);
} else {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
fragment = new MainTabFragment();
changeFragments();
}
}, 150);
}
mDrawerLayout.closeDrawer(mDrawerList);
public void changeFragments() {
if (fragment != null) {
mPendingRunnable = new Runnable() {
#Override
public void run() {
FragmentManager fragmentManager = getSupportFragmentManager();
final Bundle bundle = new Bundle();
bundle.putInt("pos_next", second_position);
bundle.putInt("pos_end", third_position);
fragment.setArguments(bundle);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment, "TOP").addToBackStack(null).commit();
}
};
if (mDrawerLayout.isDrawerOpen(mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
}
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
If I'm not wrong,
fragmentManager.beginTransaction().replace(com.cws.advisorymandi.R.id.frame_container, fragment, "TOP");
Tag refer to "TOP", if you have different fragment using the same tag, it would be difficult to switch. You could possibly change the code to
fragmentManager.beginTransaction().replace(com.cws.advisorymandi.R.id.frame_container, fragment, fragment.getClass().getSimpleName());
In this scenario, the tag will be your fragment class name.

Navigation Drawer Fragments

So I have my navigation drawer with 5 different options. They all open a new fragment that I have created. The first one is Home, and I am trying to find a way to bring it back to the first screen that shows up under the navigation drawer. It has the id of "container", in the main_activity.xml. I do not want to use and intent to call the entire class again to load up. Also I do not want to be able to use the back button from another intent. I am confused on how to make this happen.
#Override
public void onNavigationDrawerItemSelected(int position) {
FragmentHowItWorks fragmentHow;
FragmentSettings fragmentSettings;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
switch(position){
case 0:
// should I call the layout?
// this is the "Home" option
break;
case 1:
fragmentHow = new FragmentHowItWorks();
transaction.replace(R.id.container, fragmentHow);
transaction.addToBackStack(null);
transaction.commit();
break;
case 2:
fragmentSettings = new FragmentSettings();
transaction.replace(R.id.container, fragmentSettings);
transaction.addToBackStack(null);
transaction.commit();
break
case 3:
fragment = new FragmentHowItWorks();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
break;
case 4:
fragment = new FragmentHowItWorks();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
break;
}
}
Use methods add,hide and show,
Step1 Prepare all your fragments
Fragment fragment1 = new FragmentOne();
Fragment fragment2 = new FragmentTwo();
Fragment fragment3 = new FragmentThree();
Fragment mCurrentFragment = null;
Step2 Show/hide your fragments
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
switch (position) {
case 1:
fragment = fragment1;
break;
case 2:
fragment = fragment2;
break;
case 3:
fragment = fragment3;
break;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(mCurrentFragment == null) {
ft.add(R.id.container, fragment).commit();
mCurrentFragment = fragment;
} else if(fragment.isAdded()) {
ft.hide(mCurrentFragment).show(fragment).commit();
} else {
ft.hide(mCurrentFragment).add(R.id.container, fragment).commit();
}
mCurrentFragment = fragment;
}
You can do this ,
You can get the name of current fragment which is in the container . This will return name including the package + fragment name
String name = getFragmentManager().findFragmentById(container id ).getClass().getName();
When you click on the home index of drawer, check weather the current name id equal to the home.
If it is home, you don't need to perform any action.
I know that this was asked and answered long time ago but, I would like to show my approach on this problem, maybe it will help anyone else:
I added a Fragment Name over each Fragment that I use like:
public class MainFragment extends BaseFragment {
public static final String FRAGMENT_TAG = "main";
// ... all your fragment
}
And on the Drawer Layout:
public void methodThatSetsTheUi() {
mDrawerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
getFragmentManager().findFragmentByTag("main");
String tag = getFragmentTag(position);
replaceFragment(getOrCreateFragment(tag), tag);
mDrawerLayout.closeDrawer(mDrawerView);
}
});
}
#NonNull
private String getFragmentTag(int position) {
String tag;
switch (position) {
case MAIN_FRAGMENT_DRAWER_POSITION:
tag = MainFragment.FRAGMENT_TAG;
break;
case FAVORITE_FRAGMENT_DRAWER_POSITION:
tag = FavoriteFragment.FRAGMENT_TAG;
break;
default:
throw new AssertionError("That selection is wrong");
}
return tag;
}
private BaseFragment getOrCreateFragment(String fragmentName) {
BaseFragment fragment = (BaseFragment) getFragmentManager().findFragmentByTag(fragmentName);
if(fragment == null) {
fragment = FragmentFactory.createFragment(fragmentName);
}
return fragment;
}
and well, the FragmentFactory is just a simple Factory:
public final class FragmentFactory {
public static BaseFragment createFragment(String fragmentName) {
switch(fragmentName) {
case MainFragment.FRAGMENT_TAG:
return MainFragment.newInstance();
case FavoriteFragment.FRAGMENT_TAG:
return FavoriteFragment.newInstance();
// ... all fragments here.
default:
return null;
}
}
Hope to help someone.

Android using both getFragmentManager and getSupportFragmentManager causes overlapping

I have something like this inside my activity:
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 2: {
SwipeRefreshListFragment swipeFragment = new Fragment_List_Of_Assessments();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, swipeFragment)
.commit();
break;
}
case 3: {
fragment = new Fragment_Report();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
case 4: {
fragment = new Fragment_Settings();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment)
.commit();
break;
}
default:
break;
}
}
The program automatically loads case1, but when case2 is selected, getSupportFragmentManager loads the Fragment on top of case1. I guess there are some problem with using both supportFragmentManager and FragmentManager. They seem to have their own stack. The problem is that I cannot use only either one of them because the SwipeToRefresh Android example uses ListView which needs support.v4.Fragment which needs the old FragmentManager. So how is it possible to integrate both FragmentManagers together?
I have accomplished something like this when using PreferenceFragment (not supported by support library version). In order to achieve this I kept inside my Activity a pair of boolean (isLastFragmentSupportType and lastFragmentShowed) and also a String (lastFragmentTag).
At the beginning your Activity will have both of them to false. And when you add a new Fragment you use these 2 boolean to know if you need to clean the other FragmentManager or not. I'll use your code as an example:
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
switch (position+1) {
case 1: {
if(isLastFragmentSupportType && lastFragmentShowed)
{//As your last fragment was a support type you need to clear your supportFragmentManager
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
fragment = new Fragment_Login();
FragmentManager frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.container, fragment,TAG1)
.commit();
lastFragmentTag = TAG1;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
break;
}
//And so on with the others
You need to check what type (support or not) of fragment you are going to use, and check these variables to see if the last fragment was of a different type. If that is the case clean the other fragmentmanager to "clear" the screen so they wont overlap.
Also use TAGS to identify and retrieve your current fragments so you do not need to have Fragment variables over your code.
Finally use onSavedInstanceState so as to keep these values in case you need them.
Hope it helps :)
This answer is inspired from answer by zozelfelfo.
Use these two methods to replace fragments instead of getFragmentManager.beginTransaction.replace...
private void replaceFragment(Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && isLastFragmentSupportType) {
android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
}
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = false;
}
private void replaceFragment(android.support.v4.app.Fragment fragment, String fragmentTag) {
if(lastFragmentShowed && !isLastFragmentSupportType) {
Fragment fr = getFragmentManager().findFragmentByTag(lastFragmentTag);
getFragmentManager().beginTransaction().remove(fr).commit();
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragmentTag)
.commit();
lastFragmentTag = fragmentTag;
lastFragmentShowed = true;
isLastFragmentSupportType = true;
}
I'm using BottomNavigationView as Tab Bar and switching fragments as tabs. All but one fragment are Support Fragments (and last one is PreferenceFragment). I'm using "hide-add-show" rather than "remove-replace". So, status of fragments in other tabs can be preserved.
Original function to switch:
private Fragment lastFragment = null;
private void switchFragment(Fragment fragment) {
if (lastFragment != fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (null != lastFragment) {
transaction.hide(lastFragment);
}
lastFragment = fragment;
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
}
I don't use tag nor boolean, just want to keep a reference to last fragment object. So, when switching, just call switchFragment() with instance of any fragment:
private Object lastFragment = null;
private void switchFragment(Object fragment) {
if (lastFragment != fragment) {
if (null != lastFragment) {
if (lastFragment instanceof android.support.v4.app.Fragment) {
hideFragment((android.support.v4.app.Fragment) lastFragment);
} else if (lastFragment instanceof android.app.Fragment) {
hideFragment((android.app.Fragment) lastFragment);
}
}
lastFragment = fragment;
if (fragment instanceof android.support.v4.app.Fragment) {
showFragment((android.support.v4.app.Fragment) fragment);
} else if (fragment instanceof android.app.Fragment) {
showFragment((android.app.Fragment) fragment);
}
}
}
So, this function still do the same things but switch between Support Fragment and Native Fragment by checking the target class. Helper functions:
// Support Version:
private void hideFragment(android.support.v4.app.Fragment fragment) {
getSupportFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.support.v4.app.Fragment fragment) {
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
// Native Version:
private void hideFragment(android.app.Fragment fragment) {
getFragmentManager().beginTransaction().hide(fragment).commit();
}
private void showFragment(android.app.Fragment fragment) {
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_container, fragment);
}
transaction.show(fragment).commitAllowingStateLoss();
}
To avoid confusion, I removed the import so classes require full names.

Backstack android fragment navigation

This is how I used navigation drawer to display Fragments:
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new Fragment0();
break;
case 1:
fragment = new Fragment1();
break;
case 2:
fragment = new Fragment2();
break;
case 3:
fragment = new Fragment3();
break;
case 4:
fragment = new Fragment4();
break;
case 5:
fragment = new Fragment5();
}
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(drawerll);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Suppose if the user navigates to Fragment 2-> Fragment 5-> Fragment3.
If the user clicks the back button I need to have the descending order and on each fragment I am displaying the name of the Fragment when he goes to that particular fragment ie:
Fragment 3-> Fragment 5-> Fragment2.
This is what I have tried:
First Method:
FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStackImmediate();
}
Second Method:
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
I'm unable to get this working**(ie.. I'm unable to move it back to the fragment where I have come from**) and unable to display the name of the fragment based on the backstack
Any help is greatly appreciated.
Your navigation is working fine I guess and the issue you are facing is the tittle for which you can use
public class SampleFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Creating view correspoding to the fragment
View v = inflater.inflate(R.layout.fragment_layout, container, false);
// Updating the action bar title
getActivity().getActionBar().setTitle("Screen name");
return v;
}
}
in every fragment. And whenever you backpress the onCreateView method of fragmemt(the one which is poping from the backstack) gets called and the tittle will again set replacing the old tittle.
1. Handle back
You can use getSupportFragmentManager().popBackStack() method in onBackPressed:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction().commit();
}
else {
super.onBackPressed();
}
}
Don't forget to add the fragment in BackStack like :
transaction.addToBackStack(null);
2. Display Name
To show the current fragment name in actionbar, you can get it on onResume of your Fragment :
#Override
protected void onResume() {
super.onResume();
((FrgmentActivtiyName)getActivity).changeTitle("title");
}
Define a method which set the title in the actionbar in your FrgmentActivity:
public void changeTitle(String titleToSet) {
// set title as titleToSet
}
Hope it helps ツ
Please try this:
In the activity which holds the fragments, override the onbackPressed() method by,
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction().commit();
}
else {
super.onBackPressed();
}
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
menuList.setItemChecked(position, true);
menuList.setSelection(position);
}

Categories

Resources