I have an activity that is half a fragment and half some UI elements .
I want to dynamically switch this fragment programmatically by two other views with their own logic and their own UI but with the UI elements in the first half of the screen and their functionality in common.
my whole problem is when i get to switch fragments using FragmentManager the result is the whole screen is being replaced by the fragment views and overlaps the first half of the activity.
here the code in the activity:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
FirstFragment firstFragment = new FirstFragment ();
SecondFragment secondFragment = new SecondFragment ();
if (mode==2) {
fragmentTransaction.replace(android.R.id.content, secondFragment );
}else if (mode==1){
fragmentTransaction.replace(android.R.id.content, firstFragment );
}
fragmentTransaction.commit();
and here the fragment xml code inside the view of the activity
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Note i'm not concerned to switch the fragments when the activity is visible, the "mode" variable in my code is set only once at oncreate of the activity.
Could the problem be is that i have to place the first part of the my view that has common UI elements also inside a fragment?
As doodeec said android.R.id.content gets the whole view, i should have assigned an id to the fragments then call
fragmentTransaction.replace(android.R.id.myfragment, secondFragment );
and
fragmentTransaction.replace(android.R.id.myfragment, firstFragment );
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 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.
In my activity, I have various fragments. By default activity displays a map. On listitem click, fragment A, B or C is displayed using following code:
protected void replaceFragment(int i) {
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
switch (i) {
case FRAGMENT_A:
aFragment = new AFragment ();
fragmentTransaction.replace(R.id.main_framelayout_replace,
aFragment , TAG_A_FRAGMENT);
fragmentTransaction.commit();
break;//and so on.....
default:
break;
}
}
Here I'm facing an issue: When I replace FragA with FragB which is nested fragment i.e. it contains list and detail fragment within itself. When I try to remove any fragment other than FragB, I'm able to do it successfully and show the default map screen but when I'm on FragB and try to remove it, I'm not able to see default map screen. Instead a blank white screen is getting displayed.
Removing of fragments is done as follows:
if (aFragment != null) {
fragmentManager.beginTransaction()
.remove(aFragment ).commit();
}//and so on...
For FragB which is having list and detailed fragment, I also do following in onDetach of FragB,
fragmentManager.beginTransaction()
.remove(MainActivity.listFragment).commit();
Am I doing anything wrong here? Any help appreciated.
Note: I'm not getting any exception in any try catch. All the lines of code are getting executed without error including onDetach of FragB.
In your FragB class (which extends Fragment) you should be using ChildFragmentManager to manage nested fragments.
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);
}
}