Navigation Drawer back button in fragments - android

I started creating of app which use one activity (Navigation Drawer) and many fragments.
But I unable to use toolbar back button to navigate back from fragments. Hardware back button works perfectly. I know that I need to override onOptionsItemSelected, catch android.R.id.home, check if there are something in back stack and than pop it. After changing fragment, "burger" button changes to "back arrow", but when I click on it onOptionsItemSelected never fired, just opens the NavigationDrawer menu.
Here the code from activity:
public class NavDrawerActivity extends AppCompatActivity implements ... {
NavigationView navigationView;
BottomNavigationView bottomNavigationView;
ActionBarDrawerToggle toggle;
FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nav_drawer);
fragmentManager = getSupportFragmentManager();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
// Set back button
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (fragmentManager.getBackStackEntryCount() > 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.syncState();
}
}
});
// Load default fragment
changeFragment(new HomeFragment(), false);
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
View headerLayout = navigationView.getHeaderView(0);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(this);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Toast.makeText(this, "Back pressed", Toast.LENGTH_SHORT)
.show();
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private void changeFragment(Fragment fm, boolean addToBackStack)
{
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_layout_content, fm);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if (addToBackStack) ft.addToBackStack(null);
ft.commit();
}
}
And how I change (replace) fragments from HomeFragment:
IndexDetailFragment newFragment = new IndexDetailFragment();
Bundle args = new Bundle();
args.putString(IndexDetailFragment.ARG_INDEX_ID, id);
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
transaction.replace(R.id.frame_layout_content, newFragment);
transaction.addToBackStack(null);
transaction.commit();

setNavigationOnClick() on the toolbar after setSupportActionBar(toolbar) :
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Toast.makeText(getActivity(), "Back clicked!",
Toast.LENGTH_SHORT).show();
}
});
I have made a small app for reference
FirstFragment
public class FirstFragment extends Fragment {
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
SecondFragment
public class SecondFragment extends Fragment {
public SecondFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private Toolbar mToolbar;
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout mDrawerLayout;
private String TAG = "MainActivity";
private FragmentManager mFragmentManager;
private NavigationView mNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer);
drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
mDrawerLayout.addDrawerListener(drawerToggle);
mNavigationView = findViewById(R.id.navigation);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.first:
changeFragment(new FirstFragment(), true);
return true;
case R.id.second:
changeFragment(new SecondFragment(), true);
return true;
}
return false;
}
});
mFragmentManager = getSupportFragmentManager();
changeFragment(new FirstFragment(), true);
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (drawerToggle != null) {
drawerToggle.syncState();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
Log.i(TAG, "onOptionsItemSelected: Home Button Clicked");
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
} else {
mDrawerLayout.openDrawer(Gravity.START);
}
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
}
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
} else if (mFragmentManager.getBackStackEntryCount() > 0) {
mFragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private void changeFragment(Fragment fragment, boolean needToAddBackstack) {
FragmentTransaction mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.FRAME_CONTENT, fragment);
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if (needToAddBackstack)
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.commit();
}
}
activity_main
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
        
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/abc_action_bar_default_height_material"
android:background="#color/colorPrimaryDark"
/>
<FrameLayout
android:id="#+id/FRAME_CONTENT"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/abc_action_bar_default_height_material" />
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_marginTop="#dimen/abc_action_bar_default_height_material"
app:menu="#menu/drawermenu" />
</android.support.v4.widget.DrawerLayout>

I had the same issue.
I finally solved by adding this in the onCreate method.
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
menuToggle.setDrawerIndicatorEnabled(true);
}else{
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
menuToggle.setDrawerIndicatorEnabled(false);
}
}
});
Hope it helps

