Android development, Closing fragment using toggle button - android

I think the issue is probably simple, but being pretty new to Java and to Android dev, I'm not really sure. What I'm trying to do is close a fragment that's been toggled on using a ToggleButton, but I can't find a way to then hide or close it. Any help would be appreciated.
Below is the code for the OnCheckChanged() listener.
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
MyFragment frag = new MyFragment();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.main_activity, frag, "Fragment1");
if(isChecked)
{
transaction.show(frag);
}
else
{
transaction.hide(frag);
//transaction.remove(frag);
}
transaction.commit();
}

Every time you hit onCheckedChanged, you are adding a NEW fragment and then either hiding or showing it. All other fragments you have previously created are still attached laid one on top of the other.
You should get the current fragment that is attached to the layout if there is one. If there isn't one already, create it and add it to the container.
For example, this should point you in the right direction.
private void HideFragment(){
// Get the fragment that is attached to the layout
Fragment frag=getFragmentManager().findFragmentById(R.id.centerFrame);
if (frag==null){
// The fragment does not exist yet so create one and add it
frag=new MyFragment();
getFragmentManager()
.beginTransaction()
.replace(R.id.centerFrame,frag)
.commit();
}
//Hide the fragment
getFragmentManager()
.beginTransaction()
.hide(frag)
.commit();
}
Update:
It is a little ambiguous what you are actually trying to achieve. You keep saying "close" the fragment but your code suggests you just want to toggle its visibility on and off.
If you actually want to completely remove the fragment then you should use the Remove method of the FragmentTransaction.

Related

Android reload fragments stack on restore

I’m developing an android application that makes heavy use of fragments, I’m running into an issue and I’ve been unable to find a solution so far.
The flow is this: the app is launched and MainActivity is the first responder, now, depending on user interaction several fragments gets loaded and pushed onto the stack.
Here is an example:
Main Activity -> fragment A -> fragment B -> fragment C -> etc..
Back history is enabled like so:
fragment C -> fragment B -> fragment A -> etc..
Everything works perfectly fine as long as my application is in foreground but everything breaks when the application goes in background.
If I’m on fragment B for example and I press the home button the application goes in background and when I restore it back it starts from MainActivity with fragment A.
Also, the toolbar shows the title of fragment B and, since fragment A contains a recyclerview I can see parts of fragment B between item rows, like a background image.
This is how I load fragments:
public void loadFragment(Fragment fragment, Boolean addToStack) {
// Load fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragment);
fragmentTransaction.addToBackStack(null);
// show back button
if (addToStack) {
// Code to show the back button.
}
else if (fragmentManager.getBackStackEntryCount() > 0 && !addToStack) {
hideBackButton();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
fragmentTransaction.commitAllowingStateLoss();
}
I call this function from MainActivity and from the fragments:
MyFragment theFragment = new MyFragment();
MainActivity.instance.loadFragment(theFragment, true);
What I want to achieve is that when the application is restored it gets straight to the previously loaded fragment, keeping the entire "back" history. How can I do this?
I'm not sure if other portions of code are needed, but if so I'll post them as required.
call the onResume() function:
public void onResume(){
Fragment frg = null;
frg = getSupportFragmentManager().findFragmentByTag("Your_Fragment_TAG");
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
}
Ok so, after a lot of research I found the issue… and the issue was a mistake of mine.
I’d like to report it here for everyone that might run into the same issue.
At first I tried to force fragment replacement on onResume() function like so:
Fragment f = getSupportFragmentManager().findFragmentById(R.id.container);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, f);
fragmentTransaction.addToBackStack(null);
However android should handle all of this automatically, at least in my knowledge, and so I tried to dig further and I finally narrowed it down to my onStart() method.
Basically I was registering the EventBus and making a function call
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
UserNetworkManager userNetworkManager = new UserNetworkManager(MainActivity.mainActivity);
userNetworkManager.fetchFeed();
}
This code was creating the issue and after all it was not necessary to put it there, so I moved it to the onCreate() method, cleaned up my code a little bit and everything works fine now.

How to replace fragment properly using navigation drawer

I am using navigation drawer and it is simple to use. I am not providing the complete code but providing you detail which could be easy for you to understand my problem. I am using fragments these are about 8 in numbers and I am replacing them with one an other. But here comes a problem
I am replacing them on click event of the navigation drawer. but there are two main problems
After replacement , I can see the previous fragment in the background. does replace method just call the new fragment over it ? if yes then what should I do to old fragment not be visible in the background of my new fragment.
When I click navigation drawer Item , it loads the specific fragment successfully. but keeping in that fragment when I click to that specific item again it loads this fragment again and again. For example if drawer item num 3 opens fragment MyBook , then by clicking item num three 2 or many times would open fragment that much time.
So please some one answer me how to cure my app for such kind of actions which I described above.
I tried like this. Its working fine me
FragmentManager frgmanager = getFragmentManager();
frgmanager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction frgTransaction = frgmanager.beginTransaction();
if(subitem.equalsIgnoreCase("subitem")){
Frag1 frg1 =new Frag1(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg1);
}else if(subitem1.equalsIgnoreCase("subitem1")){
Frag2 frg2 =new Frag2(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg2);
}else{
Frag2 frg3 =new Frag3(mCtx);
frgTransaction.replace(R.id.inflate_layout, frg3);
}
frgTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
frgTransaction.commit();
you can use addtobackstack in fragmentstranstion object.like
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.addtoBackStack(null).commit();
Use replace-method of FragmentTransaction instead of add (http://developer.android.com/guide/components/fragments.html#Transactions)
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.bodyfragment, new AnotherFragment());
transaction.commit();
To avoid re-instantiating the fragment, keep track of the current open fragment and only do a fragment transaction, if we next-to-be-opened fragment is a different one than the current.
This may achieved like the following:
class MyActivity ... {
private String currentFragment;
private void openNewFragment(Fragment fragment) {
String newFragment = fragment.getClass().getSimpleName();
if (newFragment.equals(currentFragment)){
// new fragment already shown
return;
}
// Fragment transaction etc here:
}
}
Note that this only compares fragments based in their class name. Sometimes this might not be unique, e.g. if there is a DetailFragment class which displays information about an entity. Which entities details to show may depend on intent arguments.
The above code however will then prevent opening DetailFragment for Entity=1 if currently details for Entity=2 are shown. For these scenarios the information about the fragment kept needs to be extended (e.g. storing a Reference or WeakReference to the fragment instance itself).

