Android: Replacing a fragment in a composite layout - android

I'm trying to replace a fragment in a composite layout. Here's my root layout XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/buttons"
android:name="com.kippygo.android.touch_talker.ButtonsFragment"
android:layout_width="200dp"
android:layout_height="match_parent"
class="com.kippygo.android.touch_talker.ButtonsFragment" >
<!-- Preview: layout=#layout/buttons_fragment -->
</fragment>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/buffer"
android:name="com.kippygo.android.touch_talker.BufferFragment"
android:layout_width="match_parent"
android:layout_height="80dp" >
<!-- Preview: layout=#layout/buffer_fragment -->
</fragment>
<FrameLayout
android:id="#+id/grid_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" >
</FrameLayout>
</LinearLayout>
</LinearLayout>
As you can see, I have three areas in my layout, a fixed left column containing a fragment with buttons the rest of the layout is divided vertically with a fragment managing a textView at the top and a grid of data in the lower section.
I want to use a common layout to place various GridView elements in the "grid_frame" as I press buttons in the "buttons" fragment. Here is the "grid_fragment" layout that I want to use for each GridView fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/grid_fragment_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="80dp"
android:clipToPadding="true"
android:gravity="center"
android:horizontalSpacing="20dp"
android:numColumns="auto_fit"
android:orientation="vertical"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" >
<!-- Preview: listitem=#android:layout/simple_list_item_2 -->
</GridView>
<TextView
android:id="#+id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="22sp"
android:textStyle="bold"
android:text="#string/no_list_items"/>
</LinearLayout>
This composite layout opens up fine when I start my app. and I set my first fragment in the FrameLayout id "grid_frame" in my initial activity with the following code:
// Execute a transaction to put the categoriesFragment in the grid_view
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.grid_frame, new CategoriesFragment(), "category_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
This works perfectly fine and I see my buttons on the left, text input box on top and a grid of nicely filled cells to the right of the buttons.
When I click one of the list items in the GridView presented by the dynamic fragment I want to replace the fragment in the "grid_frame" FrameLayout. I do this with the following code in the onItemClick listener method of the "grid_frame" fragment with the following code:
// Execute a transaction to put the categoriesFragment in the grid_view
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.grid_frame, categoryWordsFragment, "category_words_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
Which looks remarkably similar to the code I used in the activity to set the initial fragment which worked fine.
When I do this my entire screen is replaced with the new fragment layout, which is another GridView with different data. My root layout appears to be totally replaced with the layout that was inflated by the new fragment even though I specify the "grid_frame" FrameLayout as the container view id in the replace method call.
I have tried everything I can find to make my layout stay intact and just change the fragment in the FrameLayout container.
What am I doing wrong please?

Problem solved! It was a very stupid mistake. I had converted my Activity classes to Fragment classes and in this one class I had forgotten to remove the call to setContentView in the class onCreate method. So the fragment was setting a new layout each time I created a new instance

Related

Android Fragment transition overlapping [duplicate]

I have an activity with two fragments, one to display a list and one to show the details of the clicked item. When starting the app the detail part is something static, once I click an item it should get replaced. The problem is that the old fragment is not being replaced, so both views are on top of each other.
My activity layout is:
<?xml version="1.0" encoding="utf-8"?>
<fragment
android:id="#+id/listFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.fragments.FragmentOrderList" >
</fragment>
<fragment
android:id="#+id/detailFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
class="com.fragments.FragmentOrderDetails" >
</fragment>
The layout for the detail fragment is:
<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" >
<TextView
android:id="#+id/tvOrderDetail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test view of details fragment" >
</TextView>
And in the above layout we see as well the static text we see initially. The code in my activity to replace the fragment is this
FragmentTransaction transaction = getFragmentManager().beginTransaction();
FragmentOrderDetails newFragment = new FragmentOrderDetails();
newFragment.setArguments(b);
transaction.replace(R.id.detailFragment, newFragment);
transaction.addToBackStack(null);
transaction.commit();
To me it looks like it is not a "replace" but rather an "add". Do I have to remove the old fragment always? Or do I have to follow a different approach here? It seems to me that only the original fragment stays there and on the second, third, ... replace the previous fragment is replaced correctly, just the static one stays there at all times.
Instead of using in layout xml fragment:
<fragment
android:id="#+id/detailFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
class="com.fragments.FragmentOrderDetails" >
</fragment>
Use some container like LinearLayout or FrameLayout with some containerId.
Then programatically firstly add fragment to this container using containerId, and after that replace content of this container with containerId also.

