Dynamically changing the fragments inside a fragment tab host?
P

1

38

I have one main activity which is fragment activity here I am setting two tabs with two fragments A and B in the B fragment I have one button when the user click on the button I want to change fragment B to fragment C. But the tabs above are visible...

How I can achieve replacing fragments inside tabs?

Any solution are greatly appreciated.

Pertinacious answered 8/8, 2013 at 7:40 Comment(0)
N
92

Basic concept- We can achieve this by creating a container. Each tab will be assigned with a specific container. Now when we need a new fragment then we will replace same using this container.

Kindly follow undermentioned code step by step to have better understanding. Step-1: Create Tabs for your app. Say "Home.java". It will contain code for creating tabs using fragment.

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.app.FragmentTabHost;
    import android.widget.TextView;
    import app.drugs.talksooner.container.GoContainerFragment;
    import app.drugs.talksooner.container.LearnContainerFragment;
    import app.drugs.talksooner.container.MoreContainerFragment;
    import app.drugs.talksooner.container.TalkContainerFragment;
    import app.drugs.talksooner.container.WatchContainerFragment;
    import app.drugs.talksooner.utils.BaseContainerFragment;

    public class Home extends FragmentActivity {

        private static final String TAB_1_TAG = "tab_1";
        private static final String TAB_2_TAG = "tab_2";
        private static final String TAB_3_TAG = "tab_3";
        private static final String TAB_4_TAG = "tab_4";
        private static final String TAB_5_TAG = "tab_5";
        private FragmentTabHost mTabHost;

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

        private void initView() {
            mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
            mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

           // mTabHost.addTab(mTabHost.newTabSpec(TAB_1_TAG).setIndicator("Talk", getResources().getDrawable(R.drawable.ic_launcher)), TalkContainerFragment.class, null);
            mTabHost.addTab(mTabHost.newTabSpec(TAB_1_TAG).setIndicator("Talk"), TalkContainerFragment.class, null);
            mTabHost.addTab(mTabHost.newTabSpec(TAB_2_TAG).setIndicator("Learn"), LearnContainerFragment.class, null);
            mTabHost.addTab(mTabHost.newTabSpec(TAB_3_TAG).setIndicator("Go"), GoContainerFragment.class, null);
            mTabHost.addTab(mTabHost.newTabSpec(TAB_4_TAG).setIndicator("Watch"), WatchContainerFragment.class, null);
            mTabHost.addTab(mTabHost.newTabSpec(TAB_5_TAG).setIndicator("More"), MoreContainerFragment.class, null);

            /* Increase tab height programatically 
             * tabs.getTabWidget().getChildAt(1).getLayoutParams().height = 150; 
             */

            for (int i = 0; i < mTabHost.getTabWidget().getChildCount(); i++) {
                final TextView tv = (TextView) mTabHost.getTabWidget().getChildAt(i).findViewById(android.R.id.title);
                if (tv == null)
                continue;
                else
                tv.setTextSize(10);

            }

        }

        @Override
        public void onBackPressed() {
            boolean isPopFragment = false;
            String currentTabTag = mTabHost.getCurrentTabTag();
            if (currentTabTag.equals(TAB_1_TAG)) {
                isPopFragment = ((BaseContainerFragment)getSupportFragmentManager().findFragmentByTag(TAB_1_TAG)).popFragment();
            } else if (currentTabTag.equals(TAB_2_TAG)) {
                isPopFragment = ((BaseContainerFragment)getSupportFragmentManager().findFragmentByTag(TAB_2_TAG)).popFragment();
            } else if (currentTabTag.equals(TAB_3_TAG)) {
                isPopFragment = ((BaseContainerFragment)getSupportFragmentManager().findFragmentByTag(TAB_3_TAG)).popFragment();
            } else if (currentTabTag.equals(TAB_4_TAG)) {
                isPopFragment = ((BaseContainerFragment)getSupportFragmentManager().findFragmentByTag(TAB_4_TAG)).popFragment();
            } else if (currentTabTag.equals(TAB_5_TAG)) {
                isPopFragment = ((BaseContainerFragment)getSupportFragmentManager().findFragmentByTag(TAB_5_TAG)).popFragment();
            }
            if (!isPopFragment) {
                finish();
            }
        }


    }

