Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActionBar Tabs with multiple fragments

I've been trying to update my app and get going with fragments, the action bar, and all the other UI features that I'm missing out on. I understand I can have multiple fragments in an activity, have different layouts based upon the device and all that good stuff but I'm struggling with getting some tab stuff the way I want. I understand how to add tabs, switching between them but how do I have more than one fragment in a tab? So for example I have essentially two screens I want the user to be able to switch back and forth from easily (why I want to use tabs). If I have two separate activities I can specify this in xml files and use setContentView using the layouts below

tab1_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <fragment
        android:name="com.example.tabrefactor.Fragment1"
        android:id="@+id/fragment_1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"/>
    <fragment
        android:name="com.example.tabrefactor.Fragment2"
        android:id="@+id/fragment_2"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"/>
    <fragment
        android:name="com.example.tabrefactor.Fragment3"
        android:id="@+id/fragment_3"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"/>
</LinearLayout>

tab2_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <fragment
        android:name="com.example.tabrefactor.Fragment4"
        android:id="@+id/fragment_4"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"/>
</LinearLayout>

I can convert the second layout to using tabs since its only contains one fragment but I'm not sure how get the first layout into a single tab. Is that something that's allowed? Thanks in advance,

Jason Prenger

like image 941
StackJP Avatar asked Feb 09 '12 17:02

StackJP


3 Answers

I'll leave this open incase someone has a simplification or a better idea...

Eventually went with a workaround of having a base layout with 3 frame layouts...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/fragment_sb"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    <FrameLayout
        android:id="@+id/fragment_local"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    <FrameLayout
        android:id="@+id/fragment_rest"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

Then in my activity with the tabs I made a custom TabListener that handled the changes between. The code I used is below (I'm using actionbarsherlock so it'll look slightly different than the normal stuff)

public class TabActivity extends FragmentActivity {

    Fragment1 fragment1;
    Fragment2 fragment2;
    Fragment3 fragment3;
    Fragment4 fragment4;

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

        final ActionBar bar = getSupportActionBar();
        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        bar.setDisplayShowTitleEnabled(true);
        bar.setDisplayShowHomeEnabled(false);
        bar.setTitle("Title");

        bar.addTab(bar.newTab()
                .setIcon(R.drawable.ic_list_tab_selected)
                .setTabListener(new ListTabListener(this)));
        bar.addTab(bar.newTab()
                .setIcon(R.drawable.ic_map_tab_selected)
                .setTabListener(new MapTabListener(this)));

        if (savedInstanceState != null) {
            bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.test_menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    public static class ListTabListener implements ActionBar.TabListener {
        private static final String fragment1Tag = "fragment1_tag";
        private static final String fragment2Tag = "fragment2_tag";
        private static final String fragment3Tag = "fragment3_tag";

        private FragmentActivity activity;
        private Fragment1 fragment1;
        private Fragment2 fragment2;
        private Fragment3 fragment3;

        public ListTabListener(FragmentActivity activity) {
            this.activity = activity;

            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
            fragment1 = (Fragment1) activity.getSupportFragmentManager().findFragmentByTag(fragment1Tag);
            if (fragment1 != null && !fragment1.isDetached()) {
                ft.detach(fragment1);
            }

            fragment2 = (Fragment2) activity.getSupportFragmentManager().findFragmentByTag(fragment1Tag);
            if (fragment2 != null && !fragment2.isDetached()) {
                ft.detach(fragment2);
            }

            fragment3 = (Fragment3) activity.getSupportFragmentManager().findFragmentByTag(fragment1Tag);
            if (fragment3 != null && !fragment3.isDetached()) {
                ft.detach(fragment3);
            }

            ft.commit();
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction nullFt) {
            //Reselected don't do anything          
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction nullFt) {
            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();

            if(fragment1 == null) {
                fragment1 = new Fragment1();
                ft.add(R.id.fragment_sb, fragment1, fragment1Tag);
            } else {
                ft.attach(fragment1);
            }

            if(fragment2 == null) {
                fragment2 = new Fragment2();
                ft.add(R.id.fragment_local, fragment2, fragment2Tag);
            } else {
                ft.attach(fragment2);
            }

            if(fragment3 == null) {
                fragment3 = new Fragment3();
                ft.add(R.id.fragment_rest, fragment3, fragment3Tag);
            } else {
                ft.attach(fragment3);
            }

            ft.commit();
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction nullFt) {
            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();

            if(fragment1 != null)
                ft.detach(fragment1);
            if(fragment2 != null)
                ft.detach(fragment2);
            if(fragment3 != null)
                ft.detach(fragment3);

            ft.commit();
        }
    }

    public static class MapTabListener implements ActionBar.TabListener {
        private static final String fragment4Tag = "fragment4_tag";

        private FragmentActivity activity;
        private Fragment4 fragment4;

        public MapTabListener(FragmentActivity activity) {
            this.activity = activity;

            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
            fragment4 = (Fragment4) activity.getSupportFragmentManager().findFragmentByTag(fragment4Tag);
            if (fragment4 != null && !fragment4.isDetached()) {
                ft.detach(fragment4);
            }
            ft.commit();
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction nullFt) {
            //Reselected don't do anything          
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction nullFt) {
            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();

            if(fragment4 == null) {
                fragment4 = new Fragment4();
                ft.add(R.id.fragment_rest, fragment4, fragment4Tag);
            } else {
                ft.attach(fragment4);
            }

            ft.commit();
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction nullFt) {
            FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();

            if(fragment4 != null)
                ft.detach(fragment4);

            ft.commit();
        }
    }
}
like image 81
StackJP Avatar answered Oct 18 '22 23:10

StackJP


Here is my solution:

import java.util.ArrayList;
import library.DatabaseHandler;
import org.json.JSONObject;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;

public class Polling extends FragmentActivity {
    private ViewPager mViewPager;
    private TabsAdapter mTabsAdapter;

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

