How to return multiple fragments from FragmentPagerAdapter - android

If I use a TabLayout with FragmentPagerAdapter, the overridden function getItem(int position) just return one fragment. In case of lager screen I would like to have 2 fragments to be returned.
How can I do it? should wrap these 2 fragments into one fragment and use that instead or is there any better solution?
FragmentPagerAdapter:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: //Ingredients
return IngredientsFragment.newInstance(mRecipe);
case 1: // Details
{
// TODO Here instead of DetailFragment I want to return
// two fragments called DetailFragment and StepFragment.
return DetailFragment.newInstance(mRecipe);
}
default:
throw new RuntimeException(this.toString() + " Wrong fragment!");
}
}
And then in my Activity onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
// Initializing, etc.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}

I do not see you have much of a wiggle room here.
These two options are exlusive:
You are returning one Fragment with two nested fragments (Wrapped fragment)
You are returning two fragments each anchored to his own tab.
If you would like two fragments to appear on singular page of ViewPager, you have no choice but to wrap them.
Otherwise swiping would go between these two fragments, which is the same as if they are completely different, that is non-correlated.

OK I managed to solve the problem using a Fragment consist of two other fragments as children.
Just do not forget in this case the FragmentManager object should be populated with getChildFragmentManager() to work properly.
For more info look at my BakingApp project DetailStepWideScreenFragment.java
GitHub Repos
Fragment Wrapper:
public class DetailStepWideScreenFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_detail_step_wide_screen, container, false);
// I added the fragments here. StepFragment can be replaced using
// replaceStepFragment function.
DetailFragment detailFragment = DetailFragment.newInstance(mRecipe);
StepFragment stepFragment = StepFragment.newInstance(mRecipe, mStepId);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.fl_detail_fragment_wide_screen, detailFragment);
transaction.add(R.id.fl_step_fragment_wide_screen, stepFragment);
transaction.commit();
return view;
}
public void replaceStepFragment(String stepId) {
mStepId = stepId;
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
StepFragment stepFragment = StepFragment.newInstance(mRecipe, mStepId);
transaction.replace(R.id.fl_step_fragment_wide_screen, stepFragment);
transaction.commit();
}
}
PagerAdapter:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private DetailStepWideScreenFragment currentFragment;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
currentFragment = null;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: //Ingredients
return IngredientsFragment.newInstance(mRecipe);
case 1: // Details
{
// Show base on screen size.
if (mIsLargeScreen) {
DetailStepWideScreenFragment detailStepWideScreenFragment = DetailStepWideScreenFragment.newInstance(mRecipe, "0");
currentFragment = detailStepWideScreenFragment;
return detailStepWideScreenFragment;
} else {
return DetailFragment.newInstance(mRecipe);
}
}
default:
throw new RuntimeException(this.toString() + " Wrong fragment!");
}
}
#Override
public int getCount() { return 2; }
public DetailStepWideScreenFragment getCurrentFragment() {
return currentFragment;
}
}

Related

How to set different layouts for different fragments which is embedded inside a tab view in android

I'm currently trying to create a tabView where each tab opens a different layout. I'm using android.support.design.widget.TabLayout and I successfully linked it with pagerView using an adapter. Now inside myFragment class if I call onCreateView and inflate a layout, the layout (fragment_main) is displayed in all tabs.
public static class MyFragment extends Fragment {
public MyFragment() {
}
public static MyFragment newInstance(int pageNumber) {
MyFragment myFragment = new MyFragment();
return myFragment;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,false);
return rootView;
}
}
I have 3 fragments connecting 3 tabs. Now how to set different layout for each fragment.
My adapter class is
class MyPagerAdapter extends FragmentStatePagerAdapter {
String[] tabs;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
tabs=getResources().getStringArray(R.array.tabs);
}
#Override
public Fragment getItem(int position) {
NavigationActivity.MyFragment myFragment = NavigationActivity.MyFragment.newInstance(position);
return myFragment;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return tabs[position];
}
}
You are passing same fragment for all the position in the below method, which is causing the problem,
#Override
public Fragment getItem(int position) {
NavigationActivity.MyFragment myFragment = NavigationActivity.MyFragment.newInstance(position);
return myFragment;
}
For solution you have to return different Fragments for different position or at least with different layout.
ArrayList< Fragment > tabFragments = new ArrayList<Fragment>();
fragments.add(new FragmentA());
fragments.add(new FragmentB());
fragments.add(new FragmentC());
#Override
public Fragment getItem(int position) {
return tabFragments.get(position);
}
Again,
I found the below mentioned blog as very useful. Each steps is described there. It is using TabListener. If the implementation is not certainly the same which you are looking for but you may get a good overview,
Android Fragment Tabs Example:
http://examples.javacodegeeks.com/android/core/app/fragment/android-fragment-tabs-example/
In your getItem() method write,
Fragment frgmt = null;
switch (position) {
case 0:
frgmt = new fragment1(Context);
break;
case 1:
frgmt = new fragment2(Context);
break;
case 2:
frgmt = new fragment3(Context);
break;
default:
break;
}
return frgmt;
Then create these fragment and their respective layouts.
please go to this i think this could help you out---- https://codeload.github.com/culmor30/android-fragments-example/zip/master

