Navigate among fragments within one activity

27,145

Solution 1

In the nutshell the answer to your question is to notify your host activity and then have your host activity replace your current fragment container using FragmentManager.

One of the approach is to make an interface in your first fragment, have your host activity register/listen (implement) to this interface and then have your FragmentManager to replace the container content with the second fragment on listener callback.

I'm not sure about tutorial but here is my snippet: First Fragment

public class First extends Fragment{
private static onMySignalListener listener;

//call this function from whatever you like i.e button onClickListener
public void switchWindow() {
    if(listener != null){
        listener.onMySignal();
    }
}

public interface onMySignalListener {
    //customize this to your liking

    //plain without argument
    void onMySignal();

    //with argument
    void onMySignalWithNum(int mNum);
}

public static void setOnMySignalListener(onMySignalListener listener) {
    First.listener = listener;
}}

Host Activity

public class HostActivity extends FragmentActivity implements onMySignalListener{
private final String ADD_TAG_IF_NECESSARY = "mTag";

@Override
public void onCreate(Bundle ssi) {
    setContentLayout(R.layout.main);

    FirstFragment.setOnMySignalListener(this);
}

@Override
public void onMySignal() {
    //if you're using compat library
    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();

    //initialize your second fragment
    sfragment = SecondFragment.newInstance(null);
    //replace your current container being most of the time as FrameLayout
    transaction.replace(R.id.container, fragment, ADD_TAG_IF_NECESSARY);
    transaction.commit();
}

@Override
public void onMySignalWithNum(int mNum) {
    //you can do the same like the above probably with your own customization
}}

This is only an example on how you'd implement interface, kindly tidy it up by yourself. And please be noted though that this is not effective if you have a lot of fragment wanting to notify your host activity about something. doing so will lead you to implement various listener to your host activity.

Solution 2

I think this will be useful for you. It is example of two fragments in one screen works independently.

MainActivity :

public class MainActivity extends Activity {

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

        Fragment newFragment = new Test();
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.add(R.id.UprLayout, newFragment);
        // transaction.addToBackStack(null);
        transaction.commit();

        Fragment newFragment2 = new TestRight(); 
        FragmentTransaction transaction2 = getFragmentManager().beginTransaction();
        transaction2.add(R.id.dwnLayout, newFragment2);
        // transaction.addToBackStack(null);
        transaction2.commit();
    }
}

main_activity.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center|center_horizontal"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/UprLayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical" />

    <LinearLayout
        android:id="@+id/dwnLayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical" />

</LinearLayout>

Fragment Test :

public class Test extends Fragment {
TextView tv;

@Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

    }

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

        View view = inflater.inflate(R.layout.test, container, false);
        return view;        
    }
}

Fragment TestRight :

public class TestRight extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.test_right, container, false);
        return view; 
    }

    @Override
    public void onStart() {
        super.onStart();
        Button button = (Button)getActivity().findViewById(R.id.button1);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Fragment newFragment = new Right2nd();
                FragmentTransaction transaction = getFragmentManager()
                        .beginTransaction();
                transaction.replace(R.id.dwnLayout, newFragment);
                transaction.addToBackStack("aa");
                transaction.commit();

                //transaction.add(R.id.frag, newFragment).commit();
            }
        });
    }
}

test.xml :

<?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:gravity="center"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="test"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="50sp" />

</LinearLayout>

test_right.xml :

<?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:gravity="center"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Test right"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="45sp" />

</LinearLayout>

Fragment Right2nd :

public class Right2nd extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View vw = inflater.inflate(R.layout.right_2nd, container, false);
        return vw;
    }
}

right_2nd.xml :

<?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:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Right 2nd"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="50sp" />

</LinearLayout>

Solution 3

I know this is quite old question but this is currently implemented in Navigation Component https://developer.android.com/guide/navigation/

Share:
27,145
Leem.fin
Author by

Leem.fin

A newbie in software development.

Updated on July 23, 2022

Comments

  • Leem.fin
    Leem.fin almost 2 years

    I would like to use one Activity which holds several fragments and navigate among the fragments. For example, in the activity, there is a list view which is a fragment, when user select one item from the list, the view will navigate to another fragment, How could this be implemented?

    I know there is a nice tutorial on the developer site, but it handles the tablet screen in which two pane layout with one list fragment and one detailed fragment showing in one screen. I only want to navigate among fragments without show two fragments in one screen.

    Are there tutorials can teach me how to do it?

  • Leem.fin
    Leem.fin over 12 years
    Hi, if I have a lot of fragments (about 5) want to notify my host activity, how to implement then?
  • Leem.fin
    Leem.fin over 12 years
    and Can I use fragment's onAttach() to set on the listener in host activity instead of your custom set on method ?
  • Raymond Lagonda
    Raymond Lagonda over 12 years
    Well, the most sophisticated notifying system in Android API is using BroadcastReceiver. You can replace the conventional java interface/listener using this class. Register a receiever in your host activity and from your namely five or more fragments you can simply send broadcast. To differentiate between your fragment you can use Intent which is sent along in sendBroadcast method. Check this out: BroadcastReceiver and probably google up for some example, I can't post my example in comments, cheers.
  • Gastón Saillén
    Gastón Saillén almost 5 years
    To solve the last problem , you should use ViewModel to share data between Fragments and Activity