What happens when you call FragmentTransaction.replace() on a fragment container? - android

My app has 1 activity and multiple fragments.
The container is a FrameLayout in my activity, and after the initial fragment is added to that container, replace() is then used to change fragments.
Initial add: transaction.add(R.id.fragment_container, firstFragment, "FirstFragment")
After initial add: transaction.replace(R.id.fragment_container, newFragment, "FragmentTag")
activity_main.xml
...
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/fragment_layout"
app:layout_constraintTop_toBottomOf="#id/toolbar"
app:layout_constraintBottom_toTopOf="#id/bottomNav">
</FrameLayout>
...
My question is, what exactly happens when I add and replace a fragment to R.id.fragment_layout?
Say my fragments are all ConstraintLayout - is the ConstraintLayout nested inside the FrameLayout?

Yes, your ConstrainLayout will be nested in FrameLayout, just open the Layout Inspector(Tools -> Layout Inspector) and you will see the following:

Related

What can be the difference of using a fragment and frameLayout in android? Can both be used interchangeably?

I have seen an approach where frameLayout is used in case of fragments. The ultimate goal was to have multiple fragments.
For showing a single Fragment immediately on the screen, yes, you can use fragment or FrameLayout interchangeably.
Single Fragment, Method 1
Showing the Fragment via the fragment tag would look like this in XML:
<fragment class="com.example.ExampleFragment"
android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
Single Fragment, Method 2
Showing the Fragment via FrameLayout would look like this in XML:
<FrameLayout android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
Followed by Java code like this:
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.details, newFragment);
transaction.addToBackStack(null);
transaction.commit();
Multiple Fragments
Method 2 then supports changing what fragment you are showing later by running more Java code to change what Fragment is there afterwards:
Fragment secondFragment = new SecondExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.details, secondFragment);
transaction.addToBackStack(null);
transaction.commit();
So FrameLayout gives you the extra ability to do that over using the fragment tag.
A framelayout, Relative View and a few others represents a view in android and is extended from viewgroup.
A Fragment is a an an Object that is used to represent a portion of a user interface and is usually hosted in an activity.
A fragment has a viewgroup which you can assign an XML layout. In the XML you can specify a viewgroup which can be a framelayout if you wish to represent the layout of the viewgroup within the fragment.
Fragments and framelayouts cannot be used interchangeably.
Having said that, you can create a Android application without the use of fragments, and just use viewgroups.

how to set position of fragment in center in RelativeLayout

hi guys I was playing aroung with fragments in android.
I read that there are two ways to bind a fragment in an activity.
1)using <fragment> tag in layout(XML) file.
2)using FragmentManager and FragmentTransaction .
I want my Activity to handle fragment dynamically so i went for the 2nd approach.
But when a fragment is added it is added to left-top corner in RelativeLayout Activity(which appears to be the default behaviour of RelativeLayout)
I want my fragment to appear at center of the Activity Layout.
I just can't figure it out how to give position to fragmet in JAVA code.
I looked into stackoverflow also,
which uses --RelativeLayout.LayoutParams
which appears to work with View objects(Button,TextView etc).
Any suggestions.
You can set a placeholder FrameLayout inside RelativeLayout in your XML and align it with android:layout_centerInParent="true". Then replace this placeholder with your fragment in the code FragmentTransaction#replace(int containerViewId, Fragment fragment, String tag)
In your Activity XML layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#id/fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
In your Activity class:
getFragmentManager().beginTransaction()
.replace(R.id.fragment, new MyFragment())
.commit();
In your Activity's layout use the attribute android:layout_gravity="center" for RelativeLayout in which Fragment resides. This will make all it's child element appear in center.

Fragment layout not fully inflating upon FragmentTransaction.add/replace

I am attempting to replace a nested fragment inside a tabLayout fragment.
My app structure follows this pattern.
Here is the XML for the Tab Fragment 2
<FrameLayout
android:id="#+id/scene_root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".Home"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/shows_fragment_list"
android:tag="list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_details"
android:tag="details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_info"
android:tag="info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
I am using this code to add the NestedFragment to the TabFragment FrameLayout
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = inflater.inflate(R.layout.shows_fragment_layout, container, false);
ShowDetailsFragment newNestedFragment = new ShowDetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getChildFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.add(R.id.show_fragment_details, newNestedFragment)
.addToBackStack("null")
.commit();
return root;
}
But when I add the Nested Fragment to the Tab Fragment, only the last part of my layout appears, in this case it is a list view (highlighted in red), but it always seems to be the which ever element is declared last when the layout is inflated by the corresponding Java file.
When I inflate these layouts as there own activity, there are no inflation problems, so it must relate to my implementation of fragments, any ideas where I am going wrong?
A good idea is always to use the Android Device Monitor to debug your layout.
I would also add some logging on the onCreateView of your fragments.
Ok so my problem was that in my XML layout for my ShowDetailsFragment (The Nested Fragment) I had a FrameLayout as the root, but there were two separate RelativeLayouts as children, meaning only the last element was being displayed, the problem was solved by nesting these two Relative Layouts in another single Relative Layout.
Props go to ctarabusi for pointing me in the right direction, although I am still unsure why this only caused a problem when inflating as a Fragment and not as an Activity.

