Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TabHost with Fragments and FragmentActivity

I'm working on an Android App and I want to use 3 tabs for navigation using Fragments for each tab, but I don't know how to create the structure for doing it.

I want to add each fragment separately because each one is different, but I don't know where to add them in FragmentActivity.

I have these files.

tabs_layout.xml

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

    <TabHost android:id="@android:id/tabhost"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

         <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

             <TabWidget
                android:id="@android:id/tabs" 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
             />

             <FrameLayout
                 android:id="@android:id/tabcontent" 
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"

             >

                 <FrameLayout
                     android:id="@+id/tabRateAPet" 
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"

                 />

                 <FrameLayout
                     android:id="@+id/tabViewMyRates" 
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"

                 />

                 <FrameLayout
                     android:id="@+id/tabViewGlobalRates" 
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"

                 />


             </FrameLayout>
        </LinearLayout>
    </TabHost>
</LinearLayout>

TabsMain.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;

public class MainTabsActivity extends FragmentActivity {
public static final String RATE_A_PET = "Rate a Pet";
public static final String MY_RATES = "My Rates";
public static final String GLOBAL_RATES = "Global Rates";

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tabs_layout);
 }
}

Tabs.java

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;

public class Tabs extends Fragment implements OnTabChangeListener {
    private static final String TAG = "FragmentTabs";
    public static final String RATE_A_PET = "Rate a Pet";
    public static final String MY_RATES = "My Rates";
    public static final String GLOBAL_RATES = "Global Rates";