    mViewPager = new ViewPager(this);
    mViewPager.setId(R.id.pager);
    setContentView(mViewPager);
    final ActionBar bar = getActionBar();
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    bar.setDisplayShowTitleEnabled(false);
    bar.setDisplayShowHomeEnabled(false);

    mTabsAdapter = new TabsAdapter(this, mViewPager);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.login),
            LoginFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.economics),
            EconFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.elections),
            ElectionsFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.politics),
            PoliticsFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.science),
            ScienceFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.finance),
            FinanceFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.religion),
            ReligionFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.military),
            MilitaryFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText(R.string.international),
            InternationalFragment.class, null); 
}

public static class TabsAdapter extends FragmentPagerAdapter
    implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

        static final class TabInfo {
            private final Class<?> clss;
            private final Bundle args;

            TabInfo(Class<?> _class, Bundle _args) {
                clss = _class;
                args = _args;
            }
        }

        public TabsAdapter(FragmentActivity activity, ViewPager pager) {
            super(activity.getSupportFragmentManager());
            mContext = activity;
            mActionBar = activity.getActionBar();
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);
        }

        public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
            TabInfo info = new TabInfo(clss, args);
            tab.setTag(info);
            tab.setTabListener(this);
            mTabs.add(info);
            mActionBar.addTab(tab);
            notifyDataSetChanged();
        }


        public int getCount() {
            return mTabs.size();
        }

        public Fragment getItem(int position) {
            TabInfo info = mTabs.get(position);
            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
        }


        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }


        public void onPageSelected(int position) {
            mActionBar.setSelectedNavigationItem(position);
        }


        public void onPageScrollStateChanged(int state) {
        }


        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            mViewPager.setCurrentItem(tab.getPosition());
            Log.v(TAG, "clicked");
            Object tag = tab.getTag();
            for (int i=0; i<mTabs.size(); i++) {
                if (mTabs.get(i) == tag) {
                    mViewPager.setCurrentItem(i);
                }
            }
        }

        public void onTabUnselected(Tab tab, FragmentTransaction ft) {}

        public void onTabReselected(Tab tab, FragmentTransaction ft) {}

        public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {}

        @Override
        public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {    
            Object tag = tab.getTag();
            for (int i=0; i<mTabs.size(); i++) {
                if (mTabs.get(i) == tag) {
                    mViewPager.setCurrentItem(i);
                }
            }
        }

        public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {}
    }

So obviously after all that, we have to look at how a fragment is made (including inflating a separate layout file). Basically in the onCreateView() method of each fragment, you have it return inflater.inflate(R.layout.THISFRAGMENTSLAYOUT, container, false); Here is the code:

public class EconFragment extends Fragment {


    private TableLayout questionContainer;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d("Econ", "onCreateView");

        return inflater.inflate(R.layout.econfragment, container, false);
    }

    public void onResume() {
        super.onResume();

        LayoutInflater inflater = (LayoutInflater) getActivity().
        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        questionContainer = (TableLayout)getActivity().findViewById(R.id.questionContainer);

        int leftMargin=5;
        int topMargin=5;
        int rightMargin=5;
        int bottomMargin=5;
        while (pos < 10) {
        View question = inflater.inflate(R.layout.question, null);
        question.setId(pos);
        TextView title = (TextView) question.findViewById(R.id.questionTextView);
        title.setText(titles[pos]);
        Button charts = (Button) question.findViewById(R.id.chartsButton);
        charts.setId(pos);
        charts.setOnClickListener(chartsListener);
        TableRow tr = (TableRow) question;
        TableLayout.LayoutParams trParams = new TableLayout.LayoutParams(
                TableLayout.LayoutParams.MATCH_PARENT,
                TableLayout.LayoutParams.WRAP_CONTENT);
        trParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);
        tr.setLayoutParams(trParams);

        questionContainer.addView(tr);
        pos++;
        }
        Log.d("Econ", "onResume");
    }
like image 1
Davek804 Avatar answered Oct 19 '22 00:10

Davek804


This is the same as the selected answer, except that I've NOT used the support libs.


There are two tabs A and B.