Your home.xml file

    <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/realtabcontent"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />


        <android.support.v4.app.FragmentTabHost
            android:id="@android:id/tabhost"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="0dip"
                android:layout_height="0dip"
                android:layout_weight="0" />

        </android.support.v4.app.FragmentTabHost>

    </LinearLayout>

Step-2: Define Base container fragment which will be helpful for backtracking and replacment of fragments "check out replaceFragement() ". Our class "BaseContainerFragment.java"

    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentTransaction;
    import android.util.Log;
    import app.drugs.talksooner.R;

    public class BaseContainerFragment extends Fragment {

        public void replaceFragment(Fragment fragment, boolean addToBackStack) {
            FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
            if (addToBackStack) {
                transaction.addToBackStack(null);
            }
            transaction.replace(R.id.container_framelayout, fragment);
            transaction.commit();
            getChildFragmentManager().executePendingTransactions();
        }

        public boolean popFragment() {
            Log.e("test", "pop fragment: " + getChildFragmentManager().getBackStackEntryCount());
            boolean isPop = false;
            if (getChildFragmentManager().getBackStackEntryCount() > 0) {
                isPop = true;
                getChildFragmentManager().popBackStack();
            }
            return isPop;
        }

    }

Step3: Now here I am considering for one fragment only hoping that rest can be handled by you in same fashion. Defining container Fragment class. Each tab will have specific container. Say TalkContainerFragment.java for first tab

    import android.os.Bundle;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import app.drugs.talksooner.R;
    import app.drugs.talksooner.Talk;
    import app.drugs.talksooner.utils.BaseContainerFragment;

    public class TalkContainerFragment extends BaseContainerFragment {

        private boolean mIsViewInited;

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            Log.e("test", "tab 1 oncreateview");
            return inflater.inflate(R.layout.container_fragment, null);
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            Log.e("test", "tab 1 container on activity created");
            if (!mIsViewInited) {
                mIsViewInited = true;
                initView();
            }
        }

        private void initView() {
            Log.e("test", "tab 1 init view");
            replaceFragment(new Talk(), false);
        }

    }

It's xml file. "container_fragment.xml" this xml container contains frameLayout. we will use this id to replace different Fragments.

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


    </FrameLayout>

Your main class. "Talk.java"

    public class Talk extends Fragment {

        /** Define global variables over here */
        //private ProgressDialog pDialog;
        StaticApiList sal;
        TalkModelAll tma;
        JSONObject myJasonObject = null;
        private ListView lv;
        private ArrayList<TalkModelAll> m_ArrayList = null;
        //ArrayList<String> stringArrayList = new ArrayList<String>();
        TalkArrayAdapter taa;
        Set<String> uniqueValues = new HashSet<String>();
        TextView rowTextView = null;
        boolean vivek = false;

        int postid;
        String title;
        String thumsrc;
        String largeimg;
        String excert;
        String description;
        String cat;
        String myUrl;
        String jsonString;
        int mCurCheckPosition;
        String check_state = null;
        String ccc;
        LinearLayout myLinearLayout;

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

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

            Button btn = (Button) rootView.findViewById(R.id.your_btn_id);
            btn.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
//Here TalkDetail is name of class that needs to open
                    TalkDetail fragment = new TalkDetail();
                    // if U need to pass some data 
                    Bundle bundle = new Bundle();

                    bundle.putString("title", m_ArrayList.get(arg2).title);
                    bundle.putString("largeimg", m_ArrayList.get(arg2).largeimg);
                    bundle.putString("excert", m_ArrayList.get(arg2).excert);
                    bundle.putString("description", m_ArrayList.get(arg2).description);
                    bundle.putString("cat", m_ArrayList.get(arg2).cat);
                    //bundle.putInt("postid", m_ArrayList.get(arg2).postid);

                    fragment.setArguments(bundle);
                    ((BaseContainerFragment)getParentFragment()).replaceFragment(fragment, true);
                }
            });

            return rootView;
        }
    }

That's it. You are good to go. The whole magic lies in calling R.id. instead of R.layout. Cheers!