Fragment code in main activity does not fill the whole screen

i have problem with my FragmentLayout in main class. i have app for location, in my main activity is map (google API) and i have a menu, FragmentLayout (in my main activity XML) is wrap_content (height), when i click on Settings, FragmentLayout is shows but its not cover the whole screen just a part and under settings i see map (which not should be there). When i set up match_parent for my FragmentLaout then i dont see the map in from my main activity.
Here is my code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.globallogic.cityguide.MainActivity"
android:id="#+id/mainLayout"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/navigation_action"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
// THIS IS MY FRAGMENTS:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" //here is this option which cover my whole screen when i put there match_parent
android:id="#+id/main_container"
android:layout_gravity="center"
>
</FrameLayout>
<include layout="#layout/activity_outdoor_map"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<android.support.design.widget.NavigationView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/navigation_view"
app:menu="#menu/navigation_menu"
app:headerLayout="#layout/navigation_action"
android:layout_gravity="start"
>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
You are using different containers, while for this purpose you'd probably rather want to just use one main container (like your xml says) and replace the fragments in it.
This way you can set your FrameLayout to fit the whole screen and just replace the settings Fragment and the Map fragment when necessary.
So the code should be changed in your MainActivity.
Let's suppose your MainActivity already extends AppCompatActivity and we have an instance of mapFragment, then you'll want to load your Map Fragment first, something like so:
// Add the fragment to the 'main_container' FrameLayout
getSupportFragmentManager().beginTransaction().add(R.id.main_container, mapFragment).commit();
now when you press the settings button you will just replace the fragment:
SettingsFragment settingsFragment = new SettingsFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the main_container view with this fragment,
// and add the transaction to the back stack if you want the user to be able to navigate back
transaction.replace(R.id.main_container, settingsFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
More info: here
You can add this in your layout file. And other menu option from your java file.
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="342dp"
android:layout_height="473dp" android:id="#+id/map" tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
</LinearLayout>

Make fragment totally inside framelayout

In my app, I want to keep a same Ad banner at the bottom of all the screens, so I use one Activity with multiple fragments.
In the Activity's layoutfile(activity_mail.xml), I have a FrameLayout as the container of the fragments and a AdView at the bottom to show the banner Ads from Admob.
<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"
tools:ignore="MergeRootFrame">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<fragment
android:id="#+id/adFragment"
android:name="com.jiyuzhai.wangxizhishufazidian.MainActivity$AdFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
</RelativeLayout>
Layout of the fragment to replace the existing fragment
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#drawable/theme_color"
android:layout_alignParentTop="true"
android:text="Topbar in fragment"
android:textColor="#android:color/white"
android:textSize="30sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#drawable/theme_color"
android:layout_alignParentBottom="true"
android:text="Bottombar in fragment"
android:textColor="#android:color/white"
android:textSize="30sp"/>
</RelativeLayout>
Code to replace the existing fragment
fragment = new LinmoFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out);
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.commit();
But when I replace the fragments in the container, the bottom area of the fragment was hide by the AdView, in other words, the fragment was out of the Framelayout, I want the fragment totally inside the container. is that possible?
The following is what I want
and this is what I get(The Ad banner hide the bottombar of the fragment)
Any idea?
By the way, I find there is no way to keep a same banner for all screens with multiple Activities in Android, many people on SO said you need to use Single Activities with multiple fragments, then you can add/remove your fragments dynamically without reload new banner, but, there is no code found for this approach, so I try it myself. if you have better solutions, please help me.
Try this:
<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"
tools:ignore="MergeRootFrame">
<fragment
android:id="#+id/adFragment"
android:name="com.jiyuzhai.wangxizhishufazidian.MainActivity$AdFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/adFragment" />
</RelativeLayout>
The changes I made to your original layout file were moving the adFragment definition above the frame layout, made the frame layout height wrap content, and added the layout_above attribute to make the frame layout appear above the ad fragment.
An alternative approach would have been to use a vertical linear layout with the frame layout first with a layout weight of 1 (and the ad fragment would not have a layout weight).
By the way, the fragment is contained completely within your frame layout. The frame layout was just being overlapped by the ad fragment in your original layout. The above suggestion makes it so that there is no overlap.
Hope this helps.
If you want to both avoid overlapping and make the container fill the screen then you should just change RelativeLayout to LinearLayout.
<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="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame"
android:orientation:"vertical"
>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<fragment
android:id="#+id/adFragment"
android:name="com.jiyuzhai.wangxizhishufazidian.MainActivity$AdFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

