I have an app which utilized NavigationDrawer and toolbar. When I click on one of the menu in the NavigationDrawer, it displays a fragment (let's call it fragment1). Inside fragment1 is a button, when clicked would display another fragment (fragment2).
Ok so when I'm at fragment1, the toolbar would display a hamburger icon, where when I click on it, the drawer would be opened. And when I'm at fragment2, the toolbar would display a back icon (up caret) instead of the hamburger. Ok this is correct, but when I click on the back icon (up caret) the drawer would be opened instead. So what should I do so that when the back icon (up caret) is clicked, I'd be brought back to fragment1, and not opening the drawer?
This is my onClick for the drawer
#Override
public void onClick(View v) {
int position = getPosition();
Fragment fragment = null;
FragmentManager fManager = ((FragmentActivity) contxt).getSupportFragmentManager();
FragmentTransaction transaction = fManager.beginTransaction();
Toast.makeText(contxt, "The Item Clicked isss: " + position, Toast.LENGTH_SHORT).show();
mDrawerLayout = (DrawerLayout) ((FragmentActivity) contxt).findViewById(R.id.dlMainDrawer);
mDrawerLayout.closeDrawers();
switch (position) {
case 1:
fragment = new MenuHome();
transaction.replace(R.id.container, fragment, "fragmentHome");
transaction.addToBackStack(null);
transaction.commit();
break;
case 2:
fragment = new MenuExpensesDaily();
transaction.replace(R.id.container, fragment, "fragmentExpensesDaily");
transaction.addToBackStack(null);
transaction.commit();
break;
default:
break;
}
}
So using the code above, I opened an instance of MenuExpensesDaily. And inside MenuExpensesDaily, when I click on a menu item, it would open another fragment, ExpensesDailyAdd, as shown below:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_main, menu);
MenuItem mItem = menu.findItem(R.id.tbAddExpenses);
mItem.setVisible(true);
mItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
ExpensesDailyAdd addExpenses = new ExpensesDailyAdd();
getFragmentManager().beginTransaction()
.replace(R.id.container, addExpenses, null)
.addToBackStack(null)
.commit();
return true;
}
});
}
Ok so now when ExpensesDailyAdd is opened, the hamburger icon is changed to the up caret. But when I click the up caret, it opens the drawer instead of going back to the previous fragment.
Related
I have a simple BottomNavigationView with two menu items (Home Fragment, Settings Fragment) in an activity.
I have implemented onNavigationItemSelectedListener and onNavigationItemSelected.
Also bottomNavigationView.setOnNavigationItemSelectedListener(this);
App page lands on the Home Fragment.
onNavigationItemSelected is being called when I switch between menu items but When I first launch the app and tap on the same menu Item i.e. Home Fragment, onNavigationItemSelected is not being called.
I would need to show a toast whenever the user clicks on the home page when user is already in home page but onNavigationItemSelected event is not triggered.
As Mike M mentioned,
setOnNavigationItemReselectedListener did the trick.
First of all we do this in the MainActivity
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int v = item.getItemId();
if(v==R.id.home)
{
getSupportActionBar().setTitle("Home");
Fragment fragment = new HomeFragment();
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frame_layout, fragment).commit();
}
else if (v==R.id.dash_board)
{
getSupportActionBar().setTitle("Dashboard");
Fragment fragment = new DashboardFragment();
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frame_layout, fragment).commit();
}
return true;
}
};
This is a example here
If you want to know in detail then click here
I was trying to implement the bottom navigation with fragment inside an activity.
I have done that and it was successful.
To replace the fragment on click each navigation item, I use the following code.
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_notifications:
loadFragment(new NotificationsFragment());
return true;
case R.id.navigation_notes:
loadFragment(new NotesFragment());
return true;
case R.id.navigation_about:
loadFragment(new AboutFragment());
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
Now the problem is that when I click on a navigation in the bottom navigation bar multiple times, the fragment is also getting added to the back stack multiple times.
So when I click the back button the fragment is again loaded, not exiting or loading the previous fragment.
So, How can I prevent the fragment getting added to the back stack multiple times?
Remove
transaction.addToBackStack(null);
or add
transaction.disallowAddToBackStack();
I'm currently developing a Android studio App using fragment and a bottom navigation bar.
When I click on a navigation bar's item, it's replacing the current fragment by another one which correspond the fragment I wanted for this item.
The problem is, the objects in my fragment are all reset after replacing fragment.
I'm not removing the fragment from the container so I don't really understand why all the objects are reset after doing this.
Here is my code to add and replace fragment to my FrameLayout :
private void setFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.fade_out);
if (getSupportFragmentManager().findFragmentById(R.id.main_frame) == null) {
fragmentTransaction.add(R.id.main_frame, fragment);
}
else
{
fragmentTransaction.replace(R.id.main_frame, fragment);
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
and here is the bottom navigation bar code to execute the previous function and change the displayed fragment:
homeFragment = new HomeFragment();
programFragment = new ProgramFragment();
bluetoothFragment = new BluetoothFragment();
mMainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
test = mMainNav.getMenu().getItem(2);
switch (item.getItemId()) {
case R.id.nav_home:
//mMainNav.setItemBackgroundResource(R.color.colorPrimary);
HQ_logo_IV.setVisibility(View.VISIBLE);
setFragment(homeFragment);
return true;
case R.id.nav_program:
//mMainNav.setItemBackgroundResource(R.color.colorAccent);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(programFragment);
return true;
case R.id.nav_bluetooth:
//mMainNav.setItemBackgroundResource(R.color.colorPrimaryDark);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(bluetoothFragment);
return true;
default:
return false;
}
}
});
I found the way to stop this thing.
I used an AsyncTask to refresh my fragment state.
I just put new "yourAsyncTaskName"().execute() at the beginning of my onCreate() method to refresh the fragment when it's created or replaced.
Hope this will help.
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();
}
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.