I have an android application which has a NavigationView with 4 fragments. I can navigate between fragments via navigation menu and when I select another fragment, I added the previous fragment into back stack to provide back button functionality.
My problem is that when I press back button to go to previous fragment, the NavigationView still shows old fragment as the selected fragment. If it is possible I want to update selected option as the fragment on the screen.
Example:
I start from A, and select B from NavigationView. The current screen is B and NavigationView shows the selected item as B. If I press back button my current screen becomes A again but NavigationView shows B as selected item.
Here is my onNavigationItemSelected method:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
HomeFragment fragment = null;
Class type = null;
switch (id) {
case R.id.nav_home:
type = HomeNavigationFragment.class;
break;
case R.id.nav_groups:
type = GroupsNavigationFragment.class;
break;
case R.id.nav_profile:
type = ProfileNavigationFragment.class;
break;
case R.id.nav_messages:
type = MessageNavigationFragment.class;
break;
}
fragment = HomeFragment.newInstance(mUser, type);
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.fragment_container, fragment).addToBackStack("fragment" + code++).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Thanks.
I fixed my problem with overriding onBackPressed like this:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
FragmentManager manager = getSupportFragmentManager();
if(manager.getBackStackEntryCount() > 0) {
super.onBackPressed();
HomeFragment currentFragment = (HomeFragment) manager.findFragmentById(R.id.fragment_container);
if(currentFragment instanceof HomeNavigationFragment){
mNavigationView.getMenu().getItem(0).setChecked(true);
}
else if(currentFragment instanceof GroupsNavigationFragment){
mNavigationView.getMenu().getItem(2).setChecked(true);
}
else if(currentFragment instanceof ProfileNavigationFragment){
mNavigationView.getMenu().getItem(1).setChecked(true);
}
else if(currentFragment instanceof MessageNavigationFragment){
mNavigationView.getMenu().getItem(3).setChecked(true);
}
}
}
}
Related
I am using a Navigation Drawer and the hamburger menu is showing in all the right screens, but on the other fragments, when I click on the back arrow, the navigation drawer opens when I want to go back in the stack to the previous screen.
How do I change the behavior so that when the arrow is showing, as opposed to the hamburger menu, I can capture the user clicking on the arrow?
I am using a Navigation Drawer with Fragments. In the main activity I am setting the top level destinations with the AppBarConfiguration:
AppBarConfiguration config = new AppBarConfiguration.Builder(topLevelDestinations)
.setDrawerLayout(drawerLayout)
.build();
NavigationUI.setupActionBarWithNavController(this, navController, config);
NavigationUI.setupWithNavController(navView, navController);
navView.setNavigationItemSelectedListener(this);
I am catching all the selections from the top level destinations and navigating appropriately:
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
item.setChecked(true);
drawerLayout.closeDrawers();
int id = item.getItemId();
switch (id) {
...
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
The getFragmentManager().popBackStack() method is probably what you are looking for. Here's a sample snippet to be placed for activity:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
In case of fragments, try calling the fragment like this:
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail") // Add this transaction to the back stack
.addToBackStack(null)
.commit();
I have Base Activity including NavigationView with 2 menu items. On start it loads Home fragment having background image inside it. Each loads specific fragment. When I select Terms & Conditions menu item, it loads T&C fragment & when I press back button it simply kills it.
However, when I select About Us menu item, it loads About Us fragment but I need to press BACK button twice to kill it. I need to know why does it happen?
Part of Code in AppBaseActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, "");
fragmentTransaction.commit();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
navigationView.getMenu().findItem(item.getItemId()).setChecked(true);
switch (item.getItemId()) {
case R.id.nav_terms :
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.replace(R.id.body_container, tcFragment, "");
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.replace(R.id.body_container, aboutUsFragment, "");
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
All fragments simply have overridden onCreateView() by inflating respected xml only. No code is written in both fragments yet.
You can stop back hardware navigation if you want.
Simply using onBackPressed() without super.onBackPressed()
#Override
public void onBackPressed() {
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
Im working with an android app which have 3 fragments and the activity_main, all of them are listed in a navigation drawer. The question is how can i return to the activity main by clicking in a item of the navigation drawer.
The basic idea of waht I need is to close all the fragments open to return to the activity main
This is my code.
if(id==R.id.taximetro){
//this is my activity_main that i need to return
trans = true;
} else if (id == R.id.factura) {
fragment=new frmFactura();
getSupportFragmentManager().beginTransaction().replace(R.id.content_main, fragment).addToBackStack(null).commit();
trans = true;
} else if (id == R.id.dispBlue) {
fragment=new frmDispositivos();
getSupportFragmentManager().beginTransaction().replace(R.id.content_main, fragment).addToBackStack(null).commit();
trans = true;
} else if (id == R.id.ayuda) {
fragment=new frmAyuda();
getSupportFragmentManager().beginTransaction().replace(R.id.content_main, fragment).addToBackStack(null).commit();
trans = true;
}
if (trans) {
getSupportFragmentManager().beginTransaction().replace(R.id.content_main, fragment).commit();
item.setCheckable(true);
getSupportActionBar().setTitle(item.getTitle());
}
//getSupportFragmentManager().beginTransaction().replace(R.id.content_main, fragment).addToBackStack(null).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Simple like you call fragments ..call your MainActivity
if you want check whats available on the view,
keep an ENUM value or other related way ..and change the value related the the view that you loaded ,and check a fragment is loaded or still the main view exists in your MainActivity using that ENUM value in your MainActivity call
so,
if a fragment view is loaded recall your MainActivity
else just slide the navigation because you are already in the view of MainActivity without any fragment loaded on it
if(id==R.id.taximetro){
// call your activity again if you want you can check that a fragment view is loaded or not and do changes only when you need if there is a fragment view loaded.. or simply recall it
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
I am building an android application using default Navigation Drawer layout and Fragment to switch from one layout to another.
The layout sequence is like
Dashboard -> Settings -> Profile Settings
MailActivity.class loads main_activity.xml which containes a frameLayout to contain fragment
and Dashboard loads ActivityDashboard Fragment.
Now, when I switch from Dashboard to Settings and then Profile Settings. onBackPress works fine. But after on Profile Settings, I selected Dashboard from Navigation Drawer to go back to the home screen. Then pressing back key follows the stack
Dashboard -> Profile Settings -> Settings -> Dashboard
The code for Navigation Drawer is
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// calling the method displaySelectedScreen()
displaySelectedScreen(item.getItemId());
return true;
}
private void displaySelectedScreen(int itemId) {
// creating Fragment object
Fragment fragment = null;
// initializing fragment
switch (itemId) {
case R.id.nav_dashboard:
fragment = new ActivityDashboard();
break;
case R.id.nav_calendar:
fragment = new ActivityCalendar();
break;
case R.id.nav_history:
fragment = new ActivityHistory();
break;
case R.id.nav_about:
fragment = new ActivityAbout();
break;
case R.id.nav_settings:
fragment = new ActivitySettings();
break;
}
// replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
I'm using same FragmentTransaction code to switch from one fragment to another in ActivityDashboard, ActivitySettings fragment classes.
Q 1. How to flush the addBackToStack when the ActivityDashboard is loaded so that user have only option to exit app ?
Q 2. How to get back to ActivityDashboard, when layout is changed from Navigation Drawer irespective of which fragment is replaced ?
i.e., When user is on ActivitySettings fragment and changed to ActivityHistory from Navigation Drawer, then on backPress, user must be tracked following
ActivityHistory -> ActivityDashboard
instead of
ActivityHistory -> ActivitySettings -> ActivityDashboard
onBackPressed() method on MainActivity.class is
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
Simply call
fragmentManager.popBackStack(stackName /* null if you did not supply a stack name while creating your fragments */, FragmentManager.POP_BACK_STACK_INCLUSIVE);
inside your ActivityDashboard
I have implemented NavigationView in Android with fragments. This is my first time dealing with fragments. The problem is I have 3 Items in NavigationView and want to do something like that:
User enters home screen and "Top 20 Fragment" is selected by default (in this moment back key makes app exit) - I am setting this fragment as default without pulling transaction to back stack,
private void setStartingFragment(NavigationView navigationView,
FragmentManager fragmentManager) {
Fragment fragment = null;
Class fragmentClass = Top20RecipesFragment.class;
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_content, fragment);
fragmentTransaction.commit();
MenuItem menuItem = navigationView.getMenu().getItem(0);
menuItem.setChecked(true); // Highlight The Selected Item
setTitle(menuItem.getTitle()); // Updating Toolbar Title
}
When I pick one of 2 other fragments I would like them to add to back stack. I want to do this like in Twitch mobile application. Possibilities are:
2nd Fragment (or 3rd) -> Home fragment -> Exit or
2nd Fragment -> 3rd Fragment -> Home Fragment -> Exit or
2nd Fragment -> 3rd Fragment -> Home Fragment -> Exit or
Another big problem is to sync NavigationView selected item and Tooblar title on back button pressed.
Here is what I have for now if we talk about NavigationView and fragments replacing:
// Replace Existing Fragment With a New One
public void selectDrawerItem(MenuItem menuItem) {
Fragment fragment = null;
Class fragmentClass = null;
switch(menuItem.getItemId()) {
case R.id.nav_top20_recipes: {
fragmentClass = Top20RecipesFragment.class;
break;
}
case R.id.nav_kitchen_type: {
fragmentClass = KitchenTypeFragment.class;
break;
}
case R.id.nav_meal_type: {
fragmentClass = MealTypeFragment.class;
break;
}
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_content, fragment);
fragmentTransaction.addToBackStack(Integer.toString(fragment.getId()));
fragmentTransaction.commit();
menuItem.setChecked(true); // Highlight The Selected Item
setTitle(menuItem.getTitle()); // Updating Toolbar Title
mDrawerLayout.closeDrawers(); // Close The Drawer
}
I looked into Android official site and they advice to use OnBackStackChangedListener to change Activity apperance according to fragment replacing and using back button.
I tried to apply this interface and here what I tried to do with different toutorials but app crashes or does not work properly.
// Managing Fragments In Back Stack
#Override
public void onBackStackChanged() {
int actualStackHeight = getSupportFragmentManager().getBackStackEntryCount();
if (actualStackHeight > 0) {
FragmentManager fragmentManager = getSupportFragmentManager();
int fragmentId = fragmentManager.getBackStackEntryAt(actualStackHeight - 1).getId();
Fragment currentFragment = fragmentManager.findFragmentById(fragmentId);
switch (currentFragment.getId()) {
case R.id.top20_fragment: {
MenuItem menuItem = nvDrawer.getMenu().getItem(0);
menuItem.setChecked(true); // Highlight The Selected Item
setTitle(menuItem.getTitle()); // Updating Toolbar Title
}
case R.id.kitchen_type_fragment: {
MenuItem menuItem = nvDrawer.getMenu().getItem(1);
menuItem.setChecked(true); // Highlight The Selected Item
setTitle(menuItem.getTitle()); // Updating Toolbar Title
}
case R.id.meal_type_fragment: {
MenuItem menuItem = nvDrawer.getMenu().getItem(2);
menuItem.setChecked(true); // Highlight The Selected Item
setTitle(menuItem.getTitle()); // Updating Toolbar Title
}
}
} else {
finish();
}
}
This is my first time dealing with something like this so please try to understand me. I've searched for different ansewers even here on stack but non of them helped me :/
If you are using NavigationView use it with the Navigation API.
Then, on your onCreate(..) method...
main_navigationview.setupWithNavController(
findNavController(R.id.main_nav_container)
)
findNavController(
R.id.main_nav_container
).addOnDestinationChangedListener {
controller, destination, bundle ->
main_navigationview.setCheckedItem(destination.id)
}
Then, the NavigationView will be in sync, as simple as that.