Reputation: 6799
Docs say you shouldn't nest fragments 'cause they are designed to work another way. But!
But what if I use ViewPager and it's fragment (visible screen) should be constructed from other fragments. Let's say we have a messenger app. On the main screen there's a ViewPager with fragment called "Last messages" (MessagesFragment) and on the submain screen (let's say Discussion or Chat room) we also have a ViewPager but Messages screen consists of MessagesFragment, NewMessageBarFragment and e.g. header fragment with other info.
One can say we shouldn't use ViewPager for that and we can use ViewFlow open source library but believe me the code, holded in such activity is a mess even with fragments. Also there's an approach to fill extra layouts, not fragments for NewMessageBar and HeaderInfo within MessagesFragment — but it's double ugly as for me.
Is it OK to use nested fragments in this particular situation? What would you recommend?
Sometimes it's really 'must have' feature. But! In most cases I would recommend follow 'responsive design' way: http://www.slideshare.net/kirillcool/responsive-mobile-design-in-practice
Upvotes: 1
Views: 4938
Reputation: 2735
Here is my solution. Now you can user getChildFragmentManager from fragment. It is included in new SupportLibrary. In my production solution I first test if fragments exist and add them only when necessary.
public class TestActivity extends SherlockFragmentActivity {
private ViewPager mPager;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.pager);
mPager = (ViewPager) findViewById(R.id.viewPager);
mPager.setAdapter(new TestAdapter(getSupportFragmentManager()));
}
public class TestAdapter extends FragmentStatePagerAdapter {
public TestAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(position);
}
@Override
public int getCount() {
return 4;
}
}
public static class TestFragment extends SherlockFragment {
private static final int ID = 9129345;
private static final String ARG_INDEX = "TestFragment.pageindex";
public static TestFragment newInstance(int page) {
TestFragment fragment = new TestFragment();
Bundle args = new Bundle();
args.putInt(ARG_INDEX, page);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.root_container, null);
int pageId = getArguments().getInt(ARG_INDEX);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.live_radio, TextFragment.newInstance("PAGE", pageId + 1));
transaction.add(R.id.breaking_news, TextFragment.newInstance("TEXT", 1));
transaction.add(R.id.main_container, TextFragment.newInstance("TEXT", 2));
transaction.commit();
return view;
}
}
public static class TextFragment extends SherlockFragment {
private static final String ARG_INDEX = "TextFragment.index";
private static final String ARG_TEXT = "TextFragment.text";
public static TextFragment newInstance(String text, int index) {
TextFragment fragment = new TextFragment();
Bundle args = new Bundle();
args.putString(ARG_TEXT, text);
args.putInt(ARG_INDEX, index);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView textView = new TextView(getActivity());
textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
textView.setText(getArguments().getString(ARG_TEXT) + " " + getArguments().getInt(ARG_INDEX));
return textView;
}
}
}
Main Layout with viewpager
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/player"
android:layout_alignParentTop="true" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
Fragment layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/live_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/breaking_news"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
Upvotes: 1
Reputation: 83311
A quick update:
Nested Fragment
s were officially introduced in Android API version 17.
Upvotes: 5
Reputation: 1007554
But what if I use ViewPager and it's fragment (visible screen) should be constructed from other fragments.
Don't do that.
Is it OK to use nested fragments in this particular situation?
What would you recommend?
Replace your "outer" fragments with simple layouts. Then use some other PagerAdapter
implementation that does not itself require a fragment (as does the FragmentPagerAdapter
interface). You may need to pinch some code from FragmentPagerAdapter
to make sure this all works well.
Or, combine "MessagesFragment, NewMessageBarFragment and e.g. header fragment with other info" into a single fragment for use on screen sizes where you want to have this pager behavior. This may result in some amount of code duplication, to have that portion of the UI broken out separately for smaller screen sizes.
Upvotes: 2