Android tabs implemented with Fragments and ViewPager

My application has 3 tabs, each represented by Fragments. There is a custom FragmentPagerAdapter which also implements ActionBar.TabListener. Initially my FragmentPagerAdapter was returning new instances of fragments in public Fragment getItem(int index) method. Also, my TabListener implementation was instantiating Fragments and showing/hiding them in the onTabSelected/onTabUnselected. Unfortunately this approach doesn't fit me well, because in this case each Fragment is actually created twice. What I want is to create it once and then just hide/show, when necessary.
For that I have instantiated my fragment earlier in the activity and passed them to the PagerAdapter:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tabs_layout);
List<Fragment> fragments = initTabFragments();
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final ActionBar actionBar = getSupportActionBar();
TabsPagerAdapter pagerAdapter = new TabsPagerAdapter(this, getSupportFragmentManager(), fragments, viewPager);
viewPager.setAdapter(pagerAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (int tab_name : tabs) {
Tab tab = actionBar.newTab();
actionBar.addTab(tab.setText(tab_name).setTabListener(pagerAdapter));
}
...
}
private List<Fragment> initTabFragments() {
List<Fragment> fragments = new ArrayList<Fragment>(3);
fragments.add(SherlockFragment.instantiate(this, TabFragment1.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment2.class.getName()));
fragments.add(SherlockFragment.instantiate(this, TabFragment3.class.getName()));
return fragments;
}
Then in the PagerAdapter I just return fragment:
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
To handle Tab selection there is the following code:
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
int position = tab.getPosition();
String tag = "android:switcher:" + viewPagerId + ":" + position;
Fragment fragment = context.getSupportFragmentManager().findFragmentByTag(tag);
switch (position) {
case 0:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(0), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(0));
}
break;
}
case 1:
if (fragment == null) {
ft.add(viewPagerId, fragments.get(1), tag);
} else {
// If it exists, simply attach it in order to show it
ft.show(fragments.get(1));
}
break;
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()) {
case 0:
ft.hide(fragments.get(0));
break;
case 1:
ft.hide(fragments.get(1));
break;
}
}
In this case each fragment is instantiated once. And the first tab is shown correctly, but when I switch between tabs second and third tabs are empty (just white background). Why?
I was trying to add fragment to a container android.R.id.content, but exception was thrown: Can't change container ID of fragment.... I found out that it is because when Fragment is returned in getItem method it is added to a viewPager container. That why I use viewPagerId when add fragment to a transaction.
Any help would be greatly appreciated.
Have a ExampleFragment class defined that extends Fragment. Something like shown below
public class ExampleFragment extends Fragment {
private View categoryView;
private ViewPager mViewPager;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
categoryView = inflater.inflate(R.layout.viewpager, container, false);
mViewPager = (ViewPager) categoryView.findViewById(R.id.pager);
return categoryView;
}
public ViewPager returnViewPager() {
return mViewPager;
}
}
main_fragment.xml
<?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="fill_parent"
android:layout_height="wrap_content"
tools:context=".ExampleFragmentActivity" >
<fragment
android:id="#+id/main_fragment"
android:name="somepackage.ExampleFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And then add this in the onCreate() of ExampleFragmentActivity
ExampleFragment fragment = (ExampleFragment) getSupportFragmentManager().findFragmentById(R.id.main_fragment);
mViewPager = fragment.returnViewPager();
fragmentManager = getSupportFragmentManager();

FragmentTransaction with FragmentPagerAdapter

Im using a FragmentPagerAdapter to manage 3 Fragments.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
Fragment fragment = new Fragment();
switch (position) {
case 0:
return fragment = new Latest();
case 1:
return fragment = new MySets();
case 2:
return fragment = new MyPictures();
default:
break;
}
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
//SET TITLE OF TABS
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1_latest).toUpperCase(l);
case 1:
return getString(R.string.title_section2_mysets).toUpperCase(l);
case 2:
return getString(R.string.title_section3_allpictures).toUpperCase(l);
}
return null;
}
}
All Fragements extend Fragment. To handle Click Events and a Custom Layout Im using a Adapter which extends BaseAdapter.
My Goal is to replace Fragment 2 through another Fragment. Is it correct that I have to add all Fragments with FragmentTransaction to replace them later?
But how can i dynamically add the fragments to use FragmentTransaction? Is there a way to add them at the getItem(int position) or is that the wrong way to go?
Edit
If you need the Fragment as soon as the app is launched then the approach you used above in getItem() is okay, you don't need to do the transaction from there.
If you want to replace the Fragment later on simply use the getSupportFragmentManger and a transaction in the Fragment.
NewFragment newFrag = new NewFragment();
FragmentTransaction transaction = getActivity()
.getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.your_fragment_container_id, newFrag);
transaction.addToBackStack(null);
transaction.commit();