Child fragment replacing parent fragment root layout

I've viewpager with 5 fragments, in one of them I want to completely replace it by button click. I also want to be able to hide child fragment by back button.
Here this fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="#+id/contacts_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#null">
<LinearLayout
android:id="#+id/import_contacts"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<include layout="#layout/listview_filter"/>
<Button
android:id="#+id/btn_my_clusters"
android:background="#drawable/btn_wide_arrow_bg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/TEXT"
android:text="#string/btn_my_clusters_text"
android:layout_marginBottom="10dp"/>
<ProgressBar
android:id="#+id/progress_bar"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_gravity="center"/>
<ListView
android:id="#+id/contacts_list"
android:divider="#null"
android:listSelector="#android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"/>
</LinearLayout>
When I try replace contacts_layout like this:
ImportContactsFragment importContactsFragment = new ImportContactsFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.contacts_layout, importContactsFragment).commit();
it doesn't work (I mean there is no error, but my ImportContactsFragment not showing at all). But when I try replace import_contacts view like this:
ImportContactsFragment importContactsFragment = new ImportContactsFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.import_contacts, importContactsFragment).commit();
everything is ok, ImportContactsFragment shown.
So I wonder is it possible to replace all fragment content by child fragment? Maybe I can do it in some other way?
The replace transaction doesn't remove the current views from the target layout container so when you use the first pice of code the new Fragment is added to the contacts_layout LinearLayout but it will not be seen as the previous views cover the entire screen(height).
With the second piece of code the LinearLayout to which you add the new Fragment is the first child of the parent LinearLayout and it has space so its visible.
For what you're doing I advise you to wrap the initial layout in a Fragment class placed in a wrapper layout which you could then later replace very easy.

Android programmatically add fragment - position in parent and layout

OK, I'm trying to create a universal app that shows 3 tabs in phone view and 3 columns in tablet landscape. As such I created several different XML layouts using Linear Layout.
However, using fragments, I came across a problem - I want to remove the leftmost column when a selection is made in that fragment. I believed I could do this but it turns out I can't remove fragments declared in XML. So now, I'm tring to create the middle and right columns in XML:
<?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:id="#+id/menu_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment
android:id="#+id/classification_fragment"
android:name="uk.colessoft.android.hilllist.fragments.MenuClassificationFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="#layout/list_classifications" >
</fragment>
<fragment
android:id="#+id/map"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
Then add the first column using
FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MenuCountryFragment countryFragment=new MenuCountryFragment();
fragmentTransaction.add(R.id.menu_layout, countryFragment, "country_menu").commit();
but I have two problems:
a) The above code only puts the fragment at the right hand side of the Linear Layout and I can't specifiy position. It needs to be on the left.
b) XML gave me the freedom to define different weights for the fragment based on screen size/orientation. Setting layout parameters programmatically in the Fragments seems a backward step. I got round this by putting a placeholder view in the xml that I read the layout params from this and assign them in onCreateView but its a hack.
I know I can put the fragment in the correct place by adding it as a child of the first element in the xml but when I do this and remove the fragment it leaves a blank space.
Create a placeholder for the new fragment you want to add (in your XML), something like this...
<?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:id="#+id/menu_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="#+android:id/realtabcontent"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<fragment
android:id="#+id/classification_fragment"
android:name="uk.colessoft.android.hilllist.fragments.MenuClassificationFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="#layout/list_classifications" >
</fragment>
<fragment
android:id="#+id/map"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
Then, instead of adding a new fragment at runtime, replace the content of the empty container...
FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MenuCountryFragment countryFragment=new MenuCountryFragment();
fragmentTransaction.replace(R.id.realtabcontent, newFrag).commit();
fragmentManager.executePendingTransactions();
Hope this helps.

Categories

Resources