18

I have an activity containing multiple fragments. Activity initially have fragment and in it have two buttons. Upon clicking this button I have to replace the fragment by new fragment. Each fragment has various widgets and replace the current fragment as various events.

This is my problem. How can I achieve this?

Suggest me ideas.

Kaiser
  • 606
  • 8
  • 22
Top Cat
  • 2,473
  • 3
  • 22
  • 34
  • 1
    why can you not just change the visibility of the fragments? – Scary Wombat Jan 20 '14 at 07:56
  • 1
    Pass callback to activity and let it replace fragment. To do this just create interface with callback and implement it in Activity. Then in Fragment override onAttach(activity) function and store the interface for onClick – Androider Jan 20 '14 at 07:57

6 Answers6

23

you can replace fragment by FragmentTransaction.

Here you go.

Make an interface.

public interface FragmentChangeListener 
{
    public void replaceFragment(Fragment fragment); 
}

implements your Fragment holding activity with this interface.

public class HomeScreen extends FragmentActivity implements
        FragmentChangeListener {


         @Override
         public void replaceFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();;     
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(mContainerId, fragment, fragment.toString());
            fragmentTransaction.addToBackStack(fragment.toString());
            fragmentTransaction.commit();   
    }

}

Call this method from Fragments like this.

//In your fragment.

public void showOtherFragment()
{
       Fragment fr=new NewDisplayingFragment();
             FragmentChangeListener fc=(FragmentChangeListener)getActivity();
             fc.replaceFragment(fr);
}

Hope this will work!

NOTE: mContainerId is id of the view who is holding the fragments inside. You should override Fragment's onString() method as well.

Ahmad Raza
  • 2,850
  • 1
  • 21
  • 37
  • 1
    the question is how to call the method in the activity from the containing fragment, not what the method should look like – Mario Stoilov Jan 20 '14 at 08:19
  • @MarioStoilov: Sorry, i have updated my answer, Please try it. – Ahmad Raza Jan 20 '14 at 09:05
  • 1
    **You should override Fragment's onString() method as well** What is this means? – Top Cat Jan 21 '14 at 06:29
  • By Overriding onString() method, you can assigned a unique name to each fragment, like you can return "myFragment" from onString() method of fragment. Now, suppose you need to search fragment in FragmentBackStack, Then you can search it by using onString() response. which is "myFragment" string.. – Ahmad Raza Jan 21 '14 at 19:02
  • One more doubt. each fragments value should be available to next fragments also. How can i pass arguments to fragment when i call ' fc.replaceFragment(fr); ' ? i used ' fragment.setArguments(args); ' . Each fragment is separate classes. – Top Cat Jan 22 '14 at 05:20
  • @Rashid: Here is the way to pass the arguments to fragments: http://stackoverflow.com/a/15459259/2105241 – Ahmad Raza Jan 22 '14 at 09:49
  • for the mContainerId, can I do fragment.getView().getId()? – Ray Mar 26 '19 at 15:37
  • Thanks you so much brother. This is what I had been looking for. And really worked well for me. Much appreciated. Good one. – Parmendra Singh Aug 10 '21 at 06:03
7

Well even I am learning android...

I solved same problem recently, "How to Change Fragment On button's click event".

buttonName.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        FragmentTransaction fragmentTransaction = getActivity()
            .getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.frame1, new Homefragment());
        fragmentTransaction.commit();
    }
});

Here frame1 is id of FrameLayout which have define in my DrawerLayer's XML.

So now whenever I want fragment transaction I use this code. Each time it will replace frame1 instated of your last fragment.

FragmentTransaction fragmentTransaction = getActivity()
        .getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame1, new newfragment());
fragmentTransaction.commit()

Hope this will help..

Stanley Ko
  • 3,383
  • 3
  • 34
  • 60
Deep Bhatt
  • 89
  • 1
  • 5
2

You can use the following to replace a fragment on button click of that fragment:

getFragmentManager().beginTransaction().replace(R.id.main_content, new insertFragmentNameHere()).addToBackStack(null).commit();
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
  • Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). Thanks – sɐunıɔןɐqɐp Aug 21 '18 at 23:41
1
  1. Define an interface and call it IChangeListener (or something like that) and define a method inside which will do the work (ex, changeFragment()) (or call another method which will do the work) for changing the fragment).
  2. Make your activity implement the interface, or make an anonymous class within the activity implement it.
  3. Make a paramerized constructor of your fragment, which accepts a IChangeListener parameter.
  4. When initializing the fragment, pass your IChangeListener implementation (the anonymous class or the activity, implementing it)
  5. Make the onClick listener of the button call the changing method of the IChangeListener.
Mario Stoilov
  • 3,411
  • 5
  • 31
  • 51
  • I know that this is the recommended method. But, can you tell me the advantages of using this over just calling getActivity().changeFragment() from the fragment's onClick? – Srikanth Jan 20 '14 at 08:03
  • @Srikanth If you call getActivity(), you will get an object of type Activity(the base class, not your implementation) and you will have to cast it to to your implementation of the activity, which makes you dependant on this particular implementation, while when you use an Interface, the class that implements it could be everything (fragment in a fragment, fragment in a listview, etc.) and that wont bother you, so you can reuse this code for different purposes – Mario Stoilov Jan 20 '14 at 08:07
  • Seems a lot cleaner and reusable that way. Thanks for clarifying. I think you need to update your answer a bit. When you use parameterized constructor for a fragment, eclipse throws a warning - http://stackoverflow.com/questions/12062946/why-do-i-want-to-avoid-non-default-constructors-in-fragments . Android recommends the use of onAttach(Activity) as mentioned here - http://developer.android.com/training/basics/fragments/communicating.html – Srikanth Jan 20 '14 at 08:16
1

From the future 2017 and after, there exists different libraries that triggers Events using Bus and now you can use it to tell the activity when an event is trigger in a fragment that it owns.

Refer to:

RxBus with RxJava

You can check new architectures suggested by Google

ViewModel

Don't use the approach in the accepted answer, get really ugly with more than 3 different events from fragments

Erick Moya
  • 31
  • 1
  • 1
  • Why do you think this will fall under Observer Pattern? I think that will be an over kill – Bavan Oct 29 '18 at 06:31
0

you can try this code it's work fine with me , inflate the layout to view , Define the buton and on click ,

Button btn_unstable;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_home,container,false);

    btn_unstable = (Button)view.findViewById(R.id.btn_unstable);
    btn_unstable.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
    getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_replace, new UnstableFragment()).commit();

        }
    });
    return view;
}