Simplest solution for Kotlin Developers
Just add this in your root activity where fragments resist
if (supportFragmentManager.backStackEntryCount > 0) {
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
toolbar.setNavigationOnClickListener {
if (supportFragmentManager.backStackEntryCount > 0) {
super.onBackPressed()
} else {
supportActionBar!!.setDisplayHomeAsUpEnabled(false)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
drawerLayout.openDrawer(GravityCompat.START)
}
}
} else {
supportActionBar!!.setDisplayHomeAsUpEnabled(false)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
}
Here, whenever setDisplayHomeAsUpEnabled is set true , I am showing back button. and on cliking it, I am calling super.onBackPressed() which is similar to what your back button does!

Add below code in onCreate() method
that's work for me
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, " Back Pressed ", Toast.LENGTH_SHORT).show();
}
});
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
drawerToggle = new ActionBarDrawerToggle(MainActivity.this, drawerLayout, toolbar,
R.string.app_name, R.string.app_name);
drawerLayout.addDrawerListener(drawerToggle);
drawerToggle.syncState();
}
}
});

The thing that solved me the issue was this:
I used the code that came automatically with the NavigationDrawerActivity template, and it was something like this:
NavigationView navigationView = _binding.navView;
// Passing each menu ID as a set of Ids because each menu should be considered as top level destinations:
_AppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_x, R.id.nav_y, R.id.nav_z)
.setOpenableLayout(_binding.drawerLayout)
.build();
_navController = Navigation.findNavController(this, R.id.nav_host_content_main);
NavigationUI.setupActionBarWithNavController(this, _navController, _AppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, _navController);
And I struggled a lot with many tricks and hacks, and nothing was working for me.
At some point, I have noticed that the fragments that I want to enable the back button are "being considered as top level destinations", exactly what the comment says in the code above. Then I removed those sub-fragments and BOOM that was it, with not a single hack or line of code needed, this is provided out of the box, I just needed to pay attention to it.
So in my case, I changed to the below code:
NavigationView navigationView = _binding.navView;
// Passing each menu ID as a set of Ids because each menu should be considered as top level destinations:
_AppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_x)
.setOpenableLayout(_binding.drawerLayout)
.build();
_navController = Navigation.findNavController(this, R.id.nav_host_content_main);
NavigationUI.setupActionBarWithNavController(this, _navController, _AppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, _navController);
: Just removed R.id.nav_y, R.id.nav_z in the AppBarConfiguration

I struggled with this for a while. I got it to work by:
setting my the drawer layout in MainActivity.kt:
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
findViewById<NavigationView>(R.id.nav_view).setupWithNavController(navController)
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
Include the toolbar layout in each of the fragments that I need the Toolbar:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
</com.google.android.material.appbar.AppBarLayout>
</LinearLayout>
Add the following code to the home fragment of the drawer, the one from which other fragments are called using the drawer. This gets the hamburguer icon to work, onside the onViewCreated method:
var myToolbar = requireActivity()
.findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
myToolbar.inflateMenu(R.menu.menu)
val drawerLayout = requireActivity().findViewById<DrawerLayout>(R.id.drawer_layout)
val toggle = ActionBarDrawerToggle(
activity, drawerLayout, myToolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
toggle.setDrawerIndicatorEnabled(true)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
Add the following code in the kotlin code for the fragments that are after the home fragment, this will get the back arrow:
val navController = findNavController()
val appBarConfiguration = AppBarConfiguration(navController.graph)
view.findViewById<Toolbar>(R.id.toolbar)
.setupWithNavController(navController, appBarConfiguration)
In the destination fragment add the following code in onCreateView Method:
activity?.onBackPressedDispatcher?.addCallback(
viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
findNavController().navigate(
[back fragment directions] )
}
})
Hope this helps everyone struggling with this :)

Related

Navigation Drawer Back Stack doesn't work

