I have a tab that contains a linear layout with a searchview and a listview. When the user clicks one of the search results, I want to replace that layout with another layout containing the details of the selection.
What happens when I replace the search fragment only the listview portion of the layout gets replaced; the searchview is still visible and active on the screen.
Here is my search layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/search_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SearchView
android:id="#+id/public_calendar_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:iconifiedByDefault="false"
</SearchView>
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:choiceMode="singleChoice" />
<TextView
android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:gravity="center"/>
</LinearLayout>
Here is the detail layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/detail_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="vertical" >
<Space
android:layout_width="0dip"
android:layout_height="20dip"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal" >
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".1" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".8"
android:text="#string/label_Name" />
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".1" />
</LinearLayout>
.........
</LinearLayout>
And my code to replace the search fragment:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack.
DetailFragment fragment = DetailFragment.newInstance(cal);
transaction.replace(R.id.search_layout, fragment);
transaction.addToBackStack(null);
transaction.commit();
Detail fragment creation:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.detail_layout, container, false);
return v;
}
static DetailFragment newInstance(String cal) {
DetailFragment d = new DetailFragment();
return d;
}
What am I doing wrong? How can I get the entire search layout to be replaced.
Thanks!
I figured out my problem. Marco wasn't exactly right but he pointed me in the right direction.
The problem was the the container ID I was passing to the replace method was the ID of the fragment I was replacing, not the ID of the fragment container. This seems to explain why some of the original fragment controls were remaining after the replace - that entire fragment wasn't being replaced.
I changed it to get the fragment container view ID, and that worked! Here's the code:
transaction.replace(((ViewGroup)(getView().getParent())).getId(), fragment);
I found the answer for getting the container view ID of a fragment here, Get fragment's container view id.
I was using the correct ID, then also it wasnt going away. Turns out that you need to set the Background color to your needed color in new Fragment layout, like this.
<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"
android:orientation="vertical"
android:background="#color/white_color">
To solve the problem, set the android:background property to “?android:windowBackground” in the fragment layout files.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
tools:context=".MainFragment">
...
</LinearLayout>
In Fragment_2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
tools:context=".SomeFragment">
...
</LinearLayout>
I was having the same problem, and the solution didn't work for me. Maybe this will help someone...
I had added a fragment inside the activity layout xml file. This caused a lot of issues.
Instead, add a frame layout in your xml file, and then programatically add and replace fragments. This causes the whole fragment to be replaced.
I had the same problem once, and this is my solution.
Try to do this, use FrameLayout instead of fragment in your layout file. Just like this:
<fragment android:id="#+id/your_fragment" />
Then, add your default fragment in activity method onCreate().
getFragmentManager().beginTransaction()
.add(R.id.your_fragment, YourFragment)
.commit();
Now, the old fragment can be replaced correctly, it looks great.
This worked for me, and I hope it helps you too.
Related
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>
Let's say I have 2 fragments, one contain a list view and another contain a loading text. I want when I click on one list item, the loading text fragment appears on top of the list view. I have adjusted the opacity of the loading text background to: android:background="#33FFFFFF" . But still it just shows the loading text on a solid grey background.
<?xml version="1.0" encoding="utf-8"?>
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#android:id/list"
android:background="#e8e9ee"
android:divider="#ccc"
android:dividerHeight="1dp"/>
Fragment that contains a textview:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/loadingText"
android:id="#+id/loadingText"
android:textColor="#e8e9ee"
android:background="#33FFFFFF"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
My java code is basically something like this: onItemClick:
FragmentTransaction transaction=manager.beginTransaction();
transaction.show(loadingFragment);
transaction.commit();
I did it and it works perfectly but instead of using .show I used .add:
Activity layout:
<RelativeLayout
android:id="#+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp">
<FrameLayout
android:id="#+id/list_view_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">
</FrameLayout>
<FrameLayout
android:id="#+id/loading_text_fragment_container"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true">
</FrameLayout>
</RelativeLayout>
In the Activity:
First add your List View:
ListViewFragment listViewFragment = new ListViewFragment();
fragmentManager.beginTransaction().add(R.id.list_view_container, listViewFragment).commit();
Then the loading text:
// Create a new Fragment to be placed in the activity layout
YourFragment yourFragment = new YourFragment();
// Add the fragment to the 'loading_text_fragment_container' FrameLayout
fragmentManager.beginTransaction().add(R.id.loading_text_fragment_container, yourFragment).commit();
In YourFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.your_fragment_layout, container, false);
}
And the your_fragment_layout.xml has a common TextView without any special attribute.
Hope it to be useful,
regards!
I think you are actually replacing the original fragment rather than overlaying it. You should create two framelayouts that cover the full screen and then assign the loading fragment to the overlaying frame layout
in you activity
<FrameLayout id="#+id/ListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<FrameLayout id="#+id/LoadingFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
and then to load them
FragmentTransaction transaction=manager.beginTransaction();
transaction.add(R.id.ListFragment, listFragment);
transaction.commit();
FragmentTransaction transaction=manager.beginTransaction();
transaction.add(R.id.LoadingFragment, loadingFragment);
transaction.commit();
I have an activity with the associated activity.xml code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/pattern_background"
android:orientation="vertical" >
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:clickable="false" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
...
<LinearLayout
android:id="#+id/llComments"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
</ScrollView>
<include
android:id="#+id/layoutComments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="#layout/widget_comentarios_fragment" >
</include>
In the LinearLayout with id llComments I introduce a fragment called CommentsFragment dynamically from the activity with the following code:
private Fragment commentsFragment;
private FragmentTransaction ft;
...
llComentarios = (LinearLayout) findViewById(R.id.llComments);
...
Bundle args = new Bundle();
args.putString(Constants.IDMODEL, getId());
commentsFragment = CommentsFragment.newInstance(args);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.llComments, commentsFragment).commit();
The Fragment associated xml file is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/comments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#color/transparent"
android:dividerHeight="10dp"
android:paddingLeft="#dimen/indicator_internal_padding"
android:paddingRight="#dimen/indicator_internal_padding" />
</LinearLayout>
The problem I cannot solve is to show in the activity more than one item (in fact I am showing one and a third items) in the list if I do not fix a height for the listview.It should adapt to as many items I add to the list in the fragment through the adapter. I have tried different combinations of heights in the layouts and views, but still does not work. Maybe I am annulating one with other.
Any help would be appreciated.
Thanks in advance
After some days I find out the exact problem. I was including a ListView into a ScrollView, and that's clearly not recomended by Android developers.
You can look for further info here: Why ListView cannot be used in a ScrollView?
Anyway, if you want to do it, you can do that with a hack. Take a look at these proposals:
How can I put a ListView into a ScrollView without it collapsing?
For me that worked. Problem solved.
I'm using supportlib v4 to reach master-detail flow.
Problem:
New instance of "details" fragment overlays the first one (xml created) instead replace it.
My Activity layout is:
<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"
android:orientation="horizontal"
tools:context=".TrackListActivity" >
<fragment
android:id="#+id/fragmentList"
android:name="pl.com.digita.BikeComputerUi.TrackList.TrackListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="#+id/fragmentTrack"
android:name="pl.com.digita.BikeComputerUi.TrackList.TrackInfoFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
Method called after click:
private void showDetails(long trackId){
View fragmentContainer = getActivity().findViewById(R.id.fragmentTrack);
TrackInfoFragment trackInfoFragment = TrackInfoFragment.newInstance(trackId);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(fragmentContainer.getId(), trackInfoFragment).commit();
}
Note: When you add a fragment to an activity layout by defining the fragment in the layout XML file, you cannot remove the fragment at runtime. If you plan to swap your fragments in and out during user interaction, you must add the fragment to the activity when the activity first starts, as shown in the next lesson.
Which is very last thing on http://developer.android.com/training/basics/fragments/creating.html
Here is solution - just need to change fragment to FrameLayout without loading it at activity creation:
<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"
android:orientation="horizontal"
tools:context=".TrackListActivity" >
<fragment
android:id="#+id/fragmentList"
android:name="pl.com.digita.BikeComputerUi.TrackList.TrackListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/details"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
Check following code it will work.
View fragmentContainer = ClassName.this.findViewById(R.id.fragmentTrack);
TrackInfoFragment fragment = new TrackInfoFragment();
getSupportFragmentManager().beginTransaction()
.replace(fragmentContainer.getId(), fragment).commit();
I am trying to create an activity with 2 Fragment
First fragment show a list of galleries using a LisFragment
Second fragment show the preview images of the gallery selected in the first fragment
When I declare the fragment in the view it works. But now I want to manage fragment dynamically :
GalleriesFragment gfs = new GalleriesFragment();
GalleryFragment gf = new GalleryFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.layout_m,gfs);
ft.add(R.id.layout_m,gf);
ft.commit();
My Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="#+id/layout_m">
</LinearLayout>
When doing this only the first fragment added is shown, I tried to invert their order when adding fragment...
When I was working on the layout I could set my fragment width with:
android:layout_width="400dp"
Now I have 2 questions :
How can I make my 2 fragments to display?
How can I set the width (programmatically?) of the 1st fragment and the second to fill the remaining width?
Thanks for your help!
PS:
GalleriesFragment doesn't have a layout and is not overriding onCreateView, but has an ArrayAdapter returning view like this for each rows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/idimage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10sp"
android:layout_marginLeft="10sp"
android:layout_marginTop="10sp"
android:contentDescription="preview"
>
</ImageView>
<LinearLayout
android:id="#+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/texttitre"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5sp"
android:layout_marginRight="7sp"
android:layout_marginTop="10sp"
android:background="#layout/roundcorner"
android:gravity="center"
android:text="Title here" >
</TextView>
<TextView
android:id="#+id/itemdescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10sp"
android:layout_marginRight="10sp"
android:text="description" >
</TextView>
</LinearLayout>
</LinearLayout>
GalleryFragment :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Gallery
android:id="#+id/gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Update 2 :
I added an onCreateView in my GalleriesFragment class :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FrameLayout.LayoutParams lparams = new FrameLayout.LayoutParams(400, LayoutParams.MATCH_PARENT);
container.setLayoutParams(lparams);
return super.onCreateView(inflater, container, savedInstanceState);
}
This fixes the first fragment's width, but the second one is still not showing...
How can I make my 2 fragments to display ?
Your current approach will make the first fragment supplied to the add method to take all the space of your container layout. One solution is to use a layout that reserves space for each of the two fragments that get added, something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_m"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="#+id/frame1"
android:layout_width="100dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/frame2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Then in code:
ft.add(R.id.frame1, gfs);
ft.add(R.id.frame2, gf);
ft.commit();
How can I set the width (programmatically ?)of the 1st fragment and
the second to fill the remaining width?
Fragments are not just ordinary views but one way to do that is to use your single LinearLayout layout file and set the LayoutParams of the fragment's view in onActivityCreated:
getView().setLayoutParams(new LinearLayout.LayoutParams(100, LinearLayout.LayoutParams.WRAP_CONTENT));
Of course this will make your fragments to be tied to the parent container, also I don't know how well this will work in the overall fragment system.