Android fragments overlap previous view and button listeners

I have an activity A with a fragment A inside.
Activity A uses layout X, and fragment A uses layout A.
code of layout X:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<fragment
android:id="#+id/fragment1"
android:name="android.app.DialogFragment"
android:layout_width="wrap_content"
android:layout_height="500dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="113dp"
class="com.example.fragtester.FragA" />
</RelativeLayout>
Layout A is just textview + linearlayout.
I set up another fragment B that uses layout B.
Now that I use the following code in activity A to change the fragments:
Fragment f = new FragB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
I end up having layout B displaying under layout A.
So I use a FrameLayout to wrap the fragment in layout X and use
ft.replace(R.id.FrameLayout1, f);
Now the view is working nicely. Though, another problem arises.
Although layout B covers layout A, but the buttons are still active.
That means when I am viewing layout B, I can still click buttons on layout A, even if I am not seeing it.
And even when I add fragment C/D/E..... (layouts C/D/E....), the buttons on layout A is still active.
Can anybody explain why is that? Am I using fragments wrongly? Thanks!
A way to get through is to make layout A blank, and use other layout to cover it. But it doesn't seems to be the "right" way??
Remove the fragment and add a FrameLayout
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" >
</FrameLayout>
then add fragments programmatically.
In android fragment button click pass through the fragments (i dont know if the fragments are suppose to work like that). what I used to do in such a situation is to make the layout of the fragment clickable. so the clicks wont pass through.
Instead of having fragment in your xml, try to create empty container for a fragments. For example empty frame layout. And then programmatically put your fragments in there.
Add the following attribute to the XML root layout of the fragment that goes on top.
android:clickable="true"
This will ensure that touch events will not propagate further than the top layer.

Fragment is not being replaced but put on top of the previous one