I have an app developed like the following image:
So a fragment A with a menu. Clicking on the menu it will open a fragment B.
My problem is that, when I click on the back button, nothing happens, so I can not return from fragment B to fragment A, and I don't understand why.
This is my code:
Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final DrawerLayout drawer = findViewById(R.id.drawer_layout);
final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open,
R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
drawer.openDrawer(Gravity.LEFT);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
FragmentA fragmentA = new FragmentA();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.relativelayout_for_fragment, fragmentA, fragmentA.getTag()).commit();
getSupportActionBar().setTitle(getResources().getString(R.string.title));
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
toggle.setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}else{
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
toggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
});
}
#Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
drawer.openDrawer(GravityCompat.START);
} else {
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Fragment A (on click on the menu)
Fragment fragmentB = new FragmentB();
FragmentTransaction transaction = activity.getFragmentManager().beginTransaction();
transaction.replace(R.id.relativelayout_for_fragment, fragmentB);
transaction.addToBackStack(null);
transaction.commit();
Fragment B
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.share_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getFragmentManager().popBackStack();
return true;
case R.id.menu_item_share:
String contenuto = "*" + titolo + "*" + "\n" + desc;
String textToShare = getResources().getString(R.string.Linc);
Intent intent = new Intent("android.intent.action.SEND");
intent.setType("text/plain");
intent.putExtra("android.intent.extra.TEXT", contenuto + "\n\n" + textToShare);
startActivity(Intent.createChooser(intent,
getResources().getString(R.string.sharing)));
return true;
}
return super.onOptionsItemSelected(item);
}
did you try this onBackPressed
override fun onBackPressed() {
val manager: FragmentManager = supportFragmentManager
if(manager.backStackEntryCount > 0){
manager.popBackStack()
}else{
super.onBackPressed()
}
}
In MainActivity
After
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Put
getSupportFragmentManager().popBackStack()

Handling and Showing back icon on toolbar with fragment onbackpressed

I am using navigation drawer with fragments and in my Home page i am navigating like this==> maincategory===>subcategory===>subcategoryDetail
while moving from maincategory to subcategory it perfectly replaces the hamburger icon and shows back arrow icon and onback press is working perfectly
but while moving from subcategory to subcategoryDetail when i press the back arrow of subcategoryDetail onback press is working perfectly
but it replaces the back arrow of subcategory.java page with hamburger icon and i cannot go back to home page
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
DrawerLayout drawer;
ActionBarDrawerToggle toggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
displaySelectedScreen(R.id.nav_home);
}
public ActionBarDrawerToggle getToggle() {
return toggle;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
} else if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
toggle.setDrawerIndicatorEnabled(true);
}
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
displaySelectedScreen(item.getItemId());
return true;
}
private void displaySelectedScreen(int itemId) {
Bundle bundle = new Bundle();
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.nav_home:
fragment = new HomeFragment();
break;
case R.id.nav_mens_clothing:
bundle.putString("MAINCATEGORYID", String.valueOf(1));
bundle.putString("MAINCATEGORYNAME","Carpentry");
fragment = new SubCategoryFragment();
fragment.setArguments(bundle);
break;
case R.id.nav_womens_clothing:
bundle.putString("MAINCATEGORYID", String.valueOf(2));
bundle.putString("MAINCATEGORYNAME","Electrical");
fragment = new SubCategoryFragment();
fragment.setArguments(bundle);
break;
case R.id.nav_boys_clothing:
fragment = new SubCategoryFragment();
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);
}
}
SubCategoryFragment.java
public class SubCategoryFragment extends Fragment {
protected Toolbar toolbar;
protected ActionBarDrawerToggle toggle;
View view;
public SubCategoryFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_sub_category, container, false);
toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
toggle = ((MainActivity) getActivity()).getToggle();
shimmerContainer = view.findViewById(R.id.shimmer_view_container);
recyclerView_subcategory = view.findViewById(R.id.recycler_view_category);
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
}
return view;
}
#Override
public void onPause() {
super.onPause();
toolbar.setTitle("Cooper");
toggle.setDrawerIndicatorEnabled(true);
}
SubCategoryDetailFragment.java
public class SubCategoryDetailFragment extends Fragment {
protected Toolbar toolbar;
protected ActionBarDrawerToggle toggle;
View view;
public SubCategoryDetailFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_sub_category_detail, container, false);
toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
toggle = ((MainActivity) getActivity()).getToggle();
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
}
return view;
}
#Override
public void onPause() {
super.onPause();
toolbar.setTitle("zzz");
toggle.setDrawerIndicatorEnabled(true);
}}
}
Design two different toolbars in XML and set their visibility according to fragment and activity. When Activity load set Toolbar with Navigation drawer, but when fragment load in that activity hide the current toolbar and replace with another toolbar XML with the back icon.
Do not forget to add toolbar code in onResume() method of the fragment.
Please add these two lines in onresume it will work.
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);

