user3155208
user3155208

Reputation: 301

Change fragment visibility in runtime when the fragment was created using FragmentPagerAdapter

I'm trying to create my first Android app that looks like following: there is main activity with multiple fragments initialized by FragmentPagerAdapter. There is another activity (SettingsActivity) where I want to list all the fragment names and allow hiding some of them. To hide them I want to use the following:

FragmentManager fm=getFragmentManager();
Fragment myFragment=fm.findFragmentByTag("tag");
fm.beginTransaction().hide(myFragment).commit();

The problem is that I don't know fragment id or tag, not sure if they exist. How I can get them? Should I switch to XML definition to make it possible?

Adapter:

public class TabsPagerAdapter extends FragmentPagerAdapter {

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

@Override
public Fragment getItem(int index) {
    switch (index){
    case 0:
        return new CoverFragment();
    case 1:
        return new NumbersConverterFragment();
    case 2:
        return new TempConverterFragment();
    case 3:
        return new LengthConverterFragment();
    case 4:
        return new AreaConverterFragment();
    case 5:
        return new VolumeConverterFragment();
    case 6:
        return new WeightConverterFragment();
    case 7:
        return new SpeedConverterFragment();
    }
    return null;
}

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

Main activity:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {

private ViewPager viewPager;
private TabsPagerAdapter tabsPagerAdapter;
private ActionBar actionBar;

@Override
protected void onCreate(Bundle savedInstanceState) {

   String[] tabs={getString(R.string.title_section0), getString(R.string.title_section1),getString(R.string.title_section2)};

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    viewPager=(ViewPager) findViewById(R.id.pager);
    actionBar=getActionBar();
    tabsPagerAdapter=new TabsPagerAdapter(getSupportFragmentManager());

    viewPager.setAdapter(tabsPagerAdapter);
    actionBar.setHomeButtonEnabled(false);
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    for(String tab : tabs){
    actionBar.addTab(actionBar.newTab().setText(tab).setTabListener(this));
    }


    viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }
     ...
    });

}

Fragment layout:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#fbfdfb"
    >


     <TextView android:text="@string/celsius_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtCelsius" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>

    <TextView android:text="@string/fahrenheit_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtFahrenheit" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>

    <TextView android:text="@string/kelvin_" android:id="@+id/textView1" 
      android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
    <EditText android:text="" android:id="@+id/txtKelvin" android:layout_width="match_parent" 
      android:layout_height="wrap_content"></EditText>    

 </LinearLayout>

Fragment class:

public class TempConverterFragment extends Fragment {

EditText txtCelsius, txtFahrenheit, txtKelvin;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.temp_converter_fragment, container, false);

    txtCelsius = (EditText) rootView.findViewById(R.id.txtCelsius);
    txtFahrenheit = (EditText) rootView.findViewById(R.id.txtFahrenheit);
    txtKelvin = (EditText) rootView.findViewById(R.id.txtKelvin);
      ...
     }
  ...
}

Thanks in advance.

Upvotes: 1

Views: 984

Answers (1)

cYrixmorten
cYrixmorten

Reputation: 7108

If SettingsActivity is not the Activity holding the FragmentPagerAdapter, then you would have to re-create all the fragments. The nature of a fragment is to be closely tied to it's activity.

If SettingsActivity is the Activity holding the FragmentPagerAdapter, then As I recall, FragmentPagerAdapter will initialize all the 8 fragments as soon as possible to have them ready when you swipe, unlike FragmentStatePagerAdapter. This means that you should (I think) be able to create each fragment in the constructor TabsPagerAdapter and keeping a reference to them, which you could access using getter methods on the TabsPagerAdapter.

Here is an example of how to get easy access to your pageradapter fragments:

public class DisplayPagerAdapter extends FragmentStatePagerAdapter {

    private static final String TAG = "DisplayPagerAdapter";

    SparseArray<DisplayFragment> registeredFragments = new SparseArray<DisplayFragment>();

    @Inject DisplayCoreModule display;

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

    @Override
    public int getCount() {
        return (display != null && display.getPagesCount() > 0) ? display.getPagesCount() : 1;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }


    @Override
    public Fragment getItem(int position) {
        Log.d(TAG, "getItem " + position);
        return DisplayFragment.newInstance(position); 
    }

    @Override
    public CharSequence getPageTitle(int position) {
        if (display != null && display.getPagesCount() > 0) {
            return "Side " + (position+1);
        } else {
            return super.getPageTitle(position);
        }
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Log.d(TAG, "instantiateItem " + position);
        DisplayFragment fragment = (DisplayFragment) 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);
    }

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }

    public SparseArray<DisplayFragment> getRegisteredFragments() {
        return registeredFragments;
    }


}

Now if you implement this usage of registeredFragments , you can call tabsPagerAdapter.getRegisteredFragment(2) to get your TempConverterFragment.

SparseArray<DisplayFragment> should be SparseArray<Fragment> in your case

Now this does not solve the your SettingsActivity problem. But if I understand you correctly, then adding the fragments your want directly in the layout XML of SettingsActivity would make sense. Then it would be easy to temporarily hide the fragments or whatever using:

FragmentManager fm=getFragmentManager();
Fragment myFragment=fm.findFragmentById(R.id.frag_tempconverter)
fm.beginTransaction().hide(myFragment).commit();

Notice the use of findFragmentById. The tag is usually used for dynamically added fragments (atleast in my mind). The findFragmentById will surely return a fragment if it is defined in the XML layout but just to be clear, it will be a new instance of the fragment.

To address your questions:

What if I move the fragments to the main activity XML? Won't it make things simpler

Do not think so, the updated answer shows how to easily access the fragments (from within your main activity).

Though not sure I can use FragmentManager in SettingsActivity

Sure you can. You can add new fragments, access available fragments (from predefined XML using findById or dynamically added using findByTag). You cannot, however, access the same instance of the fragment as was kept by your main activity.

To share information between the fragments and the two activities, you need to persist the state of your fragments somehow (which is a different topic).

All in all I think you are on the right path, you just need to combine the right pieces of the puzzle :)

Upvotes: 1

Related Questions