    private View mRoot;
    private TabHost mTabHost;
    private int mCurrentTab;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
//      super.onCreateView(inflater, container, savedInstanceState);
        mRoot = inflater.inflate(R.layout.tabs_layout, null);
        mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
        setupTabs();
        return mRoot;
    }

    private void setupTabs() {
        mTabHost.setup(); // important!
        mTabHost.addTab(newTab(RATE_A_PET, R.string.tabRateAPet, R.id.tabRateAPet));
        mTabHost.addTab(newTab(MY_RATES, R.string.tabViewMyRates, R.id.tabViewMyRates));
    }

    private TabSpec newTab(String tag, int labelId, int tabContentId) {
        Log.d(TAG, "buildTab(): tag=" + tag);

        View indicator = LayoutInflater.from(getActivity()).inflate(
                R.layout.tab,
                (ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
        ((TextView) indicator.findViewById(R.id.text)).setText(labelId);

        TabSpec tabSpec = mTabHost.newTabSpec(tag);
        tabSpec.setIndicator(indicator);
        tabSpec.setContent(tabContentId);
        return tabSpec;
    }


    @Override
    public void onTabChanged(String tabId) {
        Log.d(TAG, "onTabChanged(): tabId=" + tabId);
        if (RATE_A_PET.equals(tabId)) {
            updateTab(tabId, R.id.tabRateAPet);
            mCurrentTab = 0;
            return;
        }
        if (MY_RATES.equals(tabId)) {
            updateTab(tabId, R.id.tabViewMyRates);
            mCurrentTab = 1;
            return;
        }
        if (GLOBAL_RATES.equals(tabId)) {
            updateTab(tabId, R.id.tabViewGlobalRates);
            mCurrentTab = 2;
            return;
        }
    }   
    private void updateTab(String tabId, int placeholder) {
        FragmentManager fm = getFragmentManager();
        if (fm.findFragmentByTag(tabId) == null) {
            fm.beginTransaction()
                    .replace(placeholder, new RateMyPetActivity(), tabId)
                    .commit();
        }
    }

}
like image 367
imarban Avatar asked Jun 21 '13 04:06

imarban


People also ask

What is the difference between fragment and FragmentActivity?

If you want to use Fragments in an app targeting a platform version prior to HoneyComb, you need to add the Support Package to your project and use the FragmentActivity to hold your Fragments . The FragmentActivity class has an API for dealing with Fragments , whereas the Activity class, prior to HoneyComb, doesn't.

How do you get FragmentActivity in a fragment?

use getActivity() method. Which will return the enclosing activity for the fragment.


2 Answers

I would suggest creating a separate fragment file for each tab. I recently did this as well, so I have outlined my code below:

Layout Files

activity_main.xml

<android.support.v4.app.FragmentTabHost     xmlns:android="http://schemas.android.com/apk/res/android"     android:id="@android:id/tabhost"     android:layout_width="match_parent"     android:layout_height="match_parent">  <LinearLayout     android:orientation="vertical"     android:layout_width="match_parent"     android:layout_height="match_parent">      <TabWidget         android:id="@android:id/tabs"          android:orientation="horizontal"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_weight="0"/>      <FrameLayout         android:id="@android:id/tabcontent"         android:layout_width="0dp"         android:layout_height="0dp"         android:layout_weight="0"/>      <FrameLayout         android:id="@+id/realtabcontent"         android:layout_width="match_parent"         android:layout_height="0dp"         android:layout_weight="1"/>  </LinearLayout> </android.support.v4.app.FragmentTabHost> 

tab1_view.xml //add your respective tab layouts using this format (make sure to change string variables)

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"         xmlns:tools="http://schemas.android.com/tools"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="vertical"         tools:context=".DeviceFragment" >      <TextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="@string/tab1_fragment_string" />  </LinearLayout> 

SRC Files

MainActivity.java //notice that in the .addTab process I only used text. You can also add icons using drawables that you would need to add to your hdpi folder. I also only created three tabs in this example.

package com.example.applicationname;  import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTabHost;  public class MainActivity extends FragmentActivity {     // Fragment TabHost as mTabHost     private FragmentTabHost mTabHost;      @Override     protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);         mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);          mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Tab1"),             Tab1Fragment.class, null);         mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Tab2"),             Tab2Fragment.class, null);         mTabHost.addTab(mTabHost.newTabSpec("tab3").setIndicator("Tab3"),             Tab3Fragment.class, null);     } } 

Tab1Fragment.java //once again replicate for desired number of tabs

package com.example.applicationname;  import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup;  public class Tab1Fragment extends Fragment  {   @Override     public View onCreateView(LayoutInflater inflater, ViewGroup container,         Bundle savedInstanceState) {         // Inflate the layout for this fragment         View V = inflater.inflate(R.layout.tab1_view, container, false);          return V;     } } 

Make sure that your R.java and strings.xml files are properly set up, and then your tabs should be up and running.

like image 177
Kylie Moden Avatar answered Oct 03 '22 18:10

Kylie Moden


TabHost doesn't retains Fragment's states. So why using TabHost?

So use ViewPager with TabLayout instead.

Prons of Viewpager over Tabhost:

  • ViewPager retains Fragments states. Mean Fragment will not again recreated if switched.
  • Inbuilt swiping feature that gives user smoother experience.
  • Less CPU consumption, because Tabhost recreates Fragment/Activity again and again when Tab is switched.

See the difference :

Using Tablayout + ViewPager (Supports swipe, retains Fragments states

Tablayout + ViewPager

Using TabHost (Doesn't support swipe, doesn't retain states)

TabHost

Small Code for Tablayout + ViewPager

// find views by id
ViewPager viewPager = findViewById(R.id.viewpager);
TabLayout tabLayout = findViewById(R.id.tablayout);

// attach tablayout with viewpager
tabLayout.setupWithViewPager(viewPager);

ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());

// add your fragments
adapter.addFrag(new SampleFragment(), "Tab1");
adapter.addFrag(new SampleFragment(), "Tab2");
adapter.addFrag(new SampleFragment(), "Tab3");

// set adapter on viewpager
viewPager.setAdapter(adapter);

XML layout

<?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">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

Note If you are not using AndroidX yet, you need to change following in layout.

  • Change com.google.android.material.tabs.TabLayout to android.support.design.widget.TabLayout
  • Chagne androidx.viewpager.widget.ViewPager to android.support.v4.view.ViewPager

But I'll strongly recommend to migrate to AndroidX, see @this answer to understand why.

And this is common ViewPagerAdapter for all your Viewpager in app.

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }

    public void addFrag(Fragment fragment) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add("");
    }

    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }
}

Important Related Links

  • Difference between getSupportFragmentManager() and getChildFragmentManager()?
  • getSupportFragmentManager() versus getFragmentManager() in android 3.0+
  • Difference between FragmentPagerAdapter and FragmentStatePagerAdapter
like image 36
Khemraj Sharma Avatar answered Oct 03 '22 16:10

Khemraj Sharma