I found so many similar questions and so many different answers, but none of them helped me. I will try to post a clear question to get a clear answer if it's possible.
So I have an Activity that has a ViewPager with FragmentStatePagerAdapter containing (for now) only one fragment (HomeScreenFragment).
Inside HomeScreenFragment I have a RecyclerView with a list of several kind of different icons which should open a different fragment for each item click.
HomeScreenFragment has a FrameLayout as a root layout with id name "container". This is the method I'm calling to replace HomeScreenFragment with MainTypesFragment in this case:
private void openAllTypesFragment() {
MainTypesFragment fragment = new MainTypesFragment();
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.addToBackStack(HomeScreenFragment.class.getName());
transaction.commit();
eventBus.post(new Event(null, Event.EVENT_FRAGMENT));
}
Since FragmentStatePagerAdapter is initialized in MainActivity, I'm sending an event which will MainActivity catch and call adapter.notifyDataSetChanged();
Doing it this way, nothing happens.. I tried with getChildFragmentManager() instead of getActivity().getSupportFragmentManager() and in that case, previous fragment (HomeScreenFragment) is visible underneath new one (MainTypesFragment)..
Any ideas what am I doing wrong here?
The container you are using is wrong.Maintain one container in the activity xml and use that container to load all the fragments.
transaction.replace(R.id.container, fragment);
The container here is to be the activity container in which viewpager and other views should be present.
You can try my code :
private void addFilmDetailFragment(Movie movie){
android.support.v4.app.FragmentManager fragmentManager = getFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
FilmDetailFragment fragment = new FilmDetailFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("movie", movie); // Key, value
fragment.setArguments(bundle);
fragmentTransaction.replace(R.id.mainContentStore, fragment);
// fragmentTransaction.replace(R.id.mainContent, fragment, Config.TAG_FILM_DETAIL);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
In a fragment of viewpager :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainContentStore"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerFilm"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
It worked for me, i hope it will help your problem!
You need container inside activity for ViewPager and inside fragments(pages), containers for opening new fragments inside pages.
And if you want to open new fragment you should user something like this
in page fragment
getChildFragmentManager().beginTransaction()
.replace(R.id.page_fragment_container, fragment)
.addToBackStack(name)
.commit()
where R.id.page_fragment_container container inside page fragment.
Related
I try on another forum, thanks for answer but this was too hard tho!! :)
You should create specific layout for your fragment in activity layout and specify its id in replace method. For more information read fragment documentation
here is the documentation of FragmentTransaction.replace()
The first parameter is the ID of the container view which contains your Fragments and not the ID of your layout
The second is the instance of the Fragment you want to display.
Generally, something like this is done :
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, myFragment);
fragmentTransaction.commit();
First of all you need to have a frame layout in your main activity where you can place fragments and show to your users. That can be done like this:
<android.support.constraint.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".HomeActivity"
tools:showIn="#layout/app_bar_home">
<FrameLayout
android:id="#+id/frm"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp">
</FrameLayout>
Now in the frame layout (id = frm), you can place various fragments based on button clicks by your users. Now, by default place the first fragment in the frame layout and have a button in that fragment. Which can be done by adding the below line in your main activity:
fragmentTransaction.replace(R.id.frm,new FirstFragment()).addToBackStack(null).commit();
Once that button is clicked, you can write logic to replace the 1st fragment with 2nd fragment. Use the sample code below:
Your 1st fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/litegrey">
<Button
android:id="#+id/frag2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to fragment 2" />
</LinearLayout>
Logic to move to next slide (this should be added in your 1st Fragment):
frag2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentTransaction.replace(R.id.frm,new SecondFragment()).addToBackStack(null).commit();
}
});
You can create one activity that contains a frameLayout with an id similar to fragment_container.
then from your activity you do the following:
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
that will place one fragment inside your Activity's layout. When you want to replace that, you just create the second fragment and do the same. If you want to make it easier just use it as a method:
public void replaceFragment(Fragment fragment, Context context) {
FragmentTransaction transaction = context.getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
and use it when you need to either display a fragment or swap one for an already displaying fragment. As Context use the activity that holds the fragments.
The idea is that you have one activity as a wrapper to the fragment. In its layout file you create a space for the fragment to be displayed, and with the above method, you replace the empty space with your fragment's layout. If you call it again with a different fragment in the arguments, it will automatically replace that space with the layout of the new fragment.
EDIT: If you want to switch back and forth using a button, add a button in your activity's layout and set an onClick listener. Then use a flag to choose which fragment to display.
boolean isFragmentOneDisplayed;
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isFragmentOneDisplayed) {
FragmentTwo fragment = new FragmentTwo();
replaceFragment(fragment, MainActivity.this);
isFragmentOneDisplayed = false;
} else {
FragmentOne fragment = new FragmentOne();
replaceFragment(fragment, MainActivity.this);
isFragmentOneDisplayed = true;
}
}
});
I have two fragments the first fragment contains list of linear layouts and the whole fragment is in scroll view the second fragment is added and the first is hidden on choosing item from the first.
The problem is the second fragment is created scrolled down if the first fragment was scrolled down.
I tried the ways to force second fragment to be scrolled to (0,0) but failed.
the code used to add the second fragment
public void setActionOnClick(String id) {
CommentFragment frag = new CommentFragment();
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("TAG", TAG_NEWS_STORY);
((MainActivity) getActivity()).setCurrentTag(TAG_NEWS_STORY);
frag.setArguments(bundle);
android.support.v4.app.FragmentTransaction fragmentTransaction =
getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,
android.R.anim.fade_out);
fragmentTransaction.add(R.id.main_content, frag, TAG_NEWS_STORY);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
on Attach of second fragment the first fragment is hidden.
I don't want to use fragmentTransaction.replace because there are calls to the api which I don't want to reload.
this is an old question but. probably your fragment place_hoder is inside an scrollview.
just check if R.id.main_content is in a scrollview or not.
you should add the ScrollView to the fragment-layout instead of instantiating the fragment inside one
Before this:
android.support.v4.app.FragmentTransaction fragmentTransaction =
getActivity().getSupportFragmentManager().beginTransaction();
Add code to remove old fragment:
getSupportFragmentManager().beginTransaction().remove(yourOldFragment).commitAllowingStateLoss();
Im currently working on a sample app that will be using fragments, but im having a little problem regarding changing the fragment.
My default layout for my fragment is fragmentOne (see code below).
<fragment
android:id="#+id/fplace"
android:layout_width="match_parent"
android:layout_height="498dp"
android:name="layout.FragmentOne"
tools:layout="#layout/fragment_fragment_one" />
and that's working correctly.
but when im changing the fragment it appends. the behavior must replace the fragment not append.
here is my code for the activity (see code below).
public void onClick(View view) {
Button button = (Button) view;
Fragment fragment = null;
switch (button.getId()) {
case R.id.f1:
fragment = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fplace, fragment);
ft.commit();
break;
case R.id.f2:
fragment = new FragmentTwo();
fm = getFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.fplace, fragment);
ft.commit();
break;
}
}
and from the fragment one i am loading the data from the onCreateView() which is working correctly. the main problem is the fragment appends not replace.
(see photo below)
the red and yellow must be replaced by the blue colored fragment
As Mike said in comment
You cannot remove/replace Fragments that are declared in your layout.
So here is solution for you. Instead of fragment in xml use framelayout as container which will hold the fragment
use this instead of fragment in xml
<FrameLayout
android:id="#+id/fplace"
android:layout_width="match_parent"
android:layout_height="498dp"
/>
Hope this will help you.
declare a new fragmenttransaction in the second case dont use the fragment transaction that is used in the first case
I'm new to android programming and I'm trying to make an app that uses tabs in a viewpager from one main fragmentactivity.
The viewpager and tabs work fine but I want to have an options menu that when an item is selected, opens a completely new fragment, but I don't seem to be able to remove the view pager. I would like to just be able to put the new fragment over the viewpager on the main screen but trying to do that with a fragmenttransaction doesn't seem to work
Any ideas?
Thank you for your time
Ensure that:
1) your Fragment (e.g.: ViewPagerFragment1), which will be selected by the viewpager, has a FrameLayout as root layout with the id "container" e.g:
<FrameLayout
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:id="#+id/container"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout.... and so on
</FrameLayout>
2) Inside the ViewPagerFragment1 class, you have to replace/add the new fragment to the FrameLayout after an action has been triggered. E.g.:
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.selection:
// Create new fragment and transaction
NewFragment newFragment = new NewFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, newFragment, "NewFragment");
transaction.addToBackStack(null);
transaction.commit();
break;
default:
break;
}
}
Well, you will be adding the Fragment to some FrameLayout using the ID of the FrameLayout I assume. Just make sure the FrameLayout you are adding the Fragment to is on top of the ViewPager.
For example if both the ViewPager and FrameLayout are in a RelativeLayout container then make sure the FrameLayout is declared below the ViewPager in the XML. This will stack the FragmeLayout on top of the ViewPager. When the Fragment is added to the FrameLayout it will be drawn on top.
My requirement is quite simple: I have a button that should replace a FragmentA by FragmentB.
This sounds easy and nearly work, the big problem is that the old fragment is not removed and the new placed on the front of the old one and they are "living" together in my layout.
The Code:
FragmentManager fragMgr = a.getSupportFragmentManager();
Fragment currentFragment = (Fragment) fragMgr.findFragmentById(R.id.fragmentitself);
if(currentFragment!=null){
FragmentTransaction fragTrans = fragMgr.beginTransaction();
fragTrans.remove(currentFragment);
FragmentB newFragment = new FragmentB();
fragTrans.replace(R.id.fragmentcontainer, newFragment);
// I have also tried with R.id.fragmentitself
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();
}
The Layout:
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:id="#+id/fragmentcontainer">
<fragment
android:id="#+id/fragmentitself"
android:name="com.WazaBe.MyApp.FragmentA"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Solution
First, you have to remove your fragment from XML and just keep empty container there:
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:id="#+id/fragmentcontainer" />
Then you need to add your com.WazaBe.MyApp.FragmentA fragment from code, i.e. in onCreate() of your parent Activity.
Explanation
It is because your transactions manipulate content of ViewGroup such as said FrameLayouts. The catch is, that you can only manipulate elements you added from code as whatever is inflated from XML layout is considered "read-only". So when you put your Fragment directly into your XML layout, then it becomes permanent part of the view hierarchy and because it is permanent and the whole hierarchy is "read-only" it cannot be removed from code.
Once you get your layout fixed and Fragment extracted, the remove() call is no longer needed - it will suffice to just do replace().
If you want to place a Fragment in a View Container(Such as a Framelayout),you must make sure that your container is empty(only this you can put a fragment into it).you cannot replace a fragment writed in XML file,you should add A into the container by JAVA code ,and when you don't neet id ,you can replace it by B;
at first ,your container is empyt:
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:id="#+id/fragmentcontainer">
</FrameLayout>
OK,you put FragmentA into it:
FragmentTransaction fragTrans = fragMgr.beginTransaction();
fragTrans.remove(currentFragment);
FragmentA fragA= new FragmentA();
fragTrans.add(R.id.fragmentcontainer, fragA).commit();
NOW,if you want to replace:
FragmentTransaction fragTrans = fragMgr.beginTransaction();
FragmentB newFragment = new FragmentB();
fragTrans.replace(R.id.fragmentcontainer, newFragment);
// I have also tried with R.id.fragmentitself
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();
if we use Fragment container on activity, it require select one default FragmentABC, the default FragmentABC view cannot removed even we use the ft.remove.
Use FrameLayout container instead of Fragment container if you want a empty view of fragment on activity startup.
Same Answer In Kotlin
private fun showDetailView(position: Int) {
val fragTrans: FragmentTransaction = supportFragmentManager.beginTransaction()
val fragment: Fragment
when (position) {
0 -> fragment = FragmentA()
1 -> fragment = FragmentB()
else ->
fragment = FragmentC()
}
fragTrans.replace(
R.id.itemDetailContainer,
fragment).commit()
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
}
}