I have a problem with fragments. In my xml file I have a fragment already set there, I want with the click of a button replace it with another fragment. So with my code I can replace the fragment with the one that I want on the click of the button, but the first fragment wont disappear, so I can still see it under my second fragment, the code it's this:
public class MainActivity extends AppCompatActivity {
FragmentManager fragmentManager;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment,new BlankFragment2());
fragmentTransaction.addToBackStack(null).commit();
}
});
}
}
Set a background color of the root layout of the second fragment and put clickable and focusable true in xml file. It will make disappear of the first fragment and also disable the clicks of first fragment when showing another fragment.
Remove addToBackStack(null).
That stores the Fragment and keeps it attached so that calling popBackStack() will remove the top Fragment and replace it with the previous.
correctly implementing addToBackStack will help in this case and many other
addToBackStack takes an argument which is called task record TAG , To perform a transaction later on , you can use this tag to remove back stack up to a point
For more understanding read
https://medium.com/#bherbst/managing-the-fragment-back-stack-373e87e4ff62
Related
As an exercise i am writing a simple Ebook reader app. This has only 1 Main Activity with 3 widgets on it, 2 buttons (Previous, Next) and one Fragment container(I have used Frame Layout). All pages are different fragments that I have created that will go inside the container, and these fragments have only 1 scrollable text view that will only display text. when "next" button is pressed it should go to page2(fragment2) and when previous is pressed it should go back(previous fragment).
My problem is I don't want the "previous" button to show up on the initial screen (page1) and similarly the "next" button should not be observed on the last page.
The approach i tried was, in my fragment1(page1) class, i wrote an if condition like,
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragmentpage1,container,false);
textView1=(TextView)view.findViewById(R.id.tview);
**View listView = getActivity().findViewById(R.id.previous);**
textView1.setText(R.string.page1);
if (textView1.isEnabled()){
listView.setVisibility(View.INVISIBLE);
}
return view;
}
I am checking if textview1(the first fragment) is present or not , if yes then hide the previous button on the Main Activity. This works but it completely hides the previous button even when i go to page2. I tried all possible "is" options but none of them are giving me the results I want.
One workaround that i found was to add "setvisibility" of previous button to all fragments, so on fragment1 it is invisible and then on fragment2 i changed that to visible. But that becomes lengthy if there are 100s of fragments(pages).
Please provide me with a simple solution, I am new to Android.
Below is my Main Activity code:(Do let me know if any changes needs to be done to make code more clean)
public class MainActivity extends FragmentActivity {
Fragment fragment;
FragmentManager fm=getSupportFragmentManager();
FragmentTransaction ft;
private static Button next;
private static Button previous;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
next=(Button)findViewById(R.id.next);
previous=(Button)findViewById(R.id.previous);
create();
}
public void create(){
fragment= new FragmentPage1();
ft= fm.beginTransaction();
ft.add(container,fragment);
ft.commit();
}
public void next(View view){
fragment= new FragmentPage2();
ft= fm.beginTransaction();
ft.replace(container,fragment);
ft.commit();
}
}
Maybe you can try to use the getItem() method in FragmentPagerAdapter class.
Try to disable or enable your buttons using the switch case. Hope this can help =)
I wonder if there's a way to add a fragment into the backstack just behind the showing fragment. So that when a user press "back button" the added fragment would show up to the user.
As per my knowledge I am not sure the Fragment Manager can do such things !
Step-1: Why don't you add the fragment tobackStack` when mounting the fragment to the container
Step-2: Next onBackpressedor click of any view just pop the fragment from the container
Here is a sample from another Stackoverflow answer
fragmentTransaction.addToBackStack("fragB");
fragmentTransaction.addToBackStack("fragC");
Then in Fragment_C, pop the back stack using the name ie.. fragB and include POP_BACK_STACK_INCLUSIVE
someButtonInC.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fm = getActivity()
.getSupportFragmentManager();
fm.popBackStack ("fragB", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
});
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.
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.
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..
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();
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).
Make your activity implement the interface, or make an anonymous class within the activity implement it.
Make a paramerized constructor of your fragment, which accepts a IChangeListener parameter.
When initializing the fragment, pass your IChangeListener implementation (the anonymous class or the activity, implementing it)
Make the onClick listener of the button call the changing method of the IChangeListener.
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
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;
}
I got the next FragmentActivity. This FragmentActivity inflates a layout with a LinearLayout(a menu where some buttons are defined to call other fragments) and a FrameLayout (a black space where the other fragments are loaded depending the button I select).
public class MenuViewActivity extends FragmentActivity {
....
I load the selected Fragment using onClickListener:
protected void onCreate(Bundle savedInstanceState) {
....
final OnClickListener fragment_1 = new OnClickListener() {
#Override
public void onClick(View v) {
fragment_1 Fragment = new fragment_1();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, Fragment);
transaction.addToBackStack(null);
transaction.commit();
}
};
I do this for about 5 buttons. This menu also contains a custom back key. The functionality of this back button should be like:
[fragment_1][fragmen_2][fragment_3][fragment_4][fragment_5]
The app starts always showing fragment_1. I con go from fragment_1 to any of the other fragments. So I could go for example from [fragment_1] to [fragment_4]. When pressing the back key I should go back to [fragment_1].
To detail a little bit more the functionality, I could do: [fragment_1]->[fragment_2]->[fragment_3] and when pressing back, should go back to [fragment_1].
I've got a onClickListener for the back key, but I don't know how to implement this functionality.
you're looking for this
getSupportFragmentManager().popBackStack();
also if you're unaware that's the default functionality for the actual android back button, so unless you've overrode it that will do the same thing.
You just need to pop all fragments from your backstack, unless you reach the one you want. It is probably simplest to use FragmentManager's popBackStack():
public abstract void popBackStack (int id, int flags)
Pop all back stack states up to the one with the given identifier
I'm using an OnClickListener to do a fragment replacement. I'm toggling 3 LinearLayouts to 'GONE' within the OnClickListener also.
I would like to add a function to set the 3 LinearLayouts back to VISIBLE when the back button is pressed. The fragments swap back, but the LinearLayouts don't change their state.
Any help is appreciated, thanks!
final OnClickListener swapFragments = new OnClickListener() {
#Override
public void onClick(View v) {
if (myAdapter.isEmpty() != true) {
FragmentTransaction ft = getFragmentManager()
.beginTransaction();
FragmentTwoTop ftt = new FragmentTwoTop();
FragmentTwoBottom ftb = new FragmentTwoBottom();
ft.replace(R.id.leftTopHolder, ftt, "fragmenttwotop");
ft.replace(R.id.leftBottomtHolder, ftb, "fragmenttwobottom");
layoutOne.setVisibility(View.GONE);
layoutTwo.setVisibility(View.GONE);
layoutThree.setVisibility(View.GONE);
ft.addToBackStack("swapfragments");
ft.commit();
} else {
}
}
};
You could try adding a listener to the backstack: http://developer.android.com/reference/android/app/FragmentManager.html#addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener)
It will be called any time "something" is added or removed from/to the backstack.
You can then check the type of the class of the fragment (or maybe your holding the current fragment in a class - your Activity - variable) to decide if it's necessary to execute your animation.
The method in which you manage the layouts could simply check the visibility (getVisibility) and if it's VISIBLE then set to GONE, if it's GONE set to VISIBLE.