Android: ViewPager - adding Fragments

I am trying to add a ViewPager, but I am am having problems adding new fragments. I followed a tutorial to create it where the on each swipe the SAME fragment was used with only a TextView in the fragment changing changing.
The fragment that works is called MyFragment. ( I don't know why this works and the others don't.
I don't want to use this fragment as I have different fragments that I have already made (that work fine). I want to add for example a fragment called ReminderFragment
I tried adding a switch and case to the getItem() method, but I get an error saying: "Type mismatch: cannot convert from name of fragment to Fragment".
This is the code of my FragmentActivity - it holds the FragmentPagerAdapter inside it (I don't know if this is a good way or not):
// Removed imports, package name
public class PageViewActivity extends FragmentActivity {
MyPageAdapter pageAdapter;
private ViewPager pager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_pager_activity); // Sets the layout to an xml which includes a viewpager
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
pager = (ViewPager)findViewById(R.id.viewpager);
pager.setAdapter(pageAdapter);
pager.setCurrentItem(1);
pager.setPageTransformer(true, new ZoomOutPageTransformer());
}
#Override
public void onBackPressed() {
if (pager.getCurrentItem() == 1) {
super.onBackPressed();
} else if (pager.getCurrentItem() == 0){
pager.setCurrentItem(pager.getCurrentItem() + 1);
}
else if (pager.getCurrentItem() == 2){
pager.setCurrentItem(pager.getCurrentItem() - 1);
}
}
private List<Fragment> getFragments(){
List<Fragment> fList = new ArrayList<Fragment>();
// I don't know how to change this to work with my fragments
fList.add(MyFragment.newInstance("Page 0")); // MyFragment is the fragment I don't need, but it is the only fragment that works!
fList.add(MyFragment.newInstance("Page 1"));
fList.add(MyFragment.newInstance("Page 2"));
return fList;
}
private class MyPageAdapter extends FragmentPagerAdapter { // Sets what MyPagerAdapter is
private List<Fragment> fragments; // Defines a list of fragments called fragments
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) { // Sets what is inside the MyPagerAdapter
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int index) {
// return this.fragments.get(index);
switch (index){
case 0: return new ReminderFragment(); // This is where I get errors
case 1: return new QuickNoteFragment();
}
}
#Override
public int getCount() {
return this.fragments.size();
}
}
}
This is the code of the ReminderFragment. This does not work as I get the error above
// Removed stuff
public class ReminderFragment extends Fragment implements OnClickListener{
public static final String ARG_nOTERACTIVITY_NUMBER = "noter_activity";
// Removed stuff
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View remView = inflater.inflate(R.layout.reminder, container, false);
int i = getArguments().getInt(ARG_nOTERACTIVITY_NUMBER);
String noter_activity = getResources().getStringArray(
R.array.noter_array)[i];
// Removed stuff
getActivity().setTitle(noter_activity); // For navigation drawer(?)
return remView;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()) {
case R.id.***: // Does stuff
case R.id.***:
break;
}
}
}
public static Fragment newInstance() { // Is this necessary
// TODO Auto-generated method stub
ReminderFragment remFrag = new ReminderFragment();
return remFrag;
}
}
I know there are two methods of adding the fragments here - I just trying to show what I have tried :-). I am very confused!
Thank you
Looks that you imported Fragments from the support package in all the class. The import should be android.support.v4.app.Fragment or android.app.Fragment (if you are targeting API level 11) in all the class

Android: "Navigation Type: Fixed Tabs + Swipe"

I'm trying to use Tabs + Swipe in an App and want to use the Navigation Type "Fixed Tabs + Swipe" which the ADT provides me when creating an Activity.
Sooo now the ADT spits out nice Code, which I slightly modified...
I completely understand the code and what's going on... But how can I teach the App to use my three Fragments instead of the stupid Dummy Frag? :(
I cannot find any tutorial which deals with the ADTs "Navigation Types"...
Thanks for your help!
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
//Adding Tabs
actionBar.addTab(actionBar.newTab().setText("Tab 1").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Tab 2").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Tab 3").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy,container, false);
TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}
a switch-case to set the fragments is easy and makes it really clear. Let each of your fragment inflate the root view in your xml
#Override
public Fragment getItem(int index) {
Fragment fragment = null;
switch(index){
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
case 2:
fragment = new Fragment3();
break;
default:
break;
}
//set args if necessary (which it isn't?)
Bundle args = new Bundle();
args.putInt(ObjectFragment.ARG_OBJECT, index + 1);
fragment.setArguments(args);
//return fragment
return fragment;
}
But how can I teach the App to use my three Fragments instead of the stupid Dummy Frag?
You will notice that DummySectionFragment is referenced in getItem() of the SectionsPagerAdapter:
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
If you want to use different fragments, modify getItem() to return the fragment you want, given the supplied position (0-based page number).

Categories

Resources