How to go back from an activity to fragment

Hey I'm new in android development and i'm trying to develop an app with navigation drawer. So i created fragments with navigation drawer menus, and from one of those fragments I have given an intent to a new activity. But i dont know how to go back from that activity to previous fragment.
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
displaySelectedScreen(R.id.nav_bus);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void displaySelectedScreen(int itemId) {
Fragment fragment = null;
switch (itemId) {
case R.id.nav_bus:
fragment = new BusFragment();
break;
case R.id.nav_hotel:
fragment = new HotelFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
displaySelectedScreen(item.getItemId());
return true;
}
}
From this fragment i have given intent to city.java activity
HotelFragment.java
public class HotelFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView= inflater.inflate(R.layout.fragment_hotel, container, false);
Button button = (Button) rootView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateDetail();
} });
return rootView;
}
public void updateDetail() {
Intent intent = new Intent(getActivity(), City.class);
startActivity(intent);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Hotel");
}
}
City.java
public class City extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_city_list);
} }
In manifest file i have added this
<activity android:name=".City_List"
android:parentActivityName = "MainActivity"
>
<meta-data
android:name = "android.support.PARENT_ACTIVITY"
android:value = "MainActivity" />
</activity>
</application>
to be able to go back to the previous fragment should include the .addToBackStack()
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackstack(null)
ft.commit();
}
and when you click on back button in the toolbar programmatically go back to the previous fragment using following code.
if ( getFragmentManager().getBackStackEntryCount() > 0)
{
getFragmentManager().popBackStack();
return;
}
super.onBackPressed();
Add this line inside back pressed method
if(getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
}
else {
super.onBackPressed();
}

Hamburger Icon not opening Navigation Drawer on parent fragment after returning from child fragment by clicking back arrow on toolbar

