Here's my navigation:
HomeFragment -> LoginFragment -> CreateEventFragment
My HomeFragment is my first Fragment inside my MainActivity.
In my code, I'm replacing each one of them using the same view id( a FrameLayout inside my MainActivity's layout: R.id.container).
So every replace() is being called like this:
FragmentManager fragmentManager = mContext.getSupportFragmentManager();
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).addToBackStack(null).commit();
Except for LoginFragment to CreateEventFragment, because after the user logs in, he doesn't have to go back to LoginFragment so I don't call addToBackStack().
But something strange is happening:
When I'm on CreateEventFragment, after logging in successfully, and press the back button, my CreateEventFragment onDestroy() is not being called.
Debugging it I noticed that it isn't removed from the backStack, what am I doing wrong?
EDIT
Some code:
Common replace fragment method, inside BaseFragment, parent class of all three Fragments
public void replaceFragment(int containerId, Fragment nextFragment, boolean addToBackStack){
FragmentManager fragmentManager = mContext.getSupportFragmentManager();
if (addToBackStack)
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).addToBackStack(null).commit();
else
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).commit();
}
On HomeFragment:
BaseFragment nextFragment =
(PreferencesHandler.isLogged()) ?
CreateEventFragment.newInstance() :
LoginFragment.newInstance("create_event") ;
replaceFragment(R.id.main_fragment_container, nextFragment, true);
On LoginFragment:
public void goToNextFragment(){
Fragment nextFragment;
switch (mIntent){
case "create_event":
nextFragment = new CreateEventFragment();
break;
case "participate":
nextFragment = new ListsFragment();
break;
default:
nextFragment = new HomeFragment();
break;
}
replaceFragment(R.id.main_fragment_container, nextFragment, false);
}
My MainActivity's layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/toolbar_actionbar"
layout="#layout/toolbar_actionbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:layout_below="#+id/toolbar_actionbar"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar_actionbar"
/>
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="Fragments.`NavigationDrawerFragment`"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
EDIT 2
Noticed that pressing back button calls LoginFragment onDestroy, but not CreateFragment's. Also noticed that backStack has LoginFragment, guess it shouldn't, right?
Related
I have a main activity , it contains lots of fragments.
Main activity layout looks like this:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.taiwandigestionsociety_v11.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF">
<include layout="#layout/toolbar"/>
//switch fragment over here
<FrameLayout
android:id="#+id/mainFrame"
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
and I click the drawer item it will change to first fragment:
#Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.activitiesContents) {
//change to first fragment successful
switchFragment(ActivityList.newInstance());
toolbar.setTitle(R.string.activitiesContents);
drawerLayout.closeDrawer(GravityCompat.START);
}
}
my switch fragment function:
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
//transaction.addToBackStack(null);
transaction.commit();
}
then i click the button in first fragment, it changes to second fragment too:
//take me to second fragment succeed
switchFragment(ActivityHomePage.newInstance());
finally i click the button in second fragment, it crashed
//i want to switch to third fragment , just the same with previous
switchFragment(NewsInformation.newInstance());
the error log:
Why i got crash when i switch to third fragment? I completely have no clue.
I found the crash function function , because I set the class:
public class CommonSwitch extends Fragment {
//switch Fragment
public void switchFragment(Fragment fragment) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
//transaction.addToBackStack(null);
transaction.commit();
}
}
and I try to call it new CommonSwitch.switchFragment(goToFragment);
now I have set public void switchFragment every Fragment class.
Why when I set new CommonSwitch will cause crash ?
Your Activity state is Not Maintain.
On second layer use Activity instead of Fragment . Follow Android Standards.
According to standards Third Fragment should be Activity. otherwise you have to maintain MainActivity state.
Thanks
I've got an activity in which there are 2 fragments which changes basing on a button click.
I'd like to show an animation when the replacement appens, so i searched for the code and here's what i concluded:
public void displayView(int page){
switch (page){
case 1:
FragmentHome fragmentHome = new FragmentHome();
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentHome)
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).commit();
break;
case 2:
FragmentHomeBack fragmentHomeBack = new FragmentHomeBack();
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentHomeBack)
.setCustomAnimations(android.R.anim.accelerate_decelerate_interpolator, android.R.anim.anticipate_interpolator).commit();
break;
}
}
I don't know why but the animations don't works, the new fragment just replace the other without animation.
Here's the activity layout code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_master"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/space10"
tools:context="context">
<include
android:id="#+id/ll_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="#dimen/space5"
android:orientation="vertical"
android:layout_marginLeft="#dimen/space5"
android:layout_marginRight="#dimen/space15"
layout="#layout/menu"
android:layout_alignParentTop="true"
android:layout_above="#+id/imageView" />
<FrameLayout
android:id="#+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/ll_left">
</FrameLayout>
<ImageView
app:srcCompat="#drawable/xlink"
android:id="#+id/imageView"
android:layout_width="150dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:scaleType="fitEnd"
android:layout_height="70dp" />
The frame layout "fragment_holder" is where the Fragments are.
Thanks to everybody!
That should do the trick buddy. I have the same code and it works well.
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
.replace(R.id.layout_container, fragment)
.commit();
But..
I see what is the difference in our code. Try setting customAnimations before replace to see what happens.
And I have a suggestion to improve your code. In your "if" or "switch" statement set the fragment like
Fragment fragment;
if(page==0){
fragment = new MyFragment();
}else{
fragment = new MySecondFragment();
}
then you only have this code once
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
.replace(R.id.layout_container, fragment)
.commit();
I'm kinda new in android and I'm developing an application but I am blocked with something:
I have my activity_main:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
And this activity contains 1 fragment(drawer_layout_fragment) and my fragment(drawer_layout_fragment) contains another fragment(left_drawer) that is the nav drawer fragment:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout_fragment"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="DrawerLayoutFragment">
<!-- The navigation drawer -->
<fragment
android:id="#+id/left_drawer"
android:name="NavigationDrawerFragment"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:layout="#layout/fragment_navigation_drawer"/>
</android.support.v4.widget.DrawerLayout>
Everything works fine when I add that fragment to the fragment manager but when I'm in the next view and I clicked back button I'm seeing this error: Duplicate id 0x7f0d00a5, tag null, or parent id 0x7f0d00f4 with another fragment
I have read that error happens because of I have nested fragments but not sure how can I handle this I have tried added my drawer_layout fragment with the getChildFragmentManager but same error.
And this is how I added my drawer_layout fragment to the fragment manager:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DrawerLayoutFragment fragment = new DrawerLayoutFragment();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
And this is the code inside DrawerLayoutFragment that takes me to the next fragment. The only difference is that here I use .replace instead of .add :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.add) {
NextFragment fragment = new NextFragment();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
}
return super.onOptionsItemSelected(item);
}
I am changing fragments inside framelayout.This is my main activity layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" xmlns:app="http://schemas.android.com/apk/res/com.impact.ribony">
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip"
android:visibility="gone"
app:pstsIndicatorColor ="#0B0B16"
app:pstsShouldExpand="true" />"
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tabs">
</android.support.v4.view.ViewPager>
</RelativeLayout>
Firstly I am showing login fragment then user logins I am hiding framelayout.Because I am using viewpager.If user wants go to settings I am loading settings fragment then I am showing framelayout again.
But I have a problem,you can see it here: http://youtu.be/H6AO7yYusjM
You can see when user goes to settings fragment,firstly login fragment showing for 1 second then settings fragment is loading.How can I prevent this ? (When I try to change fragment always showing last fragment for 1 second not just login fragment)
If user logins successfully I am removing login fragment with following lines:
pager.setVisibility(View.VISIBLE);
tabs.setVisibility(View.VISIBLE);
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.GONE);
I am loading login fragment with following code:
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
LoginFragment conv = new LoginFragment();
loginObj=LoginFragment.newInstance("asd");
fragmentTransaction.replace(R.id.container, loginObj,"LoginFragment");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
actionBar.hide();
pager.setVisibility(View.GONE);
I am loading settings fragment with following code:
FrameLayout layout=(FrameLayout)findViewById(R.id.container);
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
SettingsFragment conv=new SettingsFragment();
SettingsFragment.newInstance(LOGGED_USERNAME);
fragmentTransaction.replace(R.id.container,conv);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
layout.setVisibility(View.VISIBLE);
I've got a question.
I have a fragment, which inflates two other fragments (Fragment A is left, Fragment B is right)
I want to hide Fragment A when the user changes the mode to portrait-mode.
I added in the layout-port/xml a DrawerLayout and added the code for the NavigationDrawer in my Fragment, but it doesn't work.
Does anyone have an idea, how to realize it?
Thanks :)
I've solved the first problem with this code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
orientation = newConfig.orientation;
switch (orientation) {
case Configuration.ORIENTATION_LANDSCAPE:
FragmentA fragmentleft = new FragmentA();
FragmentB fragmentright = new FragmentB();
FragmentTransaction transaction1 = getSupportFragmentManager()
.beginTransaction();
FragmentTransaction transaction2 = getSupportFragmentManager()
.beginTransaction();
transaction1.replace(R.id.framelayout_left, fragmentleft);
transaction2.replace(R.id.framelayout_right, fragmentright);
transaction1.commit();
transaction2.commit();
break;
case Configuration.ORIENTATION_PORTRAIT:
createNavigationDrawer();
Log.d("TEST", "Portrait");
break;
}
}
But now I have the problem, that i have to inflate FragmentA in my ListView of the DrawerLayout:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/framelayout_right"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/framelayout_left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
But how can I do this?
It doesn't work properly :(
I had also tried to change the ListView to a FrameLayout and inflate the FragmentA within it, but it didn't work too:(
I would be very thankful, if somebody could help me :)