1

I've looked at so many questions here that I don't even know exactly what I'm looking for.

I have a simple app that uses a ViewPager. It has 3 tabs and there is a fragment for each tab. The first fragment contains a ListView. I want to be able to click on an element in the ListView and have that bring me to a different fragment.

So basically I want to remove the fragment that contained the ListView once an element is clicked and add in a new fragment. I've tried to do this in a few different ways with none working.

The last thing I tried was to edit the TabsPageAdapter once an element was clicked which pretty much works except when I press the back button it exits the app. Also it doesn't seem like the cleanest way of doing this.

TabsPagerAdapter

public class TabsPagerAdapter extends FragmentStatePagerAdapter {

SherlockFragment mf;
TalkingPointsFragment tpf;
ContactFragment gf;
int mode = 0; 

public TabsPagerAdapter(FragmentManager fm) {
    super(fm);
    mf = new CanvassFragment();
    tpf = new TalkingPointsFragment();
    gf = new ContactFragment();
}

public TabsPagerAdapter(FragmentManager fm, int mode)
{
    super(fm);
    if(mode == 0)
    {
    mf = new CanvassFragment();
    tpf = new TalkingPointsFragment();
    gf = new ContactFragment();
    }
    else if(mode == 1)
    {
        mf = new ContactFragment();
        tpf = new TalkingPointsFragment();
        gf = new ContactFragment();
    }
}

@Override
public SherlockFragment getItem(int index) {

    switch (index) {
    case 0:
        return mf;
    case 1:
        return tpf;
    case 2:
        return gf;
    }

    return null;
}

@Override
public int getCount() {
    // get item count - equal to number of tabs
    return 3;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object)
{

}
}

The onclick code:

ViewPager viewp = (ViewPager) getActivity().findViewById(R.id.pager);
TabsPagerAdapter mAdapter = new TabsPagerAdapter(getActivity().getSupportFragmentManager(),1);

viewp.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();

layout_main.xml

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:actionBarTabStyle="@drawable/actionbar_tab_indicator">

PriestVallon
  • 1,519
  • 1
  • 22
  • 44

2 Answers2

0

I FragmentStatePagerAdapter too and when a user selects map from the ActionBar, I add the GoogleMapsFragment on top of the FragmentStatePagerAdapter:

        // create a new map
        mapsFragment = GoogleMapFragment.newInstance();
        // Then we add it using a FragmentTransaction.
        FragmentTransaction fragmentTransaction = getSupportFragmentManager()
                .beginTransaction();
        fragmentTransaction.add(android.R.id.content, mapsFragment,
                FRAGMENT_MAP_TAG);
        fragmentTransaction.commit();

For your case you would probably need to add it to the backstack too, which I have not because in my app the user has to navigate back using the ActionBar.

Thought this approach could work for you too when a user selects an item from your list.

Of course this has the disadvantage of not being able to use the FragmentStatePagerAdapter until the user navigates back. So I am not sure wether that would be acceptable for your app.

cYrixmorten
  • 7,110
  • 3
  • 25
  • 33
  • I tried this method but I didn't know what to put in where you have 'android.R.id.content'. I've added my layout_main.xml to the question. – PriestVallon Nov 01 '13 at 23:05
  • explanation for android.R.id.content: http://stackoverflow.com/questions/7776768/android-what-is-android-r-id-content-used-for. Meant for the code to be executed inside you main Activity holding the viewpager – cYrixmorten Nov 01 '13 at 23:15
  • The above solution just adds the new fragment over the existing one. So both fragments are shown at once. – PriestVallon Nov 01 '13 at 23:31
  • Yes it does, that is also why I was unsure if it would fit your case, sounded as if you wanted to show, say, detailed information regarding the clicked item. Then it would make sense to me that one would have to navigate back afterwards. – cYrixmorten Nov 01 '13 at 23:41
  • Can you post the full implementation of TabsPagerAdapter ? Think I might have yet another suggestion if you do. – cYrixmorten Nov 01 '13 at 23:56
0

Ok, so this took a bit more code that I imagined. Hope you get the idea:

public class MainClass extends FragmentActivity implements CanvassCallback {

// save a single reference to ViewPager and TabsPagerAdapter
private ViewPager mViewPager;
private TabsPagerAdapter mAdapter;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.mViewPager = (ViewPager) findViewById(R.id.pager);
    this.mAdapter = new TabsPagerAdapter(getSupportFragmentManager(), this);
    mViewPager.setAdapter(mAdapter);

    ...
}

// from the CanvassCallback interface
public void itemSelected() {
    mAdapter.canvassSelected();
    mAdapter.notifyDataSetChanged();
}

    @Override
public void onBackPressed() {
    if (mViewPager.getCurrentItem() == 0 && mAdapter.isCanvassSelected() {
        mAdapter.canvassSelected();
        mAdapter.notifyDataSetChanged();
            }
            else {
                super.onBackPressed();
            }
}

}

Mockup of your CanvassFragment showing the callback

public class CanvassFragment extends SherlockFragment {

public interface CanvassCallback {
    public void itemSelected();
}

private CanvassCallback canvassCallback;

public void setCanvassCallback(CanvassCallback canvassCallback) {
    this.canvassCallback = canvassCallback;
}

...

// The onClick of your item
private void onClick() {
    // notify your activity that an item was selected
    canvassCallback.itemSelected();
}
}

The registeredFragments are not strictly needed but I think it provides some value if your need to call methoods on your Fragment from activity.

public class TabsPagerAdapter extends FragmentStatePagerAdapter {

// see upvoted answer from http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

private boolean canvassSelected = false; 

private CanvassCallback canvassCallback;

public TabsPagerAdapter(FragmentManager fm, CanvassCallback canvassCallback) {
    super(fm);
    this.canvassCallback = canvassCallback;
}

public void canvassSelected() {
    canvassSelected = !canvassSelected;
}

    public boolean isCanvassSelected() {
            return canvassSelected;
    }

@Override
public SherlockFragment getItem(int index) {

    switch (index) {
    case 0:
        if (canvassSelected) 
            return new ContactFragment();

        CanvassFragment canvassFragment = new CanvassFragment();
        // this ensures that your Activity gets notified when an item is clicked
        canvassFragment.setCanvassCallback(canvassCallback);
        return canvassFragment;
    case 1:
        return new TalkingPointsFragment();
    case 2:
        return new ContactFragment();
    }

    return null;
}

@Override
public int getCount() {
    // get item count - equal to number of tabs
    return 3;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Log.d(TAG, "instantiateItem " + position);
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    registeredFragments.put(position, fragment);
    return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Log.d(TAG, "destroyItem " + position);
    registeredFragments.remove(position);
    super.destroyItem(container, position, object);
}

}
cYrixmorten
  • 7,110
  • 3
  • 25
  • 33
  • Where is canvassCallback initialized in the Fragment? – PriestVallon Nov 02 '13 at 01:03
  • 1
    It is set at TabsPagerAdapter(getSupportFragmentManager(), this) in onCreate where 'this' refers to your Activity which implements CanvassCallback – cYrixmorten Nov 02 '13 at 01:08
  • I'm getting a NullPointerException in the instantiateItem method. In particular on the line this line: Fragment fragment = (Fragment) super.instantiateItem(container, position); – PriestVallon Nov 02 '13 at 01:32
  • Perhaps there is an issue since you use SherlockFragment. Try and remove instantiateItem and destroyItem as they are not needed, was simply to show the possibility of keeping the fragments easy to get a hold on from Activity. – cYrixmorten Nov 02 '13 at 01:35