The app I am building uses navigation drawer android.support.v4.widget.DrawerLayout and MainActivity extends android.support.v7.app.AppCompatActivity. I have a parent fragment that is replaced by child fragment. On parent fragment default hamburger icon is properly toggling the navigation drawer. While on child fragment, hamburger icon is replaced by back arrow icon using this snippet
((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar = (Toolbar) (getActivity()).findViewById(R.id.toolbar);
((MainActivity)getActivity()).setSupportActionBar(toolbar);
On child fragment back button click event is handled on onOptionsItemSelected() and hamburger icon is shown again for parent fragment on onStop().
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getActivity().onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onStop() {
super.onStop();
((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
MainActivity.toggle.syncState();
}
On parent fragment hamburger icon is now showing properly but on clicking it the navigation drawer doesn't show up again.
Could anyone please help on what am I doing wrong?
Here are the relevant files:
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public static ActionBarDrawerToggle toggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
try {
Fragment fragment = (Fragment) ParentFragment.class.newInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_content, fragment).commit();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
ParentFragment.java
public class ParentFragment extends Fragment implements View.OnClickListener {
public static ParentFragment newInstance() {
ParentFragment fragment = new ParentFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onClick(View v) {
int i = v.getId();
Fragment fragment = null;
if(i == R.id.child_fragment_button) {
fragment = new ChildFragment();
}
if(fragment != null) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_content, fragment)
.addToBackStack(null)
.commit();
}
}
}
ChildFragment.java
public class ChildFragment extends Fragment {
private Toolbar toolbar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Show back button
((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar = (Toolbar) (getActivity()).findViewById(R.id.toolbar);
((MainActivity)getActivity()).setSupportActionBar(toolbar);
}
#Override
public void onStop() {
super.onStop();
((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
MainActivity.toggle.syncState();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getActivity().onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I finally came up with the solution. Thanks to this answer.
Here are the changes I made:
ChildFragment.java
public class ChildFragment extends Fragment {
private Toolbar toolbar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Show back button
toggle = MainActivity.toggle;
toggle.setDrawerIndicatorEnabled(false);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager manager = getActivity().getSupportFragmentManager();
manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
toggle.setDrawerIndicatorEnabled(true);
}
});
toolbar = (Toolbar) (getActivity()).findViewById(R.id.toolbar);
toolbar.setNavigationIcon(((MainActivity)getActivity()).getDrawerToggleDelegate().getThemeUpIndicator());
}
#Override
public void onStop() {
super.onStop();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
default:
return super.onOptionsItemSelected(item);
}
}
}

change navigation drawer selected item on fragment backstack change

I have two fragments FragmentHome and FragmentAbout, I have added NavigationDrawer to app when I click Home it opens FragmentHome and About opens FragmentAbout, when I open FragmentAbout I am also adding it to backstack. This is working fine.
Now the problem is when I click on About and press back button it goes to the FragmentHome but the NavigationDrawer still shows the About as selected item, I want to change this selected item to Home when I press back button from FragmentAbout
Home Activity:
public class ActivityHome extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Drawer layout
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.nav_drawer_open, R.string.nav_drawer_close);
assert drawer != null;
drawer.setDrawerListener(toggle);
toggle.syncState();
// Navigation view
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
// Open first menu item
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
// Set first item checked
navigationView.setCheckedItem(R.id.nav_home);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
final MenuItem menuItem = item;
// Check if menu item is selected
if (item.isChecked())
item.setChecked(false);
else
item.setChecked(true);
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentHome())
.commit();
} else if (id == R.id.nav_about) {
toolbar.setTitle("About");
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentAbout())
.addToBackStack(null)
.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}}
FragmentHome
public class FragmentHome extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(R.string.fragment_home_title);
}
}
FragmentAbout code is same as FragmentHome just layout change.
I have searched a lot on stackoverflow but didn't find any solution yet, so if someone know how to do this please tell me.
There is a OnBackStackChangedListener that you can use for this. Tried it and it works great.
public Fragment getCurrentFragment() {
return this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
this.getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
Fragment current = getCurrentFragment();
if (current instanceof MyFragmentA) {
navigationView.setCheckedItem(R.id.nav_myfragA);
} else {
navigationView.setCheckedItem(R.id.nav_myfragB);
}
}
});
...
}
This might not be a good solution, but at least it is acceptable for me. You need to store fragment's position inside stack variable (ex: List) whenever a fragment menu is clicked from nav drawer. Then override onBackPressed to remove the last value from stack, and set drawer position to the current last value of stack. Here's the example:
private List<Integer> itemPositionStacks = new ArrayList<>();
protected void onCreate(#Nullable Bundle savedInstanceState) {
itemPositionStacks.add(currentSelectedPosition);
}
public void onNavigationViewItemSelected(int itemId) {
Fragment fr = null;
switch (itemId) {
case 0:
fr = new aFragment();
break;
case 1:
fr = new bFragment();
break;
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fr)
.addToBackStack(null)
.commit();
Drawer.getInstance().setDrawerChecked(itemId);
itemPositionStacks.add(itemId);
}
public void onBackPressed() {
if(itemPositionStacks.size() > 1) {
itemPositionStacks.remove(itemPositionStacks.size() - 1);
Drawer.getInstance().setDrawerChecked(itemIdStacks.get(itemIdStacks.size() - 1));
}
super.onBackPressed();
}
In your onBackPressed() function ..
you must choose which item to be selected by using
drawer.setCheckedItem(R.id.nav_home);
and remove the selection of the another item
drawer.getMenu().findItem(R.id.nav_about).setChecked(false);

Categories

Resources