In my application I created a Navigation Drawer which has 5 items, once an item is clicked in the Navigation Drawer, I can correctly check the item and show the new fragment using the fragment manager.
But currently I have three problems:
My application has floating action buttons, that of course perform actions and open new fragments, so I need to handle that "Fragment changing" in the navigation drawer too, setting as checked the current item which corresponds to the fragment showed.
I SORT OF solved this problem, but using a single method that
performs the fragment transaction in the MainActivity and meanwhile
checks the new item. So everytime a Fragment want to call another
Fragment, it uses this function passing the nav_drawer_item_id as a
parameter. I think that this solutions sucks, so if you have a better idea, it would be really welcome!
My biggest problem is that when the user press the Android Back Button, the fragment pops back to previous one (or sometimes I call popback() programmatically because I am done with that specific fragment )
I really don't know how to solve this problem because I can't check the correct item in the navigation drawer once a fragment is popped back, I need to know which fragment it is.
I need to show the new fragment once the navigation drawer is closed in order to respect "Android Rules" ( And because it's nice ).
I sort of solved this problem too, by setting a "nextFragment" inside the navigation drawer onNavigationItemSelectedListener and by showing the new fragment inside the drawer onDrawerClosed. Is it the only solution?
I'm not posting any code because it really doesn't deserve to be seen, so here is some extra info:
I have a single activity which contains the Navigation Drawer and currently handles the fragment transactions.
I have 6 fragments, 5 called from the Navigation Drawer and 1 called only from others UI components, but this one doesn't need to be checked on the drawer of course.
I tought about a solution and it was like "Setting the checked item FROM the fragment that is showed", but I didn't find any way to get the Navigation Drawer from the Fragment in order to set the proper item checked.
Implement FragmentManager.OnBackStackChangedListener in your activity to get notified whenever something is popped off the back stack and sync the navigation drawer from the callback. That should get rid of the problem caused when the back button is pressed.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.....
getSupportFragmentManager().addOnBackStackChangedListener(this);
}
#Override
public void onBackStackChanged() {
// Get the currently active fragment
Fragment fragment =
getSupportFragmentManager().findFragmentById(R.id.fragments_frame);
// Check which fragment is active, check the
// correct selection and set the title accordingly
if (fragment instanceof FragmentAtPosition0) {
setCheckedAndTitle(0);
} else if (fragment instanceof FragmentAtPosition1) {
setCheckedAndTitle(1);
}
}
private void setCheckedAndTitle(int position) {
MenuItem item = navView.getMenu().getItem(position);
item.setChecked(true);
setTitle(item.getTitle());
}
As for the other two cases that you mentioned, I think the solutions you have mentioned are the preferred ways.
Related
I have multiple fragment, one bottom navigation view on bottom of Main Activity. The problem appears when I want to set selected item on Bottom Navigation View when fragment pop back from stack, setSelectedItemId always trigger OnBackStackChangedListener, thus make loop event. Here are the code
fragmentManager.addOnBackStackChangedListener {
var f : Fragment = fragmentManager.findFragmentById(R.id.frame)
if(f is HomeFragment){
bottomNavigation.selectedItemID = R.id.navigation_home
}
}
I've check from the documentation at developer.android.com and various post on StackOverflow or even forum and I don't find any proper solution for my case.
Any solution? thanks
I've been researching a solution to my problem but not a single result fixes my problem.
I have five Java activities. Each activity has five buttons, four to the other activities and one to itself. It's basically just a bar of bottoms at the bottom of the page.
My issue is that let's say I'm in one activity, and then I click that button to the activity again, it opens and loads an entirely new activity. And then when I click back, it shows the previous activity open as I left it. But if I press it ten times, I need to click back ten times. Also, if I switch between each activity twice and I want to click back to main to exit, I need to click back ten times instead of five.
I want it to be such that when I click a button, it opens the activity. If I press the button again, it does nothing if I'm in that activity. And if I'm switching between activities and I repress an activity I already opened, I want that to be brought to the top of the stack from its lower location, not added. So at most, I only want five activities running.
It's a very confusing problem as I see people suggesting to use intent flags, which I'm not sure if I place them in the manifest, which does nothing with I try. And I've seen people suggest using LaunchMode single instance, which also does nothing.
I really think fragments are the best method here. And yes, it's a little tricky but you can use fragments within fragments. For navigating without creating extra instances, I think you might be looking for something along the lines of this:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if(id == R.id.nav_home){
Fragment newFragment;
FragmentManager fragmentManager = getSupportFragmentManager();
// Look for fragment by tag
Fragment foundFragment = fragmentManager.findFragmentByTag(MAIN_FRAGMENT);
if(foundFragment != null) { //if fragment's already in the backstack
newFragment = foundFragment; //replace fragment with backstack fragment
}else{
newFragment = new MainFragment(); // use a new fragment instance
}
// Add new fragment instance to fragment manager
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, newFragment, MAIN_FRAGMENT)
.addToBackStack(MAIN_FRAGMENT)
.commit();
}
// ...
}
I have an app with a main activity which loads a navigation drawer, and a pair of fragments that load in that activity ...
In the navigation drawer I have 4 options A, B, C and D ... the first one loads FragmentA on my activity and the last 3 load FragmentB ..
FragmentA displays a list of elements and, upon selecting one of these elements FragmentB is used to load its content... I want to change the home (hamburger/drawer) icon on FragmentB for the up icon when initiating from FragmentA (and change the corresponding behavior to make a popstack on select).. I have no problem with this using setDisplayHomeAsUpEnabled(true), but since all this is occurring inside one activity if I then select one other option (say B) from the navigation drawer the up icon will still be showing (it its also showing on the popped fragment)...
if I use setDisplayHomeAsUpEnabled(false) all this do is hide the home/up button from the toolbar, I need to recover the home button and make sure this will be shown when FragmentB is initiated from the drawer menu ...
Does this problem ring a bell to anyone? or am I just using fragments the wrong way? .. any advice will be appreciated
EDIT
this is more or less what I have in code
In Main Activity .. as the onNavigationItemSelected(MenuItem item) for the drawer I have a something like this ...
switch(optionNumber) {
case 0:
fragment = FragmentA.newInstance(optionNumber);
break;
default:
fragment = FragmentB.newInstance(optionNumber);
break;
}
Fragment frag = fragmentManager.findFragmentByTag("current_fragment");
if (frag != null && frag.getClass() == FolderFragment.class){
((FolderFragment)frag).resetScroll();
}
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction().replace(R.id.content, fragment, "current_fragment").commit();
which selects the fragment to load according to the option selected..
In FragmentA I'm calling FragmentB with this ..
FragmentB fFragment = FragmentB.newInstance(position);
Bundle args = new Bundle();
args.putString("filter", "something"); fFragment.setArguments(args);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.flContent, fFragment, "current_fragment")
.addToBackStack(null)
.commit();
Preserving the fragment in the stack
And in fragmentB inside onResume() function I got something like...
String filter = getArguments().getString("filter", null);
if (type != null) {
mActivity.setTitle(title);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
}else {
/*mActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActivity.getSupportActionBar().setDisplayShowHomeEnabled(true);
mActivity.getSupportActionBar().setHomeButtonEnabled(true);
mActivity.getSupportActionBar().setIcon(R.mipmap.ic_menu);*/
}
So When I'm creating fragmentB I check for arguments and see if it comes from fragmentA or not ( I could also check the fragmentmanager backstack and see if there's something)... there I just change the drawer icon with setDisplayShowHomeEnabled(true) ... leaving the back arrow, if I return to FragmentA (via onBackPressed()) FragmentA shows the arrow and I need it to show the original drawer icon ... the same happens if I select an option from the drawer menu ...
Does this gives more clarity to my issue ?... I have some commented code there because it doesn't work .. if I activate the line with setDisplayHomeAsUpEnabled(false).. the icon just disappears from the activity (which is the intended result of the function as far as I know)...
After a while I finally found this post
Switching between Android Navigation Drawer image and Up caret when using fragments
I guess that when involving a Drawer in the interface you might need to handle this issue with that component... this post gave me the answer.
Particular notice to the last comment by Wolfram Rittmeyer
I've had a search on SO and can't find anything that works.
Here's what I want to do, when I navigate between navigation drawer pages, I want the view to be the same. So if I go from page A to B, and then from B to A. I expect A to have the same state.
In my app, I add some text to fragment A via some button. When I navigate to fragment B, and then back to A, the text is gone. I want the text to still be there.
How do I do this?
I've already tried setRetainState(true). This doesn't work. I have also made sure that new Fragment() is only called once when going to the page. This also doesn't work.
The structure of my navigation drawer is identical to the one shown in the Android documentation.
I think, if you have a navigation drawer that you use fragments for each page.
On select item in navigation drawer don't recreate the fragment, just pop it from back stack if it exists.
HomeFragment homeFragment = (HomeFragment) fm.findFragmentByTag(fragmentName);
if (homeFragment == null) {
homeFragment = new HomeFragment();
fm.beginTransaction().addToBackStack(fragmentName).replace(R.id.content_frame, homeFragment, fragmentName).commit();
} else {
fm.popBackStackImmediate(fragmentName, 0);
}
I am using the nav drawer pattern in an application.
One of my fragments does some work that I would like to stop while the nav drawer is open.
The same fragment can also produce a dialog (DialogFragment) and, again, I would like to stop the ongoing work in my fragment while the dialog is shown over it.
Are there any lifecycle callbacks or listeners I could set up that would allow me to do this in one place? (in both cases my fragment's view is behind others and clicking on the visible portion of my fragments view will be redirected to close the nav drawer/dialog).
Currently I have a callback from my main activity to the fragment to tell it about the nav drawer opening and closing, but I would like to be much more encapsulated than that, especially seeing as I have to worry about the dialog too. Which will probably mean having to add state to track each of these.
I've tried a focus listener on my root view but didn't seem to get any callbacks on that.
I also looked into the onBackStackChanged callback of my fragment and I might be able to use this for the dialog, but not the nav drawer I don't think?
A summary of what I have tried:
Tried all these listener interfaces:
ViewTreeObserver.OnWindowFocusChangeListener,
ViewTreeObserver.OnGlobalFocusChangeListener,
View.OnFocusChangeListener,
ViewTreeObserver.OnGlobalLayoutListener
The only one that seemed to work at all was the OnWindowFocusChangeListener. This gave me a call when opening/closing the dialog but not the Nav drawer and is only supported from API 18 :(
This is working for the dialog fragment if I use the child fragment manager to add it:
#Override
public void onBackStackChanged()
{
FragmentManager fragmentManager = getChildFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
Log.v(TAG, "onBackStackChanged, count: " + count);
if (count == 0)
{
//we are at the top
***start working***
}
else
{
***stop working***
}
}