20

It's taken me some time to wrap my head around fragments, but this should be my last question on fragments, since I think I just about have them down. I know this is a huge mess of code to go through. But I'd appreciate the help, to make sure I'm not breaking any fundamental rules with fragments.

I am going to post all of my code just to see if someone can "look over it" to see if I'm making any major mistakes or if I should go a simpler route. Lastly, as stated in the title, my fragment is NOT being replaced... it'd being added on top.

File Tree:

enter image description here

MainActivity.java:

package com.example.learn.fragments;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends FragmentActivity{

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    /* Add a class to handle fragment */
    public static class SSFFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View v = inflater.inflate(R.layout.choose_pill_frag, container,
                    false);
            return v;
        }
    }

    public void red(View view) {


        // Create new fragment and transaction
        ExampleFragments newFragment = new ExampleFragments();
        android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frag, newFragment);
        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

    public void blue(View view) {
        //Figure out code for "red" first
    }

}

ExampleFragments.java:

package com.example.learn.fragments;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ExampleFragments extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.red_pill_frag, container, false);
    }
}

ActivityMain.xml:

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

    <fragment
        android:id="@+id/frag"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.example.learn.fragments.MainActivity$SSFFragment" />

</RelativeLayout>

choose_pill_frag.xml

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

    <ImageButton
        android:id="@+id/imageButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:onClick="blue"
        android:src="@drawable/blue" />

    <ImageButton
        android:id="@+id/imageButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:onClick="red"
        android:src="@drawable/red" />

</RelativeLayout>

red_pill_frag.xml

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

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="You stay in Wonderland and I show you how deep the rabbit-hole goes."
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

The application should show two buttons. The two buttons exist in a single fragment, and then if you hit a button, the fragment gets replaced with a new fragment that shows the proper text. As of right now, it should replace, but it only seems to add it on top.

EGHDK
  • 17,818
  • 45
  • 129
  • 204
  • 2
    I had the same problem, almost made me not want to use fragments any more, I had to remove the old fragment and then replace it for some stupid reason? – FabianCook Jul 23 '12 at 22:17
  • Glad to know I'm not alone in this boat. – EGHDK Jul 23 '12 at 22:22
  • 2
    No, you are not alone. Unless I really, really, really need a dynamic view, old fashioned activities are the way to go. I'm tempted to even write my own preferences activity with get and put shared preferences coded. Google made way to many preprep and postprep steps to the process. And why have an inflator. Stating that it's a fragment and just using a swap in or swap out function should be enough. – Howard Hodson Jul 24 '12 at 00:30

5 Answers5

26

Instead of <fragment> use <FrameLayout> in layout xml for activity.

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

Then in FragmentActivity in onCreate add initial fragment (in your case SSFFragment):

    FragmentA fragmentA = new FragmentA();
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.add(R.id.container_id, fragmentA);
    transaction.commit();

From inside fragment you can replace fragment in container.

class FragmentA extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        Button button = new Button(getActivity());
        button.setText("Replace");
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                FragmentB fragmentB = new FragmentB();
                transaction.replace(R.id.container_id, fragmentB);
                transaction.commit();
            }
        });
        return button;
    }
}
pawelzieba
  • 16,082
  • 3
  • 46
  • 72
  • This isn't the exact answer I was looking for (pertaining to my example), but it does give you a general idea when starting out with fragments. Thanks – EGHDK Aug 04 '12 at 21:18
  • @EGHDK, check out my answer to your age old question of, "what the fragment is going on??!?!" – whyoz May 08 '13 at 22:51
4

Here is the answer to your real question...since this was your second question resulting from your original post, I've modified the solution to get at that frag in another way:

Fragment details = (Fragment)getSupportFragmentManager().findFragmentById(R.id.details);
details = new ExamplesFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();

Also, the android.support.v4.app part is just not necessary, and frankly leads to possible hours of "going down the wrong road" type efforts by adding and removing it all over your code (as long as you're using:)

import android.support.v4.app.FragmentTransaction;

In this my example, you don't need to import the support for FragmentManager. However, if you're getting errors, make sure you've imported the library itself into your "libs" folder.

This solution will fix the overlapping fragment problem, and hopefully save people hours of tinkering around with replacing frags.

Community
  • 1
  • 1
whyoz
  • 5,168
  • 47
  • 53
  • "ft.replace(R.id.details, details);" R.id.details is the ID of your old fragment. Shouldn't it be the ID of the container in which all the fragments are? – Yar Jun 22 '16 at 18:04
  • @Yar I'd have to revisit that code with new APIs and the like, but you would think so wouldn't you? – whyoz Jul 05 '16 at 22:57
  • that id not the idea of your old fragment, it should be the id of the container. – Brill Pappin Jan 17 '17 at 19:19
2

well i was facing the same problem and i just replace the fragment from main layout with linear lay out and guess what its working.. its strange dont know how but its working. i am using actionbar to switch between fragments for replacing my code is :

 protected class MyTabsListener1 implements ActionBar.TabListener{
        private Fragment frag ;
        public MyTabsListener1 ( Fragment frag){
            this.frag = frag;
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            //  TODO Auto-generated method stub

        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {

                switch (tab.getPosition()){
                case 0:

                        ft.replace(R.id.replace, homeFrag);
                    break;

                case 1:
                    ft.replace(R.id.replace, createFrag);
                        break;

                case 2:
                    ft.replace(R.id.replace, ioListFrag);
                    break;
                case 3:

                    ft.replace(R.id.replace, settingFrag);

                    break;      


                default: 


                    break;

                }

            }

and my main layout is this :

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

</LinearLayout>
grv_9098
  • 465
  • 5
  • 16
1

In short, you CAN NOT replace fragment if u defined it in XML with fragment tag. Instead, as @pawelzieba adviced add Frame tag in your layout, find it and add,remove, replace fragments there.. Hope it helped. Cheers

Ewoks
  • 12,285
  • 8
  • 58
  • 67
  • This is the correct answer. Use a layout instead of declaring the fragment in the layout.xml file. I asked the same question earlier; http://stackoverflow.com/questions/8903874/can-i-remove-a-fragment-defined-in-a-layout-xml-file – Glenn Bech Aug 03 '12 at 12:05
0

The main benefit of using fragments is to be able to make them take up portions of the screen rather than the whole screen, which is what Activities do.

If you're just making an app for a small screen that will function like an Activity, but is coded in Fragments, just make a separate FragmentActivity for each of your Fragments.

Make this the onCreate of your FragmentActivity:

public void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.emptylayout);

    FragmentManager fragmentManager = getSupportFragmentManager(); //Or getFragmentManager() if you're not using the support library
    FragmentTransaction fragmentTransaction = fragmentManager
            .beginTransaction();
    YourFragment fragment = new YourFragment();
    fragmentTransaction.add(R.id.emptyview, fragment);
    fragmentTransaction.commit();
}

Where layout/emptylayout is an XML layout file with a FrameLayout. id/emptyview is that FrameLayout.

If you want to use XML for your fragment's actual layout, make a separate XML layout for the actual fragment, and inflate it in the fragment's `onCreateView':

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.files, container, false);
            // Do stuff here
    return view;
}

Then just use startActivity(new Intent(getActivity(), YourFragmentActivity.class)) to launch a FragmentActivity from a Fragment.

It seems redundant, yeah, but if you're going to be targeting larger screens later (if not, why are you bothering with fragments?), it'll make it easier in the long run.

Steven Schoen
  • 4,366
  • 5
  • 34
  • 65