Activity:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment1 fragment = new Fragment1();
Fragment2 fragment2 = new Fragment2();
transaction.replace(R.id.Fragment1, fragment);
transaction.addToBackStack(null);
transaction.commit();
FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
transaction2.replace(R.id.Fragment1, fragment2);
transaction2.addToBackStack(null);
transaction2.commit();
Code in the view:
<fragment
android:id="#+id/Fragment1"
android:name="com.landa.fragment.Fragment1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_below="#+id/include1" />
The problem is, the content doesn't really get replaced - it gets put on top (so it overlaps).
When I click back, the first fragment gets shown properly (without the second), but initially both are visible (I want only the last one to be visible).
What am I missing here?
You are doing two things wrong here:
You cannot replace a fragment that is statically placed in an xml layout file. You should create a container (e.g. a FrameLayout) in the layout and then add the fragment programatically using FragmentTransaction.
FragmentTransaction.replace expects the id of the container that contains the fragment and not the id of the fragment as the first parameter. So you should pass the first argument as the id of the container that you added the first fragment to.
You can refer to this link for more details.
I had a similar problem but my issue was that I was using two different Fragment managers:
One from getSupportFragmentManager() and one from getFragmentManager(). If I added one fragment with the SupportFragmentManager and then tried replacing the fragment with the FragmentManager, the fragment would just get added on top. I needed to change the code so that the same FragmentManager would be used and that took care of the issue.
The android developer site suggests the use of a FrameLayout to load fragments dynamically at run-time. You have hard-coded the fragment in your xml file. So it cannot be removed at run-time as mentioned in this link:
http://developer.android.com/training/basics/fragments/creating.html
this link shows how to add fragments through your program:
http://developer.android.com/training/basics/fragments/fragment-ui.html
I had the same problem and saw all the answers, but none of them contained my mistake!
Before trying to replace the current fragment, I was showing the default fragment in the xml of the container activity like this:
<FrameLayout
android:id="#+id/fragment_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="....ShopFragment"
android:id="#+id/fragment"
tools:layout="#layout/fragment_shop" />
</FrameLayout>
after that, although i was passing the FrameLayout to the fragmentTransaction.replace() but i had the exact problem.
it was showing the second fragment on top of the previous one.
The problem fixed by removing the fragment from the xml and showing it programmatically in the onCreate() method of the container activity for the default preview on the start of the program like this:
fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_frame_layout,new ShopFragment());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
and the container activity xml:
<FrameLayout
android:id="#+id/fragment_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
You can clear backStack before replacing fragments:
FragmentManager fm = getActivity().getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
fm.popBackStack();
}
// replace your fragments
<FrameLayout
android:id="#+id/fragment_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground">
//Add fragment here
</FrameLayout>
Add android:background="?android:windowBackground"> to the container in which your fragment resides. In in my case I added a FrameLayout, that should help.
I agree with Sapan Diwakar's answer. But I have found a workaround on how to do this.
First, in your activity(e.g. activity_main), where you have all the layouts, Add a FrameLayout. It's height and width should be match parent. Also, give it an id.
Now, in your fragment which is going to replace the current layout, call onPause() and onResume(). Initialise all the all the inner containers in View. And set their visibility to GONE in onResume() and VISIBLE in onPause().
NOTE: Not the FrameLayout which you are replacing with this fragment.
Suppose you have ViewPager, TabLayout, ImageView and a custom <fragment> in activity_main.xml. Add, a FrameLayout as mentioned above.
In abcFragment.java, in onClick() function, add addToBackstack(null) in transaction.
Example code:
in xyzFragment, which is going to replace abcFragment(and everything shown in activity_main.xml), do this
#Override
public void onResume() {
super.onResume();
// On resume, make everything in activity_main invisible except this fragment.
slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
viewPager = getActivity().findViewById(R.id.pager);
miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);
slidingTabs.setVisibility(View.GONE);
viewPager.setVisibility(View.GONE);
miniPlayerFragment.setVisibility(View.GONE);
}
#Override
public void onPause() {
super.onPause();
// Make everything visible again
slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
viewPager = getActivity().findViewById(R.id.pager);
miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);
slidingTabs.setVisibility(View.VISIBLE);
viewPager.setVisibility(View.VISIBLE);
miniPlayerFragment.setVisibility(View.VISIBLE);
}
Happy coding!
Use a container instead of using fragment
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!" />
Now in MainActivity
if(condition)
getFragmentManager().beginTransaction().replace(R.id.container,new FirstFragment()).commit();
else
getFragmentManager().beginTransaction().replace(R.id.container, new SecondFragment()).commit();
Please note that your fragment class should import 'android.app.Fragment'
Make sure, that you use "support.v4" or the "original" implementations and do not mix them. I was getting this problem because I had mixed them.
You can use setTransition method from FragmentTransaction to fix overlapping issue.
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
In Oncreate ()
BaseFragmentloginpage fragment = new BaseFragmentloginpage();
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame, fragment);
fragmentTransaction.isAddToBackStackAllowed();
fragmentTransaction.commit();
now this will be always your default fragment ...if you add fragment in xml layout it will always overlap , so set initial content with fragment at run time
i had same problem after using this problem solved
Take frame layout where u are replacing ur fragment
<FrameLayout
android:id="#+id/fragment_place"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and code for replacement
public void selectFrag(View view) {
Fragment fr;
if(view == findViewById(R.id.button2))
{
fr = new FragmentTwo();
}else {
fr = new FragmentOne();
}
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
if you want whole example i will send you just comment me......
I also had the same issue, but it was because I had not changed the background color of the fragment that I was trying add to my framelayout.
Try doing this, with layout_height and layout_width set to match_parent
I once had this problem and found out that it was because I had accidentally deleted the android:background attribute that is missing on your xml code. I believe it works like when you're painting a wall, android:background is the color that the wall will be and the other views are placed on top of that base color. When you don't paint the wall prior to positioning your views they will be on top of what was already in that wall, in your case, your other fragment. Don't know if that will help you though, good luck.
I have tried above all the case and try to fix the issue but still not got solution. I don't know why its not working for me. I agree with above answers because so many agree with it.
I am just extending the answer and below is the way which is working for me.
I have added this property android:clickable="true" in top parent layout on fragment.xml file.
I hope someone will get help.
Thank you to Sapan Diwakar and others. This answer helped me. I simply created a RelativeLayout without a fragment inside it, used the RelativeLayout as a parent or group view, specified that group view in the transaction to replace, and it worked.
Code:
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_group_view, itemDetailFragment).commit();
XML:
<RelativeLayout
android:id="#+id/content_group_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
Check your frame layout ID and replace it as below
fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();

Categories

Resources