94

I tried making a navigation between fragments. I've got the NewFragment.java with the new fragment working. My problem is:

How do I make this onClickListener run NewFragment.java correctly?

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {

        Intent i = new Intent(getActivity(), NewFragment.class);
        startActivity(i);

    }
});

FYI: This is from inside a fragment (I don't know if that matters).

nbro
  • 15,395
  • 32
  • 113
  • 196
Hultan
  • 1,409
  • 1
  • 15
  • 28
  • IMPORTANT: When working with fragments, navigations is closely related to host acivity so, you can't justo jump from fragment to fragment without implement that fragment class in host Activity. Sample: `public class MyHostActivity extends AppCompatActivity implements MyFragmentOne.OnFragmentInteractionListener {` Also, check your host activity has the next override function: ` @Override public void onFragmentInteraction(Uri uri) {} ` Hope this helps... – Gerry R Mar 27 '19 at 19:11

14 Answers14

176

Add following code in your click listener function,

NextFragment nextFrag= new NextFragment();
getActivity().getSupportFragmentManager().beginTransaction()
             .replace(R.id.Layout_container, nextFrag, "findThisFragment")
             .addToBackStack(null)
             .commit();

The string "findThisFragment" can be used to find the fragment later, if you need.

nbro
  • 15,395
  • 32
  • 113
  • 196
Narendra
  • 1,824
  • 1
  • 11
  • 4
  • 22
    what will be `Layout_container`? – Shailendra Madda Mar 10 '17 at 11:43
  • 8
    can anyone clarify what `Layout_container` should be? – Huw Davies Jul 17 '18 at 06:05
  • 9
    Layout_container is the id of current fragment. I would recommend using ((ViewGroup).getView().getParent()).getId() instead of R.id.Layout_container. – BTR Naidu Aug 10 '18 at 16:00
  • layout_container is the id of view present in activity layout where you want to replace a fragment – Asad Ali Mar 21 '19 at 06:13
  • 13
    @BTRNaidu Should be: ((ViewGroup)getView().getParent()).getId(); – KvnH Apr 18 '19 at 15:10
  • Very important if you want to actually replace the old fragment and not just display the new one next to the old one: Don't declare any fragments inside the container's (e.g. "Activity1", while the fragments are "A1F1" and "A1F2") xml file (as described [here](https://developer.android.com/guide/components/fragments#Adding)), instead do it at runtime (as described [here](https://developer.android.com/training/basics/fragments/fragment-ui#AddAtRuntime)), which also requires the container to be a `FrameLayout` (not an e.g. `LinearLayout`)! – Neph Feb 26 '20 at 14:10
  • 4
    Kotlin version: ((view as ViewGroup).parent as View).id – James Bond Jul 15 '20 at 19:01
  • How should i use this line of code in a customadapter class that extends listadapter? i get error getContext() can not be resolved – stefanosn Nov 26 '20 at 21:21
12

This is more described code of @Narendra's code,

First you need an instance of the 2nd fragment. Then you should have objects of FragmentManager and FragmentTransaction. The complete code is as below,

Fragment2 fragment2=new Fragment2();
FragmentManager fragmentManager=getActivity().getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_main,fragment2,"tag");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Hope this will work. In case you use androidx, you need getSupportFragmentManager() instead of getFragmentManager().

Marco
  • 1,073
  • 9
  • 22
Nipuna Dilhara
  • 424
  • 2
  • 6
  • 18
6

Use this,

AppCompatActivity activity = (AppCompatActivity) view.getContext();
Fragment myFragment = new MyFragment();
activity.getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, myFragment).addToBackStack(null).commit();
nbro
  • 15,395
  • 32
  • 113
  • 196
Parinda Rajapaksha
  • 2,963
  • 1
  • 36
  • 40
  • I get error addView(View) is not supported in AdapterView when i use this code inside customadapter that extends from listadapter...how should be changed? – stefanosn Nov 26 '20 at 21:53
5

You should create a function inside activity to open new fragment and pass the activity reference to the fragment and on some event inside fragment call this function.

nbro
  • 15,395
  • 32
  • 113
  • 196
vipul mittal
  • 17,343
  • 3
  • 41
  • 44
  • 3
    From inside a fragment you automatically already have a reference to the parent activity. Use getActivity() or if you use onAttach the activity is in the arguments. – miva2 Sep 21 '15 at 14:24
2
@Override
public void onListItemClick(ListView l, View v, int pos, long id) {
    super.onListItemClick(l, v, pos, id);
    UserResult nextFrag= new UserResult();
    this.getFragmentManager().beginTransaction()
    .replace(R.id.content_frame, nextFrag, null)
    .addToBackStack(null)
    .commit();  
}
Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
2

Using Kotlin to replace a Fragment with another to the container , you can do

button.setOnClickListener {
    activity!!
        .supportFragmentManager
        .beginTransaction()
        .replace(R.id.container, NewFragment.newInstance())
        .commitNow()
}
All Іѕ Vаиітy
  • 24,861
  • 16
  • 87
  • 111
2

use this in adapter/fragment all previous methouds are expired now

((AppCompatActivity) context).getSupportFragmentManager().beginTransaction().replace(R.id.container,new cartFragment()).commit();
2

My how things do change in 8 years time. If you are using NavigationController in your app this is very simple. In your mobile_navigation.xml file you need to create "from" and "to" fragments. In the "from" fragment add the destination id of the "to" fragment.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@+id/nav_home">

    <fragment
        android:id="@+id/nav_home"
        android:name="com.yourpackage.FromFragment"
        android:label="@string/menu_home"
        tools:layout="@layout/from_fragment" >
        <action android:id="@+id/action_go"
            app:destination="@id/dest_fragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim"
            app:popEnterAnim="@anim/nav_default_pop_enter_anim"
            app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
    </fragment>

    <fragment
        android:id="@+id/dest_fragment"
        android:name="com.yourpackage.ToFragment"
        android:label="To Fragment"
        tools:layout="@layout/to_fragment" />
</navigation>

Then in your onClick handler call:

Navigation.findNavController(view).navigate(R.id.action_go);

This page provides more details including how to set up the destination programmatically.

https://developer.android.com/guide/navigation/navigation-navigate

Lehrian
  • 347
  • 1
  • 2
  • 9
1

Well my problem was that i used the code from the answer, which is checked as a solution here, but after the replacement was executed, the first layer was still visible and functionating under just opened fragment. My solution was simmple, i added

.remove(CourseListFragment.this)

the CourseListFragment is a class file for the fragment i tried to close. (MainActivity.java, but for specific section (navigation drawer fragment), if it makes more sense to you) so my code looks like this now :

LecturesFragment nextFrag= new LecturesFragment();

                    getActivity().getSupportFragmentManager().beginTransaction()
                            .remove(CourseListFragment.this)
                            .replace(((ViewGroup)getView().getParent()).getId(), nextFrag, "findThisFragment")
                            .addToBackStack(null)
                            .commit();

And it works like a charm for me.

Maris S.
  • 51
  • 1
  • 12
  • I guess this is the correct solution. But I faced an exception in this case: java.lang.IllegalStateException: Cannot remove Fragment attached to a different FragmentManager. Fragment FileListFragment{206d1c0} (2d135556-b398-4f1f-a282-ba9b19dad5ae id=0x7f09015c) is already attached to a FragmentManager. – bvn13 Apr 19 '23 at 09:21
1

a simple option is to navigate to the second fragment by defining an action in the nav_graph.xml and then use it like this (example for Kotlin):

rootViewOfFirstFragment.someBtn.setOnClickListener{
            Navigation.findNavController(rootViewOfFirstFragment)
                .navigate(R.id.action_firstFragment_to_secondFragment)
        }
0
 Fragment fr = new Fragment_class();
             FragmentManager fm = getFragmentManager();
            FragmentTransaction fragmentTransaction = fm.beginTransaction();
            fragmentTransaction.add(R.id.viewpagerId, fr);
            fragmentTransaction.commit();

Just to be precise, R.id.viewpagerId is cretaed in your current class layout, upon calling, the new fragment automatically gets infiltrated.

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Mbanda
  • 968
  • 11
  • 21
0

Adding to @Narendra solution...

IMPORTANT: When working with fragments, navigations is closely related to host acivity so, you can't justo jump from fragment to fragment without implement that fragment class in host Activity.

Sample:

public class MyHostActivity extends AppCompatActivity implements MyFragmentOne.OnFragmentInteractionListener {

Also, check your host activity has the next override function:

@Override public void onFragmentInteraction(Uri uri) {} Hope this helps...

Gerry R
  • 392
  • 3
  • 3
0

first of all, give set an ID for your Fragment layout e.g:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
**android:id="@+id/cameraFragment"**
tools:context=".CameraFragment">

and use that ID to replace the view with another fragment.java file. e.g

 ivGallary.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          UploadDoc uploadDoc= new UploadDoc();
          (getActivity()).getSupportFragmentManager().beginTransaction()
                  .replace(**R.id.cameraFragment**, uploadDoc, "findThisFragment")
                  .addToBackStack(null)
                  .commit();
      }
  });
Jatin
  • 17
  • 2
0

For Kotlin simply you can use this,

First: Create new instance of the fragment

val newFragment = NewFragment.newInstance()

Second: Start the fragment transaction

val fragmentTransaction: FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()

Third: Replace current fragment with new fragment ( tips: avoid using id of the container view like R.id.fl_fragment, you may face view not find error, just use is at mentioned below)

fragmentTransaction.replace(
 (view!!.parent as ViewGroup).id,newFragment
)

Final Steps:

fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
Aathil Ahamed
  • 460
  • 4
  • 16