Nickinickie answered 8/11, 2013 at 13:8 Comment(30)
great job..really you are a hacker..this is what I am looking for. +1 with thanks.Psychometry
Its Working Fine for with out maps.. But How to use maps here.. If I use BaseContainer fragment its giving me nullPointerException. onClick of a Button redirectring it to fragment where i need to show map. Please Help meSorrento
@Sorrento .. You simply need to define map frgament in your layout. :) .. Also don't forgot to include google key and other credentials in your manifest file.Nickinickie
@Nickinickie : As you set :: bundle.putString("cat", m_ArrayList.get(arg2).cat);. So in replacive fragment, how can we get set value from bundle ??Ruthenious
if(getArguments() != null){ Bundle bundle = this.getArguments(); //cat = bundle.getString("cat", ""); title = bundle.getString("title");}else{// Do what ever you wish }Nickinickie
Thanks a lot man!! Your Code rocks in ma PC. Very nicely elaborate. Its logic is very similar to GroupActivity. Fragments are new for me so this helped me a lot.Copyreader
This is an awesome answer ... Cheers [+1] :)Hirschfeld
Hi AndroidHacker, i have one issues when i user this, ((BaseContainerFragment)getParentFragment()).replaceFragment(fragment3, false); it's forward to new fragment, but when i press on back button creat issues, so last fragment and also show new fragment, how to solve this issues, please help me.Litigious
How to remove previous all fragment.Litigious
krunal sorry I didn't get U on this. and as far reloading of fragment is concerned you need to make use of OnSaveInstance (might be I mentioned wrong method name) method to accomplish this task. You can also perform this task using Boolean check. which will check whether this activity is loaded for first or second time.Nickinickie
what if I m not using FragmentTabHost ??Sodality
@Nickinickie Charming solution, I want exactly this one. 1+Egide
Is it possible to use this solution, except make the swap of fragments within an activity that extends actionbaractivity? #25629548Verbenaceous
Nope .. for that you need to make use of ViewPager. :)Nickinickie
@AndroidHacker. I am using onActivityResult() method in "Talk" fragment class. But this method is not execute in this class. Instead of that it is execute in 1st in "TalkContainerFragment" class and 2nd "Home" class. Please give me solution to invoke onActivityResult() method in "Talk" fragment class. Thanks in advance.Secern
@AndroidHacker. Here is my code for pick image from gallery. Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, REQUEST_GALLERY);Secern
Thank you for this. It was exactly what was needed for replacing of one of the fragments/tabs to work in my app. Good work. :DAudit
@Nickinickie hi...hope u'll reply. I have used your code to open nested fragment inside each fragment tab but since i use view pager to change tabs by swipe.It goes back to main activity on back button press instead of going to previous Fragment.Cathern
@Nickinickie I have similar issue like this..check here..#28107444 you help?Orphanage
Awesome answer... still helping ppl... thanks dude! very elaborateWherever
Thanks for the answer! I'm trying to figure out how to get it working with different menu options now :)Abessive
@Abessive .. May you please be more specific with the scenario, so that I can be very specific to put up the solution :)Nickinickie
I got it working actually! I had to make sure to call: getActivity().invalidateOptionsMenu(); so that the appropriate menus would be set. If I didn't do that, the menus wouldn't change when switching tabs.Abessive
@Nickinickie : hi, is it possible to replace the fragment from the Home class it self. ?Springhead
@Nickinickie ..Could you help me...Actually i have stucked in the problem that..on tab change i have to show Tab fragment instead of sub fragment of that tab... So plz help me to sort out from these problemLinneman
Excellent tutorial! Implementation was flawless, but now im stuck at this, lets say i go to TalkDetail fragment = new TalkDetail(); and once in that fragment go to TalkItem fragment = new TalkItem(); this is giving me an error Recursive entry to executePendingTransactions any help here will be appretiatedWherever
@ RonEskinder : Try replacing Fragments using BaseContainerFragment class.Nickinickie
@Nickinickie First of all, crispy tutorial!!! I still don't get how to open a new fragment because it keeps throwing out NullPointerException. Can you help me with that? Here is my Code: dropbox.com/sh/8l0w0ccj7igv8nx/AAD_B4mSibsB767Wtz4AT6kRa?dl=0 It's the onClick in the OpenedFragmentOptic
@Nickinickie Can you help me on this #41359576Fae
i did this with a viewpager and tablayout over here if anyone wants to see: #44743926Jack

© 2022 - 2024 — McMap. All rights reserved.