Tab A contains Apples and Apricots

Tab B contains Bananas and Berries


I've use a FrameLayout as a container to hold these babies

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 <FrameLayout
   android:id="@+id/container_widgets"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"/>
</LinearLayout>

MultiFragsInTabsJelly.java - handles the attach and detach ops.

import java.util.ArrayList;
import java.util.Iterator;

import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.ActionBar.Tab;
import android.os.Bundle;
import android.util.Log;

public class MultiFragsInTabsJelly extends Activity {
    
    public static String TAG = "EPE";

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      
   // setup action bar for tabs
      setContentView(R.layout.main_layout_jelly);
      
      ActionBar actionBar = getActionBar();
      actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
      actionBar.setDisplayShowTitleEnabled(false);
      
      actionBar.setTitle("A and B");
      
      Tab tabA = actionBar
              .newTab()
              .setText("A");
       tabA.setTabListener(new TabAListener(this));
       
       actionBar.addTab(tabA);
        
       Tab tabB = actionBar
                    .newTab()
                    .setText("B");
       tabB.setTabListener(new TabBListener(this));
       actionBar.addTab(tabB);
    }
    
    
 public static class TabAListener implements ActionBar.TabListener {
        
        // FIXME: is this really needed?
        private static final String appleTag   = "apple";
        private static final String apricotTag = "apricot";
     
        private final Activity      mActivity;
        private ArrayList<Fragment> fragList;

        public TabAListener(Activity activity) {
            mActivity = activity;
            fragList  = null;
        }
        
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // Reselected don't do anything 
            Log.d(TAG, "Tab A: on Tab reselected");
        }
        
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
        
            Log.d(TAG, "Tab A: on Tab Selected");

            // attach all the fragments
            if(fragList == null) {
                
                fragList  = new ArrayList<Fragment>();
                RecordingFragment   appleFrag   = new RecordingFragment();
                ApricotFragment apricotFrag = new ApricotFragment();
                ft.add(R.id.container_widgets, appleFrag, appleTag);
                ft.add(R.id.container_widgets, apricotFrag,  apricotTag);
                fragList.add(appleFrag);
                fragList.add(apricotFrag);
                Log.d(TAG, "Tab A: Added fragments to the ArrayList");
                
            } else {
                
                Iterator iter = fragList.iterator();

                while (iter.hasNext())
                {
                    Log.d(TAG, "Tab A: Attaching fragments");
                    ft.attach((Fragment) iter.next());
                }
            }
        }
        
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            Log.d(TAG, "Tab A: on Tab Unselected");

            if(fragList != null)
            {  
                Iterator iter = fragList.iterator();
                while (iter.hasNext())
                {
                    Log.d(TAG, "Tab A: Fragments detached");
                    ft.detach((Fragment) iter.next());
                }
            }
        }
    }
 
    public static class TabBListener implements ActionBar.TabListener {

        // FIXME: is this really needed?
        private static final String bananaTag = "banana";
        private static final String berryTag  = "berry";

        private final Activity mActivity;
        private ArrayList<Fragment> fragList;

        public TabBListener(Activity activity) {
            mActivity = activity;
            fragList = null;
        }

        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // Reselected don't do anything
            Log.d(TAG, "Tab B: on Tab reselected");
        }

        public void onTabSelected(Tab tab, FragmentTransaction ft) {

            Log.d(TAG, "Tab B: on Tab Selected");

            // attach all the fragments
            if (fragList == null) {

                fragList = new ArrayList<Fragment>();
                BananaFragment bananaFrag = new BananaFragment();
                BerryFragment   berryFrag = new BerryFragment();
                ft.add(R.id.container_widgets, bananaFrag, bananaTag);
                ft.add(R.id.container_widgets, berryFrag,  berryTag);
                fragList.add(bananaFrag);
                fragList.add(berryFrag);
                Log.d(TAG, "Tab B: Added fragments to the ArrayList");

            } else {

                Iterator iter = fragList.iterator();
                while (iter.hasNext()) {
                    Log.d(TAG, "Tab B: Attaching fragments");
                    ft.attach((Fragment) iter.next());
                }
            }
        }

        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            Log.d(TAG, "Tab B: on Tab Unselected");

            if (fragList != null) {
                Iterator iter = fragList.iterator();
                while (iter.hasNext()) {
                    Log.d(TAG, "Tab B: Fragments detached");
                    ft.detach((Fragment) iter.next());
                }
            }
        }
    }
}

Here we have the (empty) body of each Fragment. I've only shown one ApricotFragment

apricot_fragment.xml

<?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"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="200dip"
        android:layout_height="wrap_content"
        android:padding="6dip"
        android:text="Apricot" />
    
</RelativeLayout>

ApricotFragment.java

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ApricotFragment extends Fragment {
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.apricot_fragment, container, false);
    }
}

I've you have managed to implement this give yourself a pat on the butt and get some cinnamon rolls with coffee and treat yourself to excellent pictures of cats

like image 1
Reno Avatar answered Oct 19 '22 01:10

Reno