from activity back to fragment,some layout can't visiable and gone

in my fragment, I have a layout.when click the button,show it.and when i click it again I set the visibility to Gone.
but I set the layout visible and gone don't work when I jump to an activity and back to the fragment.then I getVisibility() == View.VISIBLE and ==View.GONE, the layout really is visible and gone. but the fragment can't show it.
private void beginTransaction(Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
I doubt my fragment have some problem because when I try to use Fragment.replace to replace difference fragment, the fragment can't load some data. but I copy the replace code form my last project and the old project don't have any problem.
I use these code to solve the old problem.
bottomBar.post(new Runnable() {
#Override
public void run() {
startHomeFragment();
}
});
but I don't know how to solve the new problem now

How to show a Fragment managed by FragmentPagerAdapter?

I have a class derived from FragmentPagerAdapter and user swiping works fine (4 tabs), but I would like to show a page/tab/fragment from code. For example, when user taps a textview, I would like to switch to a specific fragment.
I've tried the following without success:
public void onClockClick(View v)
{
FragmentManager fm = getFragmentManager();
if (fm != null) {
fm.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(mainFragment)
.commit();
}
}
Am I barking up the wrong tree?
Well, if you know the position of the fragment you want to show then you can simply do: pager.setCurrentItem(pos)
This will automatically animate to the fragment at the desired position. Simple.
If you want to add another fragment to the existing FragmentPagerAdapter, then you'll need to first add the fragment's instance to that adapter and then call notifiyDataSetChanged on it.

Android Fragment - move from one View to another?

Can i first add a Fragment to a View, then "detach" it, and then "re-attach" it to another View?
In code, i want to:
fragOne one = new fragOne();
getSupportFragmentManager().beginTransaction()
.add(R.id.left, one, "tag").commit();
getSupportFragmentManager().beginTransaction()
.detach(one).commit(); // or .remove(), or .addToBackStack(null).remove()
getSupportFragmentManager().executePendingTransactions();
getSupportFragmentManager().beginTransaction()
.add(R.id.right, one).commit();
But it throws error:
04-05 13:28:03.492: E/AndroidRuntime(7195): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.trybackstack/com.example.trybackstack.MainActivity}: java.lang.IllegalStateException: Can't change container ID of fragment fragOne{40523130 #0 id=0x7f080000 tag}: was 2131230720 now 2131230721
Thanks for help!
I had the same problem but I found that what I really needed was to reparent the fragment's view and not the fragment itself, thus avoiding any fragmentManager transaction.
View vv = fragment.getView();
ViewGroup parent = (ViewGroup)vv.getParent();
parent.removeView(vv);
newparent.addView(vv, layoutParams);
after trying all the answers from similar questions, looks like i've found a way to do the trick.
First issue - you really have to commit and execute remove transaction before trying to add fragment to another container. Thanks for that goes to nave's answer
But this doesn't work every time. The second issue is a back stack. It somehow blocks the transaction.
So the complete code, that works for me looks like:
manager.popBackStackImmediate(null, manager.POP_BACK_STACK_INCLUSIVE);
manager.beginTransaction().remove(detailFragment).commit();
manager.executePendingTransactions();
manager.beginTransaction()
.replace(R.id.content, masterFragment, masterTag)
.add(R.id.detail, detailFragment, activeTag)
.commit();
I guess you would have this figured out by now, but i dont't see any satisfactory answer.
So, I'm posting this for others who may refer to this in the future.
If you want to move a fragment from one view to another you do the following:
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment1);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.containerToMoveTo, fragment1);
fragmentTransaction.commit();
This way you do not have to duplicate the fragment.
Please check the solution,you need to create the new instance of the same fragment and instantiate it with state of the old fragment if you want to save the state of the old fragment.
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.remove(one);
Fragment newInstance = fetchOldState(one);
ft.add(R.id.right, newInstance);
ft.commit();
//TO fetch the old state
private Fragment fetchOldState(Fragment f)
{
try {
Fragment.SavedState oldState= mFragmentManager.saveFragmentInstanceState(f);
Fragment newInstance = f.getClass().newInstance();
newInstance.setInitialSavedState(oldState);
return newInstance;
}
catch (Exception e) // InstantiationException, IllegalAccessException
{
}
}
I have run into that problem as well. Sometimes moving fragments works, sometimes you have to create a new instance. It seems that moving fragments does not work, if the fragment keeps being in the "isRemoving" state.
Being removed also seems to be prevented by having a fragment in the backstack.
Adding to the Yan. Yurkin's answer. Make sure not to have any transitions applied to the transaction as these seem to delay the fragment from being detached.

Categories

Resources