I want to create an app with three tabs. I have three fragments, three xml files, one main activity, one main xml and a tablistener class. The app shows the first two tabs properly, but the third tab is not shown. There is no error in the code.
Note: I'm using support library.
MainActivity:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupTabs();
}
// To setup tabs using ActionBar and fragments
private void setupTabs() {
// setup the ActionBar
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(true);
//define which tabs you would like to display
//and attach listeners for each tab:
ActionBar.Tab tab1 = actionBar
.newTab()
.setText("First")
.setTabListener(new SupportFragmentTabListener<FirstFragment>(R.id.main,this,
"first", FirstFragment.class));
actionBar.addTab(tab1);
actionBar.selectTab(tab1);
ActionBar.Tab tab2 = actionBar
.newTab()
.setText("Second")
.setTabListener(new SupportFragmentTabListener<SecondFragment>(R.id.main,this,
"second", SecondFragment.class));
actionBar.addTab(tab2);
ActionBar.Tab tab3 = actionBar
.newTab()
.setText("Third")
.setTabListener(new SupportFragmentTabListener<ThirdFragment>(R.id.main, this,
"third", ThirdFragment.class));
ActionBar.Tab tab4 = actionBar
.newTab()
.setText("Fourth")
.setTabListener(new SupportFragmentTabListener<FourthFragment>(R.id.main, this,
"fourth", FourthFragment.class));
}
}
TabListener:
public class SupportFragmentTabListener<T extends Fragment>
implements TabListener {
private Fragment mFragment;
private final FragmentActivity mActivity;
private final String mTag;
private final Class<T> mClass;
private final int mfragmentContainerId;
public SupportFragmentTabListener(FragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
mfragmentContainerId = android.R.id.content;
}
public SupportFragmentTabListener(int fragmentContainerId, FragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
mfragmentContainerId = fragmentContainerId;
}
/* The following are each of the ActionBar.TabListener callbacks */
public void onTabSelected(Tab tab, FragmentTransaction sft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
sft.replace(mfragmentContainerId, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
sft.replace(mfragmentContainerId, mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction sft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
//sft.remove(mFragment);
sft.replace(mfragmentContainerId,mFragment);
}else{
// If not, instantiate and add it to the activity:
mFragment = Fragment.instantiate(mActivity, mClass.getName());
sft.add(android.R.id.content, mFragment,mTag);
}
}
public void onTabReselected(Tab tab, FragmentTransaction sft) {
// User selected the already selected tab. Usually do nothing.
}
}
ThirdFragment:
public class ThirdFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.grade_table, container, false);
TextView ff = (TextView) rootView.findViewById(R.id.textView2);
return rootView;
}
}
You need to add the tab after creating it. You forgot to write:
actionBar.addTab(tab3);
and
actionBar.addTab(tab4);
Related
UPDATE : I don't understand why when tapping on each tab onTabSelected() doesn't show the correct fragment even though it's been added to the fragmentTransaction android.R.id.content.
I call this method before onTabSelected gets called to make sure fragments are not null.
protected void initTabs() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(mShowFragment3 == null) {
mShowFragment3 = EpisodeTileFragment.newInstance(getString(R.string.title_section4));
ft.add(android.R.id.content, mShowFragment3);
}
if(mShowFragment2 == null) {
mShowFragment2 = EpisodeTileFragment.newInstance(getString(R.string.title_section3));
ft.add(android.R.id.content, mShowFragment2);
}
}
#Override
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction ft) {
//this usually works, but if i try to mess with adding the tabs to the
//FragmentTransaction this won't work anymore
if(tab.getPosition() == 1) {
ft.show(mShowFragment2);
}
I have scoured the internet and this may not be possible but I wanted to give this a shot.
I currently have the app working fine, it has 4 tabs and 4 corresponding fragments. When a user opens the app onTabSelected is called and selects the first tab/fragment is added and we're all good.
A user clicks tab2 and the 2nd fragment is added and rendered. When a user clicks the 2nd tab there is an asynctask that gets data and renders this on a fragment. Etc.. this happens on tab 3 and 4 also. When a user clicks a tab the first time I instantiate the fragment and add it to the fragmentTransaction, the next time you click on the tab it's lightning fast because it's already added, and I'm hiding and showing fragments.
The question I have is , is there a way to load up all 4 tabs at the same time, vs. waiting for a user to click on a tab and then have onTabSelected firing and grabbing data etc. Please let me know if there is any questions, the code is working with no errors just not what I want, and I don't know how to instantiate all 4 fragments at the same time.
mSectionsPagerAdapter = new SectionsPagerAdapter(this.getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
View tabView = inflater.inflate(R.layout.tab_title, null);
TextView titleTV = (TextView) tabView.findViewById(R.id.action_custom_title);
titleTV.setText(mSectionsPagerAdapter.getPageTitle(i));
titleTV.setTypeface(Typeface.createFromAsset(getAssets(), getString(R.string.tab_font)));
titleTV.setSingleLine();
titleTV.setTextSize(13);
Tab t = actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this);
t.setCustomView(tabView);
actionBar.addTab(t);
}
this is for adding the tabs. but need to add the fragments for each tab.
Set the offscreen page limit to your number of tabs, and then your ViewPager will render all the fragments when the parent activity is created.
mViewPager.setOffscreenPageLimit(4);
You should also check out the Class Overview of ViewPager, which has a really good example of using a custom FragmentPagerAdapter called TabsAdapter with a ViewPager (instead of using the ADT generated SectionsPagerAdapter). I added the code from the official Android docs below:
public class ActionBarTabsPager extends Activity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
#Override
protected 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.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
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(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
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();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
i am using actionbar(support.v7) with 4 tabs using fragments. I want each tab to have a separate activity rather than a common activity calling fragments?
ApplicationMainTabsActivity
public class ApplicationMainTabsActivity extends ActionBarActivity {
ActionBar.Tab Tab1, Tab2, Tab3,Tab4;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
String label1 = getResources().getString(R.string.label1);
Tab1 = actionBar.newTab();
Tab1.setText(label1);
ApplicationTabListener<Fragment1> tl = new ApplicationTabListener<Fragment1>(this,label1, Fragment1.class);
Tab1.setTabListener(tl);
actionBar.addTab(Tab1);
String label2 = getResources().getString(R.string.label2);
Tab2 = actionBar.newTab();
Tab2.setText(label2);
ApplicationTabListener<Fragment2> t2 = new ApplicationTabListener<Fragment2>(this,label2, Fragment2.class);
Tab2.setTabListener(t2);
actionBar.addTab(Tab2);
String label3 = getResources().getString(R.string.label3);
Tab3 = actionBar.newTab();
Tab3.setText(label3);
ApplicationTabListener<Fragment3> t3 = new ApplicationTabListener<Fragment3>(this,label3, Fragment3.class);
Tab3.setTabListener(t3);
actionBar.addTab(Tab3);
String label4 = getResources().getString(R.string.label4);
Tab4 = actionBar.newTab();
Tab4.setText(label4);
ApplicationTabListener<Fragment4> t4 = new ApplicationTabListener<Fragment4>(this,label4, Fragment4.class);
Tab4.setTabListener(t4);
actionBar.addTab(Tab4);
}
ApplicationTabListener.java
final class ApplicationTabListener<T extends Activity> implements ActionBar.TabListener {
private Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
/**
* Constructor used each time a new tab is created.
*
* #param activity
* The host Activity, used to instantiate the fragment
* #param tag
* The identifier tag for the fragment
* #param clz
* The fragment's Class, used to instantiate the fragment
*/
public ApplicationTabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public ApplicationTabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(R.id.action_bar_activity_content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.replace(R.id.action_bar_activity_content,mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
// Detach the fragment, because another one is being attached
ft.remove(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// User selected the already selected tab. Usually do nothing.
}
}
Fragment1.java
public class Fragment1 extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main, container, false);
}
}
You cannot have separate activity for each Tab which was used to be as in TabActivity. And it's deprecated. You need to attach fragments in order to use it. Otherwise you need to build your own custom TabActivity.
I created my Sherlock fragment activity and implemented tabs:
public class Home extends SherlockFragmentActivity
{
ActionBar actionBar;
TabHost myTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
actionBar=getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1= actionBar.newTab();
ActionBar.Tab tab2= actionBar.newTab();
//ActionBar.Tab tab3 = actionBar.newTab();
tab1.setText("Contacts");
tab2.setText("Inbox");
// tab3.setText("Outbox");
tab1.setTabListener(new MyTabListener());
tab2.setTabListener(new MyTabListener());
actionBar.addTab(tab1, true);
actionBar.addTab(tab2);
actionBar.addTab(tab3);
}
And this is my tab change listener:
private class MyTabListener implements TabListener
{
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getPosition()==0)
{
FragmentA frag = new FragmentA ();
ft.replace(android.R.id.content, frag );
}
else
{
FragmentB frag = new FragmentB ();
ft.replace(android.R.id.content,frag );
}
}
And this is my FragmentA:
public class FragmentA extends Fragment
{
TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.activity_list, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
}
Here under my first tab, there is a list that is displaying. When I click any one of the list items, I need to load another fragment under the same activity. And when back is pressed, the old fragment needs to be loaded under the same tab.
Is this possible in actionbarsherlock tabs? If so, how do I do this?
I have a doubt about my program.
I have 3 tabs in the action bar (made with fragments), each one shows a different view. These views have a lot of information that they collect from a database to show charts. The problem is that the ammount of information is quite big for read it everytime I change from one tab to another.
The question:
Is there any way to create each view only once and then just move between them?
The Activity:
String label1 = "one day";
Tab tab = actionBar.newTab();
tab.setText(label1);
TabListener<Tab1Fragment> tl = new TabListener<Tab1Fragment>(this, label1, Tab1Fragment.class);
tab.setTabListener(tl);
actionBar.addTab(tab);
String label2 = "two days";
tab = actionBar.newTab();
tab.setText(label2);
TabListener<Tab2Fragment> tl2 = new TabListener<Tab2Fragment>(this, label2, Tab2Fragment.class);
tab.setTabListener(tl2);
actionBar.addTab(tab);
String label3 = "three days";
tab = actionBar.newTab();
tab.setText(label3);
TabListener<Tab3Fragment> tl3 = new TabListener<Tab3Fragment>(this, label3, Tab3Fragment.class);
tab.setTabListener(tl3);
actionBar.addTab(tab);
The tab listener class:
private class TabListener<T extends Fragment> implements ActionBar.TabListener{
private Fragment fragment;
private final Activity activity;
private final String tag;
private final Class<T> classT;
public TabListener(Activity activityTab, String tagTab, Class<T> classTab) {
activity = activityTab;
tag = tagTab;
classT = classTab;
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (fragment == null) {
fragment = Fragment.instantiate(activity, classT.getName());
ft.add(android.R.id.content, fragment, tag);
} else {
ft.attach(fragment); }
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.detach(fragment);
}
And one of the fragments (the 3 are the same, only change the R.layout.**):
public class Tab1Fragment extends Fragment {
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
setRetainInstance(true);
return (LinearLayout) inflater.inflate(R.layout.main, container, false);
Thank you!
Each fragment can retain its state. Call setRetainInstance(true) in the fragment constructor.
Then you should fetch the data only if it has not already been fetched (if your store you data in a List, set that list to null in the constructor, create and fill it when you fetch data, and in the onStart method, if the list is null, fetch the data. Else, do nothing).
See also: Persisting list items in ListAdapter on configurationChanges with setRetainInstance
I am trying to avoid using intents and activities within tabhost and tabwidget
This code is starting to get messy just using views for everything.
My problem is that I am having difficulty retaining information. In one tab I have one view which has 4 buttons, each button loads another view and this takes up the visual information on screen in that tab. The problem is that when I go "back" to load the previous view in that tab, none of the information is that view is retained, even the button listeners won't re-instantiate.
How do I approach this? I have seen some very rudimentary examples of views within tabs, but nothing interactive that loads more views.
(viewflippers and action bars are not an option, and I am trying to avoid using tabs with activities)
Forget Activity Group. Forget Tab Host. It's all about ActionBar Tabs and ViewPager Fragments now. The API Demos sample app (which is also the Android Compatibility Library sample app) provides an implementation that combines both Tab and ViewPager navigation between Fragments, but it sort of fakes the Tabs (i.e., they are not true ActionBar tabs). See FragmentTabsPager.java. You can take this and make it work with true ActionBar tabs, too.
Here's the interesting bit. (I deleted a bunch of stuff, so don't look for a complete working solution here.)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_tabs_pager);
mViewPager = (ViewPager)findViewById(R.id.pager);
// This block thanks to https://stackoverflow.com/q/9790279/517561
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowTitleEnabled(true);
bar.setDisplayShowHomeEnabled(true);
//
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab("simple", "Simple",
FragmentStackSupport.CountingFragment.class, null);
mTabsAdapter.addTab("contacts", "Contacts",
LoaderCursorSupport.CursorLoaderListFragment.class, null);
mTabsAdapter.addTab("custom", "Custom",
LoaderCustomSupport.AppListFragment.class, null);
mTabsAdapter.addTab("throttle", "Throttle",
LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
}
public static class TabsAdapter extends FragmentPagerAdapter
implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final SherlockFragmentActivity mContext;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
#SuppressWarnings("unused")
private final String tag;
private final Class<?> clss;
private final Bundle args;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
#Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(String tag, CharSequence label, Class<?> clss, Bundle args) {
ActionBar.Tab tab = mContext.getSupportActionBar().newTab();
tab.setText(label);
tab.setTabListener(this);
mContext.getSupportActionBar().addTab(tab);
TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public void onPageSelected(int position) {
mContext.getSupportActionBar().setSelectedNavigationItem(position);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(mContext.getSupportActionBar().getSelectedNavigationIndex());
}
}
My complete solution: http://code.google.com/p/sherlock-demo/
Note: Requires ActionBarSherlock.
Note: Thanks to ActionBarSherlock and FragmentTabsPager
User Activity Group for tabs and put any beautiful layout you create for tab or activities.
Here we go: http://ericharlow.blogspot.com/2010/09/experience-multiple-android-activities.html