I am trying to display a nested ListFragment inside my DialogFragment.
Apparently I cannot just declare a <fragment> in the XML for my DialogFragment layout because fragments-in-fragments need the childFragmentManager. So I am trying to do this in my DialogFragment:
Fragment listfragment = new ClassThatExtendsListFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(????????, listfragment).commit();
I have absolutely no idea what resource ID I need to put in the ???????? section, or how I'd even go about assigning it.
simply add FrameLayout in you layout. suppose you gave it's id as "container",
Fragment exampleFragment = new ExampleFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container, exampleFragment).commit();
My requirement also was same like you. below code worked for me.
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyTripFragment myTripFragment = new MyTripFragment();
fragmentTransaction.add(R.id.fragment_container, myTripFragment);
fragmentTransaction.commit();
XML code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Hope it will help for you.
I'm not sure what type of layout you're using for your DialogFragment, but generally in the XML that DialogFragment inflates you need to add a FrameLayout and importantly give it an ID. Then when you do your fragment transaction you pass in the resource id of that FrameLayout
XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
If you want to use nested fragments you'll need to call getChildFragmentManager():
FragmentManager fragmentManager = getChildFragmentManager()
Then for your fragment transaction:
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, new MyFragment()).commit();
You might want to use the add method instead of replace, but thats up to you
You might also want to add the previous fragment to the backstack if you want the enable back button presses:
fragmentTransaction.replace(R.id.fragment_container, new MyFragment()).addToBackStack(null).commit();
Related
I have an issue please help me out. I am building an android application and I have successfully integrated Rewarded video ads to it.
I want to show a fragment or auto redirect to a specific fragment when the below condition is met:
#Override
public void onRewarded(RewardItem rewardItem) {
// I want to redirect the user to a particular fragment here.
}
So Please help me out, if there is any other way to achieve this then please let me know.
Use Fragment Manager and Fragment Transaction Manager for this.
getFragmentManager().beginTransaction().replace(R.id.your_framelayout_id, new your_fragment()).commit();
Write below code inside your onRewarded :
android.support.v4.app.Fragment fragment = new FragmentA();
android.support.v4.app.FragmentManager fragmentManager = getActivity()
.getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
Here fragment_container is a FrameLayout defined inside your Activity on which you want to host your fragment.
I am mentioning a sample activity with a framelayout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Below is a fragment Container" />
<FrameLayout
android:id="#+id/fragment_container"
android:layout_height="wrap_content"
android:layout_width="match_content" />
</LinearLayout>
Say I have an activity and there are two placeholder in the view:
<RelativeLayout>
<RelativeLayout id="fg_1" ...>
<RelativeLayout id="fg_2 ...>
</RelativeLayout>
Now once something happened I will add a fragment to the view by these codes:
private void showFragment(Fragment fragment, int id) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(id, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
For example, when I trigger action 1, the Fragment1 will show, when trigger action2 Fragment2 will show.
Now when I click the back menu, in my opinion, the Fragment2 will disappear, and when I click back menu again, the Fragment1 will disappear, and the app will exit once I click back menu again.
However the app will exit even I click the back menu once, it seems that the addToBackStack does not work as I expected.
Did I miss anything?
I would like to say that you have to replace with same container.
Here you have taken 2 Relative layout as container.
<RelativeLayout>
<RelativeLayout id="fg_1" ...>
<RelativeLayout id="fg_2 ...>
</RelativeLayout>
Which should be like
<RelativeLayout>
<RelativeLayout id="fg_1" ...>
</RelativeLayout>
Replace your fragment with 1 Relative layout ( fg_1 ) container.
Let me know for the same if any issue.
Hope it will help you.
Edit:
Make sure you are using same FragmentManager, same Fragment. Means I have faced same issue before 2 months that I have used android.app.FragmentManager in one class and and android.support.v4.app.FragmentManager in other class.
May be it would be help you.
Remove the addBackStack(null) method from your code. after click on back press to exit the app.
private void showFragment(Fragment fragment, int id)
{
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(id, fragment);
fragmentTransaction.commit();
}
I am writing an android app using ActionBarSherlock
My layout file is:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="#+id/fragment_menu"
android:layout_width="#dimen/menu_size"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/dummy"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Depending the category is selected in Menu fragment, I replace the fragment in dummy FrameLayout.Eg:
Bundle extras = new Bundle();
extras.putInt(ProgramDetailFrament.EXTRA_PROGRAM_ID, programId);
final ProgramDetailFrament fragment = ProgramDetailFrament.newInstance(extras);
getSupportFragmentManager().beginTransaction()
.replace(R.id.dummy, fragment)
.addToBackStack(null)
.commit();
getSupportFragmentManager().executePendingTransactions();
But the replaced fragment still receives touch/click event when I interact with the visible fragment. I don't know whether SherlockFragment is related to this issue?
I solved that by setting click event on the root layout of the visible fragment and do nothing in this event. But It seems a ugly solution.
Anyone knows how to solve it.
Thanks in advance.
As you state in your question, you're trying to replace a Fragment with another, so you should use the replace method of FragmentTransaction.
Here's roughly how to do it :
Bundle extras = new Bundle();
extras.putInt(ProgramDetailFrament.EXTRA_PROGRAM_ID, programId);
ProgramDetailFrament fragment = ProgramDetailFrament.newInstance(extras);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.id_of_fragment_container, fragment, DETAIL_FRAGMENT_TAG);
ft.commit();
I hope this helps ;-)
You actually need to use the replace function instead of add. What you're doing is adding a fragment on top of the other one, so you're creating a stack of fragments which are all still visible, only you don't see them because the top fragment covers all the other ones.
Use replace instead of add:
getSupportFragmentManager().beginTransaction()
.replace(R.id.dummy, fragment)
.addToBackStack(null)
.commit();
getSupportFragmentManager().executePendingTransactions();
This will remove all the other fragments in the dummy container and add the fragment you selected.
I'm defining an ID for my fragment in the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
...
Then I add this fragment in the activity's onCreate method:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment);
fragmentTransaction.commit();
This is all working fine. Replacing fragments and is also working.
Later I'm trying to retrieve this fragment by its ID in one of the activity's methods:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Doing so leads to myFragment being null. Always.
When I try to do the same with tags instead of IDs I can retrieve the fragment by its tag without any problems:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment, "testfragment");
fragmentTransaction.commit();
...
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentByTag("testfragment");
Why can't findFragmentById find the fragment, but findFragmentByTag does so? Am I missing something?
R.id.test_fragment is not the ID of your fragment but the id of your LinearLayout
Calling add(int containerViewId, Fragment fragment) will add a fragment without a tag.
So or you use add(int containerViewId, Fragment fragment, String tag) and you get back your fragment using your tag (as an ID)
Use the <FrameLayout> tag as a container in your layout file. Later to replace the fragments from your activity dynamically, you can use the ID of the <FrameLayout> container to replace the fragments in your activity.
<FrameLayout
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
it should be a fragment not a LinearLayout
<fragment android:name="com.example.yourfragment"
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I was using android.support.v4.app.Fragment in my layout while calling getFragmentManager() which actually searched for android.app.Fragment subclasses and I got null.
So the fix was to call getSupportFragmentManager() instead.
In general make sure the package of a fragment you are subclassing and using in your layout is the same returned by the corresponding FragmentManager which performs search.
Or, you should have instead used :
(MyFragment) getFragmentManager().findFragmentById(R.id.fragment_container);
R.id.test_fragment is your LinearLayout ID not your Fragment.
You can define and id on a fragment when it is inflated from an xml like in this sample http://developer.android.com/guide/topics/fundamentals/fragments.html#Adding
The reasons mentioned above are valid but another possible reason is that you are trying to search for the fragment while being in a fragment this also results in fragmentManager.findFragmentById to return null. We should use childFragmentManager.findFragmentById to find the fragment inside a fragment.
According to the official documentation.
public final androidx.fragment.app.FragmentManager getChildFragmentManager()
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.
FragmentB fragmentB =
(FragmentB) getSupportFragmentManager().findFragmentById(R.id.containerb);
if(fragmentB != null)
{
fragmentB.showuserResponse(msg);
}
Use container id as fragment id. And then check for null reference.
fragmentTransaction.add(R.id.fragment_container, myFragment);
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Please notice the difference.
You should pass R.id.fragment_container as the argument to findFragmentById, as you pass it to the add function, instead of R.id.test_fragment
By the way , according to the inner implementation of the two functions, it should be right that the id can be
that of its container view.
I built an activity which takes data from a rss file and shows them on a ListFragment; this is how I defined it on the layout file:
<fragment
android:id="#+id/news_list_fragment"
android:name="com.thecoffeedrinker.theforcereader.NewsListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/header_layout" />
It might happen that there is no connection available; this case I want the application to show a layout to warn the user about it, to be shown in the same layout area of the list. What's the best thing to do to achieve this? Should I create a "disconnected fragment" class and replace an instance with the list on the same activity? Should I load this layout within the List Fragment class? I tried to replace it but when I resume the activity it crashes...why is that? Thanks for your replies.
To Replace one Fragment with Another
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Adding new Fragment
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();