Twentyonehundred
Twentyonehundred

Reputation: 2239

Managing Fragments Correctly

I am having some difficulty correctly using and managing fragments in my project.

I am starting with this Android Developers project as a basis.

The mainactivity extends SampleActivityBase and starts a simple fragment:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    SlidingTabsBasicFragment fragment = new SlidingTabsBasicFragment();
    transaction.replace(R.id.sample_content_fragment, fragment);
    transaction.commit();
}

The SlidingTabsbasicFragment class extends Fragment and returns a layout onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_sample, container, false);
}

Then in another class that extends PagerAdapter, the content of the view based on the position is altered:

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        // Inflate a new layout from our resources
        View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item,
                container, false);
        // Add the newly created View to the ViewPager
        container.addView(view);

        // Retrieve a TextView from the inflated View, and update it's text
        TextView title = (TextView) view.findViewById(R.id.item_title);
        title.setText(String.valueOf(position + 1));

        Log.i(LOG_TAG, "instantiateItem() [position: " + position + "]");

        // Return the View
        return view;
    }

This gives me the basic tab functionality that I am looking for. I have even change the layout by inflating a new one based on the position okay. But now I am attempting to implemented a custom calendar called Caldroid.

The main class here extends FragmentActivity. This allows it to setContentView and use FragmentTransaction and .replace to change a layout with an ID into a fragment with the custom calendar on it:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy");

    // Setup caldroid fragment
    // **** If you want normal CaldroidFragment, use below line ****
    caldroidFragment = new CaldroidFragment();

    // //////////////////////////////////////////////////////////////////////
    // **** This is to show customized fragment. If you want customized
    // version, uncomment below line ****

// caldroidFragment = new CaldroidSampleCustomFragment();

    // Setup arguments

    // If Activity is created after rotation
    if (savedInstanceState != null) {
        caldroidFragment.restoreStatesFromKey(savedInstanceState,
                "CALDROID_SAVED_STATE");
    }
    // If activity is created from fresh
    else {
        Bundle args = new Bundle();
        Calendar cal = Calendar.getInstance();
        args.putInt(CaldroidFragment.MONTH, cal.get(Calendar.MONTH) + 1);
        args.putInt(CaldroidFragment.YEAR, cal.get(Calendar.YEAR));
        args.putBoolean(CaldroidFragment.ENABLE_SWIPE, true);
        args.putBoolean(CaldroidFragment.SIX_WEEKS_IN_CALENDAR, true);

        // Uncomment this to customize startDayOfWeek
        // args.putInt(CaldroidFragment.START_DAY_OF_WEEK,
        // CaldroidFragment.TUESDAY); // Tuesday
        caldroidFragment.setArguments(args);
    }

    setCustomResourceForDates();

    // Attach to the activity
    FragmentTransaction t = getSupportFragmentManager().beginTransaction();
    t.replace(R.id.calendar1, caldroidFragment);
    t.commit();

What I am trying to achieve is retaining my tabbed layout, and generating the custom calendar inside only one of the tabs. I'd appreciate any direction / help / resources or alternative suggestions.

I've included some code snippets, but both projects exist (more or less) as originals:

SlidingTabsBasic Caldroid

Thanks for any help anyone can provide.

*(1) Added PagerAdapter as requested: (From what I've seen, people say not to mess around with instantiateItem?)

class SamplePagerAdapter extends PagerAdapter {

@Override
public int getCount() {
    return 3;
}

@Override
public boolean isViewFromObject(View view, Object o) {
    return o == view;
}

@Override
public CharSequence getPageTitle(int position) {
    switch(position) {
        case 0:
            return "Item 1";
        case 1:
            return "Item 2";
        case 2:
            return "Item 3";
    }
    return "Item " + (position + 1);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {

    // Inflate a new layout from our resources
    View view = null;
    if(position==2) {
        view = getActivity().getLayoutInflater().inflate(R.layout.item_1, container, false);
        container.addView(view);
    } else if(position==0) {
        view = getActivity().getLayoutInflater().inflate(R.layout.item_2, container, false);
        container.addView(view);
    } else {
        view = getActivity().getLayoutInflater().inflate(R.layout.item3, container, false);
        container.addView(view);
    }

    Log.i(LOG_TAG, "instantiateItem() [position: " + position + "]");

    // Return the View
    return view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    Log.i(LOG_TAG, "destroyItem() [position: " + position + "]");
}

}

Upvotes: 0

Views: 555

Answers (1)

Xaver Kapeller
Xaver Kapeller

Reputation: 49837

What you need to do is use a FragmentStatePagerAdapter instead of PagerAdapter. You essentially only need to define how many Tabs you have and which Fragment belongs in each Tab:

private class ExampleAdapter extends FragmentStatePagerAdapter {

    public ExampleAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {

        // Return the correct Fragment for each Tab 
        // The position corresponds to the position of the Tab
        // So the first Tab has a position of 0, the second Tab has a position of 1...
        switch (position) {

            case 0:
                return new Fragment1();

            case 1:
                return new Fragment2();

            case 2:
                return new Fragment3();

            default: 
                return null;
        }
    }

    @Override
    public int getCount() {
        return 3; // 3 Fragments in this example
    }
}

So this is the most basic implementation of a FragmentStatePagerAdapter and it is all you need to get it to work. I have not tested it but if necessary you should still be able to override getPageTitle() like before.

Upvotes: 1

Related Questions