41

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.

fllo
  • 11,595
  • 5
  • 39
  • 95
kalyan pvs
  • 14,495
  • 3
  • 39
  • 57

1 Answers1

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!

Skynet
  • 7,522
  • 5
  • 40
  • 78
AndroidHacker
  • 3,588
  • 22
  • 44
  • 5
    great job..really you are a hacker..this is what I am looking for. +1 with thanks. – Ketan Ahir Feb 06 '14 at 07:19
  • 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 me – user2199280 Feb 14 '14 at 11:44
  • @user2199280 .. 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. – AndroidHacker Feb 17 '14 at 04:23
  • @AndroidHacker : As you set :: bundle.putString("cat", m_ArrayList.get(arg2).cat);. So in replacive fragment, how can we get set value from bundle ?? – MS. Feb 24 '14 at 12:17
  • if(getArguments() != null){ Bundle bundle = this.getArguments(); //cat = bundle.getString("cat", ""); title = bundle.getString("title");}else{// Do what ever you wish } – AndroidHacker Feb 25 '14 at 11:10
  • 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. – Sagar Shah Apr 07 '14 at 13:44
  • This is an awesome answer ... Cheers [+1] :) – Devrath Apr 25 '14 at 08:31
  • 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. – Krunal Indrodiya May 14 '14 at 07:08
  • How to remove previous all fragment. – Krunal Indrodiya May 14 '14 at 07:14
  • 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. – AndroidHacker May 15 '14 at 04:19
  • what if I m not using `FragmentTabHost` ?? – SweetWisher ツ Jun 05 '14 at 08:03
  • @AndroidHacker Charming solution, I want exactly this one. 1+ – Hiren Patel Aug 15 '14 at 17:14
  • Is it possible to use this solution, except make the swap of fragments within an activity that extends actionbaractivity? http://stackoverflow.com/questions/25629048/findfragmentbytag-is-returning-null-when-working-with-getsupportfragmentmanage – Lee Torres Sep 02 '14 at 18:01
  • Nope .. for that you need to make use of ViewPager. :) – AndroidHacker Sep 03 '14 at 07:12
  • @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. – Dhruv Sep 05 '14 at 11:32
  • @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); – Dhruv Sep 05 '14 at 11:54
  • 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. :D – wojciii Sep 10 '14 at 13:28
  • @AndroidHacker 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. – user3853169 Dec 15 '14 at 11:21
  • @AndroidHacker I have similar issue like this..check here..http://stackoverflow.com/questions/28106944/how-to-add-tabhost-with-navigation-drawer?noredirect=1#comment44592501_28106944..can you help? –  Jan 23 '15 at 13:25
  • 2
    Wow, this saved my job! Thanks, AndroidHacker! – hadez30 Apr 03 '15 at 04:04
  • 1
    Great answer. You are genius!! – Brandon Yang Jun 03 '15 at 03:44
  • Awesome answer... still helping ppl... thanks dude! very elaborate – RonEskinder Sep 11 '15 at 17:17
  • Thanks for the answer! I'm trying to figure out how to get it working with different menu options now :) – Dehli Oct 30 '15 at 16:40
  • @Dehli .. May you please be more specific with the scenario, so that I can be very specific to put up the solution :) – AndroidHacker Nov 03 '15 at 04:36
  • 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. – Dehli Nov 03 '15 at 14:41
  • @AndroidHacker : hi, is it possible to replace the fragment from the Home class it self. ? – DKV Nov 30 '15 at 05:46
  • @AndroidHacker ..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 problem – Ravindra Kushwaha Feb 17 '16 at 11:23
  • 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 appretiated – RonEskinder May 06 '16 at 20:37
  • @ RonEskinder : Try replacing Fragments using BaseContainerFragment class. – AndroidHacker May 09 '16 at 10:49
  • @AndroidHacker 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: https://www.dropbox.com/sh/8l0w0ccj7igv8nx/AAD_B4mSibsB767Wtz4AT6kRa?dl=0 It's the onClick in the OpenedFragment – Ron Jul 29 '16 at 10:30
  • @AndroidHacker Can you help me on this http://stackoverflow.com/questions/41359076/cannot-replacing-an-old-fragment-with-new-one-in-a-tabbed-activity/41359291#41359291 – Santanu Dec 31 '16 at 13:01
  • i did this with a viewpager and tablayout over here if anyone wants to see: https://stackoverflow.com/questions/44743426/android-viewpager-with-tablayout-how-to-add-another-fragment-on-top-of-a-tab/44744604#44744604 – j2emanue Jun 26 '17 at 02:47