8

I am creating a three tabs that contains one fragment each now I want to replace the first Tab's Fragment with a new Fragment within the same Tab. How can I do that with the tab remaining the same?

My Code -

Tab_Widget.java

    public class Tab_Widget extends TabActivity {

            TabHost tabHost; 

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

            tabHost = getTabHost();

            tabHost.addTab(tabHost.newTabSpec("Tab1")
                .setIndicator("Tab1")
                .setContent(new Intent().setClass(this, main_activity.class)));

            tabHost.addTab(tabHost.newTabSpec("Tab2")
                .setIndicator("Tab2")
                .setContent(new Intent().setClass(this, second_activity.class)));

            tabHost.addTab(tabHost.newTabSpec("Tab3")
                    .setIndicator("Tab3")
                    .setContent(new Intent().setClass(this, third_activity.class)));

            tabHost.setCurrentTab(0);
        }
     }

main_activity.java

public class main_activity extends FragmentActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainfragment);
    }
}

main_fragment.java

public class main_fragment extends Fragment
{
    LinearLayout mLayout;
    Button mButton;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        mLayout = (LinearLayout) inflater.inflate(R.layout.main_view, null);
        mButton = (Button) mLayout.findViewById(R.id.btn);
        mButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                Fragment mFragment = new third_fragment_view();
                FragmentTransaction ft = getFragmentManager().beginTransaction();
//              ft.replace(R.id.Maincontainer, mFragment);
                ft.replace(R.id.main_fragment, mFragment);
                ft.addToBackStack(null);
                ft.commit();
            }
        });
        return mLayout;
    }
}

My XML

mainfragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/Maincontainer"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment
  android:name="com.fragment.main_fragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/main_fragment">
</fragment>
</LinearLayout>

By, this the Fragment is getting called no doubt, but its overlapping the previous Fragment.

Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242

3 Answers3

7

You have a structure like so:

TabActivity
 -> Tab1 = FragmentActivity = MainFragment
 -> Tab2          
 -> Tab3          

From inside of MainFragment you are trying to replace the contents of its container (itself).

It would be best if the MainFragment called a customised TabActivity which in turn called a replace on it's container, either like so (Which may likely fall foul of the same problem as it's basically running the same code from the same place, but it should give you a basic idea of what I'm suggesting):

    Fragment newFragment = new FragmentToChangeTo();
    CustomTabActivity tabActivity = (CustomTabActivity) getActivity();
    tabActivity.changeFragment(newFragment);

If this doesn't work try doing a similar thing but instead of calling the activity directly pass commands to it through Intents & Actions (or Bundles) containing information on what to change which container to.

I would have preferred to say /why/ Fragments don't work well with Fragment-in-fragment and related intricacies: check here to see why I suggest cutting fragments out of the control of fragments.

Community
  • 1
  • 1
Graeme
  • 25,714
  • 24
  • 124
  • 186
  • @Greame I just want to replace a Fragment, not Fragment inside Fragment. – Lalit Poptani Aug 03 '11 at 15:50
  • Your mis-understanding. You ARE using a fragment to replace itself. At very best this is confusing and bad practice at worst it will never ever work (Unfortunately fragments aren't the most translucent process). Create a system where a fragment communicates with it's container to get it to replace its child with something else. – Graeme Aug 09 '11 at 08:11
  • Yes, now I got it that Fragments cannot replace itself, Thanks. :) – Lalit Poptani Aug 09 '11 at 08:47
5

OK, several things:

  1. You don't need both replace and remove. Replace effectively just removes the first fragment and adds the second in its place.

  2. I suspect that your arguments are incorrect for the replace command. This is the proper form:

    replace (int containerViewId, Fragment fragment)
    

    You seem to be passing the id of the fragment itself, rather than the id of the container. The replace command takes the id of the container view and removes all fragments in that container before adding a new one. So if this was your layout:

    <LinearLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
        <fragment class="com.example.stackoverflow.YourFragmentName"
        android:id="@+id/main_fragment"
        android:layout_weight="1"
        android:layout_width="0px"
        android:layout_height="match_parent" />
    
    </LinearLayout>
    

    You would use:

    replace(R.id.container, mFragment);
    

    and not

    replace(R.id.main_fragment, mFragment);
    
  3. Since you are trying to findFragmentById(R.id.main_fragment), I suspect that you have added this fragment to your XML layout file. If you have a fragment added directly in the XML, you cannot remove it programmatically at run time. In order to remove or replace fragments, you must have added them with a FragmentTransaction at run time.

EDIT:

Numbers 2 and 3 from my original answer still apply. You need to use the id of the containing ViewGroup for adding and replacing. In this case, that's your LinearLayout, R.id.Maincontainer, not R.id.main_fragment.

Also, as I said before, you cannot remove fragments that you have added directly in the XML. Your main_fragment is added in the XML and therefore cannot be removed at run time.

Try this for your mainfragment.xml:

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

    <Button
    android:id="@+id/btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Switch Fragments">

</LinearLayout>

And this for your main_fragment class:

public class main_activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainfragment);

        //Notice that I am adding this 1st fragment in the Activity and not the XML
        main_fragment mainFragment = new main_fragment();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.Maincontainer, mainFragment);
        ft.commit();

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

            @Override
            public void onClick(View v)
            {

                Fragment mFragment = new third_fragment_view();
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                //Replacing using the id of the container and not the fragment itself
                ft.replace(R.id.Maincontainer, mFragment);
                ft.addToBackStack(null);
                ft.commit();
            }
        });
    }
}
theisenp
  • 8,639
  • 5
  • 39
  • 47
0

@theisenp i am creating a tab view in that when a button is clicked it must move to another screen when i try to implement it using the above code it is changing to another screen but the button is still visible with next screen and i want next screen should cover entire screen

public class Tab1Fragment extends Fragment  {
LinearLayout mLayout;
/** (non-Javadoc)
 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
 */
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    if (container == null) {


        return null;
    }

    LinearLayout theLayout = (LinearLayout)inflater.inflate(R.layout.tab_frag1_layout, container, false);

            // Register for the Button.OnClick event

            Button b = (Button)theLayout.findViewById(R.id.button1);

            b.setOnClickListener(new View.OnClickListener() {



                @Override

                public void onClick(View v) {

                     Fragment mFragment = new third_fragment_view();
                     android.support.v4.app.FragmentTransaction ft = getFragmentManager().beginTransaction();

                     ft.replace(R.id.container, mFragment);
                     ft.addToBackStack(null);
                     ft.commit();   


                }

            });

    return theLayout;

}
}

activity is displaying partially

Ghouse
  • 516
  • 1
  • 8
  • 29