Android bottom navigation bar when press back go to previous fragment - android

Here is my navigation bar :
There are 4 items in my bottom nav bar , I want it to back to previous fragment when I press the back button,
Here`s my xml :
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottomnav"
android:layout_width="382dp"
android:layout_height="52dp"
android:layout_marginBottom="0dp"
app:itemBackground="#color/backbeyez"
app:itemIconTint="#drawable/nav_items_color"
app:itemTextColor="#drawable/nav_items_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation"
tools:layout_editor_absoluteY="515dp">
</android.support.design.widget.BottomNavigationView>
Here`s the code for MainActivity :
public class MainActivity extends AppCompatActivity {
public void switchorders() {
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, new OrdersLayout()).commit();
}
public void switchcredits() {
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, new CreditLayout()).commit();
}
public void switchworks() {
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, new ListLayout()).commit();
}
public void switchprofile() {
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, new ProfileLayout()).commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switchorders();
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottomnav);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_orders:
switchorders();
break;
case R.id.navigation_credit:
switchcredits();
break;
case R.id.navigation_works:
switchworks();
break;
case R.id.navigation_profile:
switchprofile();
break;
}
return true;
}
});
}
I also tried defining a back button with the statements below but they didn`t work :
public void aboutback(View view) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
{
boolean done = getSupportFragmentManager().popBackStackImmediate();
}
}
and also "popbackstack()" and "popbackstackImmediate()" did not work!

If you want to handle backpress in fragment than you should add addToBackStack() when adding or replacing a fragment
try to add like that in your all fragment
public void switchorders() {
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, new OrdersLayout()).addToBackStack("TAG").commit();
}
It will be handle by default.
You can also handle in onBackPress() in activity if you want

Following code will set the icon of the home fragment icon of the bottom navigation to active, use accordingly to make active each icon on back press:
final BottomNavigationView mBottomNav = findViewById(R.id.nav_view);
MenuItem homeItem = mBottomNav.getMenu().getItem(0);
mBottomNav.setSelectedItemId(homeItem.getItemId());

Use AlertDialog On BackPressed try this,
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes, new OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
WelcomeActivity.super.onBackPressed();
}
}).create().show();
}
I hope this may help you..

Related

BackStack not navigating to the correct Fragment

Hello im trying to navigate between some fragments with addToBaackStack but having issues with it ,
Ok i will explain it in detail so there should be no confusuion
1 :- I have only one activity (main activity) which consist of all the other fragments and a fragment container to hold the fragments in it , i have implemented bottom navigation in the main activity ,where the bottom navigation have 5 main fragments home,following,upload,notification and profile my issues is related to the profile fragment
2 :- In the profile fragment i have some buttons like edit profile button which opens edit profile fragment but now when i presse back it should navigate back to the profile fragment which it is not doing ,its is navigating to the last fragment of the bottomnavigation (which can be any other of the main fragments for eg if my last fragment is following fragment then when i press back from the edit profile fragment it goes to the following fragment )but this not happens if i put a back arrow icon in edit profile fragment then when i click the back arrow it perfectly navigate me to the profile fragments as it is not related to addToBackStack
It shows that the issue is related with my bottom navigation but i dont know how to exactly fix it
Prifile_Fragment.java
editProfileButton.setOnClickListener(v -> {
Fragment edit_profile = new Edit_Profile();
assert getFragmentManager() != null;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, edit_profile);
transaction.addToBackStack(null);
transaction.commit();
});
MainActivity.java // where the bottom navigation is implemented
public class MainActivity extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
Deque<Integer> integerDeque = new ArrayDeque<>(4);
boolean flag = true;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setContentView(R.layout.activity_main);
Window window = this.getWindow();
window.setStatusBarColor(this.getResources().getColor(R.color.black));
bottomNavigationView = findViewById(R.id.bottom_navigation_view);
integerDeque.push(R.id.nav_home);
loadFragments(new Home_Fragment());
bottomNavigationView.setSelectedItemId(R.id.nav_home);
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
int id = item.getItemId();
if (integerDeque.contains(id)) {
if (id == R.id.nav_home) {
integerDeque.size();
if (flag) {
integerDeque.addFirst(R.id.nav_home);
flag = false;
}
}
integerDeque.remove(id);
}
integerDeque.push(id);
loadFragments(getFragment(item.getItemId()));
return false;
}
);
}
#SuppressLint("NonConstantResourceId")
private Fragment getFragment(int itemId) {
switch (itemId) {
case R.id.nav_home:
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
case R.id.nav_following:
bottomNavigationView.getMenu().getItem(1).setChecked(true);
return new Following_Fragment();
case R.id.nav_upload:
bottomNavigationView.getMenu().getItem(2).setChecked(true);
return new Upload_Fragment();
case R.id.nav_notification:
bottomNavigationView.getMenu().getItem(3).setChecked(true);
return new Notification_Fragment();
case R.id.nav_profile:
bottomNavigationView.getMenu().getItem(4).setChecked(true);
return new Profile_Fragment();
}
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
}
public void loadFragments(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName())
.commit();
}
}
#Override
public void onBackPressed() {
integerDeque.pop();
if (!integerDeque.isEmpty()) {
loadFragments(getFragment(integerDeque.peek()));
} else {
finish();
}
}
}
Have you consider to use popBackStack ? You can try this.
#Override
public void onBackPressed() {
final FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
finish();
}
}

Android show AlertDialog before fragment change

I want to show AlertDialog before fragment changes from StageZeroFragment to any other. I change fragments with my BottomNavigationView:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stages);
util = new Util(this);
bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
displayView(item.getItemId());
return true;
}
});
}
public void displayView(int viewId) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (viewId) {
case R.id.navigation_stage_zero:
fragment = new StageZeroFragment();
break;
case R.id.navigation_stage_one:
fragment = new StageOneFragment();
break;
case R.id.navigation_stage_two:
fragment = new StageTwoFragment();
break;
case R.id.navigation_stage_three:
fragment = new StageThreeFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
}
I was trying to write something like this in my StageZeroFragment:
#Override
public void onPause() {
new AlertDialog.Builder(getActivity(), R.style.MojStyl).setIcon(android.R.drawable.ic_dialog_info)
.setCancelable(false).setTitle(R.string.hide_dialog_title)
.setMessage(R.string.stage_zero_confirmation)
.setPositiveButton((R.string.no), null)
.setNegativeButton((R.string.yes), (dialog, which) -> {
editor.putBoolean("correctionDone", true);
editor.apply();
super.onPause();
}).show();
}
but there was en error saying that super.onPause() is not called. So how can I achieve possibility to show AlertDialog when StageZeroFragment is shown and before fragment is changed to another from BottomNavigationView? Thank you in advance!
You don't need onPause for this. You can show dialog in onNavigationItemSelected and perform fragment transaction displayView on button click of AlertDialog.
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if(bottomNavigationView.getSelectedItemId() == R.id.navigation_stage_zero){
new AlertDialog.Builder(getActivity(), R.style.MojStyl).setIcon(android.R.drawable.ic_dialog_info)
.setCancelable(false).setTitle(R.string.hide_dialog_title)
.setMessage(R.string.stage_zero_confirmation)
.setPositiveButton((R.string.no), null)
.setNegativeButton((R.string.yes), (dialog, which) -> {
editor.putBoolean("correctionDone", true);
editor.apply();
displayView(R.id.navigation_stage_one);
}).show();
} else {
displayView(item.getItemId());
}
return true;
}
});

How to keep fragments state like Instagram in Android?

I need to implement the UI of my app, like the Instagram one. I need to switch from different fragments, with the usage of the bottom navigation view, but I need to keep state of the fragments, like I left them. How Can I achieve this?
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
item.setChecked(true);
switch (item.getItemId()) {
case R.id.action_formation:
if (homeFragment == null) {
homeFragment = new HomeFragment();
}
displayFragment(homeFragment);
break;
case R.id.action_result:
if (introResultFragment == null) {
introResultFragment = new IntroResultFragment();
}
displayFragment(introResultFragment);
break;
case R.id.action_market:
displayFragment(new MarketFragment());
break;
}
return false;
}
public void displayFragment(final Fragment fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment, fragment.getClass().toString());
fragmentTransaction.commit();
}
It's been a long time but I want to offer my open source library in github which implements the same UX of Youtube and Instagram:
https://github.com/ZachBublil/ZNavigator
You got to add this dependency to your gradle:
compile 'com.zach.znavigator:znavigator:1.0.0'
The only thing you have to do is to pass the list of fragments you want to be in the BottomNavigationView:
public class SampleActivity extends NavigationActivity {
private BottomNavigationView navigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navigationView = (BottomNavigationView) findViewById(R.id.navigationView);
LinkedHashMap<Integer, Fragment> rootFragments = new LinkedHashMap<>();
rootFragments.put(R.id.tab1, new FirstTab());
rootFragments.put(R.id.tab2,new SecondTab());
rootFragments.put(R.id.tab3, new ThirdTab());
init(rootFragments, R.id.container);
navigationView.setOnNavigationItemSelectedListener(this);
navigationView.setOnNavigationItemReselectedListener(this);
}
#Override
public void tabChanged(int id) {
navigationView.getMenu().findItem(id).setChecked(true);
}
}
If you want to open a new fragment as inner screen in one of the tabs you can do it by using ZNavigation class in the tab fragment:
ZNavigation.openChildFragment(getFragmentManager(),new ChildFragment());
just remember the active fragment, and use userVisiableHint to get active status in each fragment.
private Fragment currentFragment; // need to be init
private void switch2Fragment(Fragment target){
getFragmentManager().executePendingTransactions();
if(target.isAdded){
getFragmentManager().beginTransaction().hide(currentFragment).show(target).commit();
} else {
getFragmentManager().beginTransaction().hide(currentFragment).add(R.id.xxx, target).commit();
}
currentFragment.setUserVisibleHint(false);
currentFragment = target;
target.setUserVisibleHint(true);
}
private boolean isFragmentActive(Fragment target){
return target.getUserVisibleHint();
}

How to handle bottom navigation perfectly with back pressed

I am working on a bottom navigation bar, but I am not getting perfectly bottom navigation bar.
My MainActivity class:
public class MainActivity extends AppCompatActivity {
private static final String SELECTED_ITEM = "selected_item";
private BottomNavigationView bottomNavigationView;
private Toolbar toolbar;
private MenuItem menuItemSelected;
private int mMenuItemSelected;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
selectFragment(item);
return true;
}
});
//Always load first fragment as default
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, new AnnouncementFragment());
fragmentTransaction.commit();
if (savedInstanceState != null) {
mMenuItemSelected = savedInstanceState.getInt(SELECTED_ITEM, 0);
menuItemSelected = bottomNavigationView.getMenu().findItem(mMenuItemSelected);
} else {
menuItemSelected = bottomNavigationView.getMenu().getItem(0);
}
selectFragment(menuItemSelected);
}
private void selectFragment(MenuItem item) {
Fragment fragment = null;
Class fragmentClass;
switch (item.getItemId()) {
case R.id.action_announcement:
fragmentClass = AnnouncementFragment.class;
break;
case R.id.action_menu:
fragmentClass = MenuFragment.class;
break;
case R.id.action_menu_reports:
fragmentClass = ReportFragment.class;
break;
case R.id.action_setting:
fragmentClass = SettingFragment.class;
break;
default:
fragmentClass = AnnouncementFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frameLayout, fragment).commit();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SELECTED_ITEM, mMenuItemSelected);
super.onSaveInstanceState(outState);
}
And my back pressed also not working properly:
#Override
public void onBackPressed() {
MenuItem homeItem = bottomNavigationView.getMenu().getItem(0);
if (mMenuItemSelected != homeItem.getItemId()) {
selectFragment(homeItem);
} else {
super.onBackPressed();
}
}
How should I do that because bottom menu has uneven distribution on bar. How to properly maintain the menu space without uneven distribution.
Here I am attaching my result which I obtain on AVD
According to the guidelines for Material Design
On Android, the Back button does not navigate between bottom
navigation bar views.
EDIT: Material Design link no longer mentions back button behavior.
Pressing the back button you can quit the application, which is the default behavior, such as in Google Photo...
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
// note: there is NOT a addToBackStack call
fragmentTransaction.commit();
...or lead the user to the home section and then, if pushed again, at the exit.
Personally I find this last pattern much better.
To get it without override onBackPressed you need to identify the home fragment and differentiate it from all the others
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
viewFragment(new HomeFragment(), FRAGMENT_HOME);
return true;
case R.id.navigation_page_1:
viewFragment(new OneFragment(), FRAGMENT_OTHER);
return true;
case R.id.navigation_page_2:
viewFragment(new TwoFragment(), FRAGMENT_OTHER);
return true;
}
return false;
}
});
What you have to do now is write the viewfragment method that have to:
Know how many fragments there are in the stack before the commit
If the fragment is not "home type", save it to the stack before
the commit
Add an OnBackStackChangedListener that when the stack decreases,
(i.e. when I pressed back ), delete all the fragments that are
not "home type" (POP_BACK_STACK_INCLUSIVE) , bringing us to the home fragment
Below the full method with comments
private void viewFragment(Fragment fragment, String name){
final FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
// 1. Know how many fragments there are in the stack
final int count = fragmentManager.getBackStackEntryCount();
// 2. If the fragment is **not** "home type", save it to the stack
if( name.equals( FRAGMENT_OTHER) ) {
fragmentTransaction.addToBackStack(name);
}
// Commit !
fragmentTransaction.commit();
// 3. After the commit, if the fragment is not an "home type" the back stack is changed, triggering the
// OnBackStackChanged callback
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
// If the stack decreases it means I clicked the back button
if( fragmentManager.getBackStackEntryCount() <= count){
// pop all the fragment and remove the listener
fragmentManager.popBackStack(FRAGMENT_OTHER, POP_BACK_STACK_INCLUSIVE);
fragmentManager.removeOnBackStackChangedListener(this);
// set the home button selected
navigation.getMenu().getItem(0).setChecked(true);
}
}
});
}
Try this
#Override
public void onBackPressed() {
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
int seletedItemId = bottomNavigationView.getSelectedItemId();
if (R.id.home != seletedItemId) {
setHomeItem(MainActivity.this);
} else {
super.onBackPressed();
}
}
public static void setHomeItem(Activity activity) {
BottomNavigationView bottomNavigationView = (BottomNavigationView)
activity.findViewById(R.id.navigation);
bottomNavigationView.setSelectedItemId(R.id.home);
}
#Override
public void onBackPressed() {
BottomNavigationView mBottomNavigationView = findViewById(R.id.navigation);
if (mBottomNavigationView.getSelectedItemId() == R.id.navigation_home)
{
super.onBackPressed();
finish();
}
else
{
mBottomNavigationView.setSelectedItemId(R.id.navigation_home);
}
}
This is maybe a little late but I think the best way to do it is as simple as this.
#Override
public void onBackPressed() {
if (mBottomNavigationView.getSelectedItemId() == R.id.action_home) {
super.onBackPressed();
} else {
mBottomNavigationView.setSelectedItemId(R.id.action_home);
}
}
I hope it helps and happy coding :)
onBackPressed did not worked for me. So this I used.
#Override
protected void onResume() {
super.onResume();
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
The best way is: when in home button the app is closed and when in another button back in home button.
Below I put my code :
first i'm load home button in navigation View :
private void loadFragment(Fragment fragment) {
Toast.makeText(this, "load", Toast.LENGTH_SHORT).show();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment, TAG_FRAGMENT);
transaction.commit();
}
and remember dont call addToBackStack() .
and then handle the situation by onBackPressed() :
#Override
public void onBackPressed() {
if (navigation.getSelectedItemId() == R.id.bottomAkhbar) {
super.onBackPressed();
} else {
navigation.setSelectedItemId(R.id.bottomAkhbar);
}
}
I had the same problem so I solved my problem using this method:
In my main activity, I have a bottom nav bar and a nav drawer, I need to sync items in my drawer and bottom nav:
I created a method for my main fragment and the others:
my main fragment replacer:
public void MainFragmentChanger(final Fragment fragment, final String TAG){
if (main_page_fragment != null){
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.remove(main_page_fragment).commit();
}
if (main_drawer.isDrawerOpen()){
main_drawer.closeDrawer();
}
new Handler().post(new Runnable() {
#Override
public void run() {
main_page_fragment = fragment;
main_page_fragment.setRetainInstance(true);
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_container, main_page_fragment,TAG);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.commitAllowingStateLoss();
}
});
}
and this is for my other fragment replacer:
public void changeBottomFragment(final Fragment fragment, final String TAG){
if (main_drawer.isDrawerOpen()){
main_drawer.closeDrawer();
}
new Handler().post(new Runnable() {
#Override
public void run() {
main_page_fragment = fragment;
main_page_fragment.setRetainInstance(true);
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_container, main_page_fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.commitAllowingStateLoss();
}
});
}
so after that, I need to sync items in both drawer and bar:
Note I use material navigation drawer by Mike Penz, and com.ashokvarma.bottomnavigation.BottomNavigationBar for nav bar.
here is the method for that purpose:
public void changeNavAndBarStats(String tag){
if (tag == "flash"){
bottomNavigationBar.selectTab(2,false);
main_drawer.setSelection(flashcards.getIdentifier(),false);
}else if (tag == "dic"){
bottomNavigationBar.selectTab(3,false);
main_drawer.setSelection(dictionary.getIdentifier(),false);
}else if (tag == "Home"){
bottomNavigationBar.selectTab(0,false);
main_drawer.setSelection(home.getIdentifier(),false);
}
}
So I call my fragments Like this:
MainFragmentChanger(new MainPageFragment(),"Home");
bottomNavigationBar.selectTab(0,false);
changeBottomFragment(new FlashCardFragment(),"flash");
bottomNavigationBar.selectTab(2,false);
changeBottomFragment(new TranslateFragment(),"dic");
bottomNavigationBar.selectTab(3,false);
At the end I call changeNavAndBarStatus in my fragment's onResume method:
((MainPageActivity)getContext()).changeNavAndBarStats("flash");
That's it! you are good to go!
Try this to achieve the following:
on back press:
from home fragment exit the app.
from other fragments goto home fragment.
//On Back Press if we are at a Fragment other than the Home Fragment it will navigate back to the
// Home Fragment. From Home Fragment it will exit the App.
#Override
public void onBackPressed() {
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackEntryCount == 0) {
super.onBackPressed();
} else {
goHome();
}
}
public void goHome() {
//Following code will set the icon of the bottom navigation to active
final BottomNavigationView mBottomNav = findViewById(R.id.nav_view);
MenuItem homeItem = mBottomNav.getMenu().getItem(0);
mBottomNav.setSelectedItemId(homeItem.getItemId());
getSupportFragmentManager().popBackStackImmediate();
//To delete all entries from back stack immediately one by one.
int backStackEntry = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackEntry; i++) {
getSupportFragmentManager().popBackStackImmediate();
}
//To navigate to the Home Fragment
final HomeFragment homeFragment = new HomeFragment();
FragmentTransaction myFragmentTransaction = getSupportFragmentManager().beginTransaction();
myFragmentTransaction.replace(R.id.nav_host_fragment, homeFragment, "HomeFrag Tag");
myFragmentTransaction.commit();
}
You can try this /
its worked for me
public class MainActivity extends BaseActivity {
private HomeFragment homeFragment = new HomeFragment();
private CartFragment cartFragment = new CartFragment();
private ProfileFragment profileFragment = new ProfileFragment();
private BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null){
setContentView(R.layout.activity_main);
bottomNavigationView = findViewById(R.id.bottom_nav);
bottomNavigationView.setSelectedItemId(R.id.btnHome);
FragmentTransaction homeFm = getSupportFragmentManager().beginTransaction();
homeFm.replace(R.id.fragment_container, homeFragment);
homeFm.commit();
setupView();
}
}
private void setupView() {
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
{
switch (item.getItemId()) {
case R.id.btnHome:
loadFragment(homeFragment);
return true;
case R.id.btnCart:
loadFragment(cartFragment);
return true;
case R.id.btnProfile:
loadFragment(profileFragment);
return true;
}
return false;
}
});
}
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
if (bottomNavigationView.getSelectedItemId() == R.id.btnHome)
{
finish();
}
else
{
bottomNavigationView.setSelectedItemId(R.id.btnHome);
}
}}
Use addToBackStack Method when calling a fragment like this,
getSupportFragmentManager().beginTransaction().addToBackStack(null).add(R.id.content_home_nav,newFragment).commit();
Use this code in your onBackPressed Method
if (getSupportFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
For your requirement you would be working with fragments on navigation for this you can use Tablayout with view pager and make bottom navigation.
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="60dp"></android.support.design.widget.TabLayout>
and then setup viewpager with tab layout and add icon to tablayout in your activity
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
viewPager = (ViewPager) findViewById(R.id.controller_pager);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
viewPager.setOffscreenPageLimit(4);
tabLayout.setupWithViewPager(viewPager);
tabLayout.getTabAt(0).setIcon(R.drawable.selector_home);
tabLayout.getTabAt(1).setIcon(R.drawable.selector_contact);
tabLayout.getTabAt(2).setIcon(R.drawable.selector_profile);
tabLayout.getTabAt(3).setIcon(R.drawable.selector_settings);
now handle all things on the click of tablayout and it will work fine
tabLayout.addOnTabSelectedListener(this);
I was facing the same problem but after doing this I got the solution
First Paste this code in your main activity (where you are using Bottom navigation bar)
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
And then create a class named BottomNavigationViewHelper and paste the following code.
public class BottomNavigationViewHelper {
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}
Hope It helps
Try this.
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
// Gets the previous global stack count
int previousStackCount = mPreviousStackCount;
// Gets a FragmentManager instance
FragmentManager localFragmentManager = getSupportFragmentManager();
// Sets the current back stack count
int currentStackCount = localFragmentManager.getBackStackEntryCount();
// Re-sets the global stack count to be the current count
mPreviousStackCount = currentStackCount;
boolean popping = currentStackCount < previousStackCount;
if(popping){
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
}
});
Please try this solution.
I have made changes in your code given in question.
I have assumed that on back pressing first time your app will come back to home fragment (in your case Announcement fragment) and if you back press again, the app will close.
This flow will also reflect in bottom navigation bar.
public class MainActivity extends AppCompatActivity {
private static final String BACK_STACK_ROOT_TAG = "root_home_fragment";
private static final String SELECTED_ITEM = "selected_item";
private Fragment fragment;
private FragmentManager fragmentManager;
private BottomNavigationView bottomNavigationView;
private Toolbar toolbar;
private MenuItem menuItemSelected;
private int mMenuItemSelected;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
boolean selected = false;
switch (item.getItemId()) {
case R.id.action_announcement:
fragment = AnnouncementFragment.newInstance();
selected = true;
break;
case R.id.action_menu:
fragment = MenuFragment.newInstance();
selected = true;
break;
case R.id.action_menu_reports:
fragment = ReportFragment.newInstance();
selected = true;
break;
case R.id.action_setting:
fragment = SettingFragment.newInstance();
selected = true;
}
if(fragment !=null){
fragmentManager = getFragmentManager();
switch (item.getItemId()) {
case R.id.action_announcement:
// Pop every fragment from backstack including home fragment.
fragmentManager.popBackStack(BACK_STACK_ROOT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack(BACK_STACK_ROOT_TAG)
.commit();
break;
default:
fragmentManager.beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack(null)
.commit();
break;
}
}
return selected;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
//Always load first fragment as default
bottomNavigationView.setSelectedItemId(R.id.action_announcement);
if (savedInstanceState != null) {
mMenuItemSelected = savedInstanceState.getInt(SELECTED_ITEM, 0);
menuItemSelected = bottomNavigationView.getMenu().findItem(mMenuItemSelected);
} else {
menuItemSelected = bottomNavigationView.getMenu().getItem(0);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SELECTED_ITEM, mMenuItemSelected);
super.onSaveInstanceState(outState);
}
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if(count >1){
// We have lots of fragment on backstack to be popped.
// Pop till the root fragment.
getFragmentManager().popBackStack(BACK_STACK_ROOT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
bottomNavigationView.setSelectedItemId(R.id.action_announcement);
}
else{
// Close the application when we are on home fragment.
supportFinishAfterTransition();
}
}
}
Most time when you, press back button, old fragment in the back stack,
are recalled. therefore the system call this onCreateView() method
there add this code
val bottomNav = activity?.findViewById<BottomNavigationView>(R.id.activity_main_bottom_navigation)
bottomNav?.selectedItemId = R.id.the_id_of_the_icon__that_represent_the_fragment
I did this after trying all and everything and at last it worked -_- .I have pasted this 2 override method in my each and every activity that i am surfing through my bottom navigation.
#Override
protected void onResume() {
super.onResume();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_Menu_name);
bottomNavigationView.getMenu().getItem(Menu_item_position).setChecked(true);
}
#Override
protected void onRestart() {
super.onRestart();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_Menu_name);
bottomNavigationView.getMenu().getItem(Menu_item_position).setChecked(true);
}
Late answer but here it goes.
Let's say you have a BottomNavigation inside MainActivity with 4 Fragments.
FragmentA
FragmentB
FragmentC
FragmentD
If your are adding each fragment to backstack like so:
With kotlin:
main_bottom_navigation.setOnNavigationItemSelectedListener { item ->
var fragment: Fragment? = null
when (item.itemId) {
R.id.nav_a -> fragment = FragmentA()
R.id.nav_b -> fragment = FragmentB()
R.id.nav_c -> fragment = FragmentC()
R.id.nav_d -> fragment = FragmentD()
}
supportFragmentManager
.beginTransaction()
.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out)
.replace(R.id.home_content, fragment!!)
.addToBackStack(fragment.tag)
.commit()
true
}
You dont really need to override onBackPressed() inside the MainActivity but explicitly cast on each fragment and assigning the BottomNavigation like this:
FragmentA.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(0).isChecked = true
}
FragmentB.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(1).isChecked = true
}
FragmentC.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(2).isChecked = true
}
FragmentD.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(3).isChecked = true
}
Like this the fragment backstack will properly pop and even exit application when it reaches 0.
This is what I did to handle back press in the activity:
#Override
public void onBackPressed() {
super.onBackPressed();
if(homeFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_home);
}
if(searchFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_search);
}
if(myProfileFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_profile);
}
}
this code is work for me:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.unsubscribeWhenNotificationsAreDisabled(true)
.init();
bottomNavigationView = findViewById(R.id.bottomNav);
frameLayout = findViewById(R.id.main_frame);
homeFragment = new HomeFragment();
aboutUsFragment = new AboutUsFragment();
recipesFragment = new RecipesFragment();
knowledgeFragment = new KnowledgeFragment();
contactFragment = new ContactFragment();
loadFragment(homeFragment);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.home:
//mManiNav.setItemBackgroundResource(R.color.blue);
loadFragment(homeFragment);
return true;
case R.id.deposit:
// mManiNav.setItemBackgroundResource(R.color.colorAccent);
loadFragment(recipesFragment);
return true;
case R.id.exchange:
//mManiNav.setItemBackgroundResource(R.color.colorPrimary);
loadFragment(knowledgeFragment);
return true;
case R.id.profile:
// mManiNav.setItemBackgroundResource(R.color.light_blue);
loadFragment(aboutUsFragment);
return true;
case R.id.payout:
// mManiNav.setItemBackgroundResource(R.color.light_blue);
loadFragment(contactFragment);
return true;
default:
return false;
}
}
});
}
Here the load fragment class:
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
Here is the popBackStackTillEntry method:
enter code here public void popBackStackTillEntry(int entryIndex) {
if (getSupportFragmentManager() == null) {
return;
}
if (getSupportFragmentManager().getBackStackEntryCount() <= entryIndex) {
return;
}
FragmentManager.BackStackEntry entry = getSupportFragmentManager().getBackStackEntryAt(
entryIndex);
if (entry != null) {
getSupportFragmentManager().popBackStackImmediate(entry.getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Here is the backpress method:
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
popBackStackTillEntry(0);
moveTaskToBack(true);
System.exit(0);
return;
}
this.doubleBackToExitPressedOnce = true;
loadFragment(new HomeFragment());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
This is a simple and complete working code in Kotlin.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomNavigationView = findViewById(R.id.bottom_navigation)
bottomNavigationView.setOnItemSelectedListener {menuItem ->
when(menuItem.itemId){
R.id.navBottom_menu_1 -> nextFragment(Fragment_1())
R.id.navBottom_menu_2 -> nextFragment(Fragment_2())
R.id.navBottom_menu_3 -> nextFragment(Fragment_3())
R.id.navBottom_menu_4 -> nextFragment(Fragment_4())
else ->false
}
}
}
fun nextFragment(fm:Fragment): Boolean {
supportFragmentManager.beginTransaction().replace(R.id.linearLayout_rootFragment, fm).commit()
return true
}
fun isMenuChecked(itemIndex:Int):Boolean{
return bottomNavigationView.menu.getItem(itemIndex).isChecked
}
fun setMenuItemChecked(itemIndex:Int){
bottomNavigationView.menu.getItem(itemIndex).isChecked = true
}
override fun onBackPressed() {
when(true){
isMenuChecked(3) -> {nextFragment(Fragment_3()) ; setMenuItemChecked(2) }
isMenuChecked(2) -> {nextFragment(Fragment_2()) ; setMenuItemChecked(1) }
isMenuChecked(1) -> {nextFragment(Fragment_1()) ; setMenuItemChecked(0) }
else -> super.onBackPressed()
}
}
}
This is how I solved my,
Wrap your main widget in WillPopScope() and set a function in the onWillpop: as this
Future<bool> _onBackpress() {
if (_currentpage != 0) {
setState(() {
_currentpage--;//decreases number of pages till the fisrt page
});
} else {
// a function to close the app
}
}

Why not works ClickListeners for Toolbar?

I use MaterialDrawer and code MainActivity is:
public class MainActivity extends AppCompatActivity implements KitchenFragment.CallbackOne {
public static final String TAG = "myLogTag";
private Toolbar mToolbar;
private Drawer drawer;
private FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "CLICK NOCL");
}
});
setSupportActionBar(mToolbar);
// getSupportActionBar().setDisplayHomeAsUpEnabled(false);
fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.content_frame);
if (fragment == null) {
fragment = MenuFragment.newInstance();
fm.beginTransaction()
.add(R.id.content_frame, fragment)
.commit();
}
drawer = new DrawerBuilder()
.withActivity(this)
.withToolbar(mToolbar)
.withActionBarDrawerToggle(true)
.withHeader(R.layout.drawer_header)
.addDrawerItems(
new PrimaryDrawerItem().withName(R.string.menu).withIdentifier(1),
new PrimaryDrawerItem().withName(R.string.kitchen_title).withIdentifier(2),
new PrimaryDrawerItem().withName(R.string.information_title).withEnabled(false)
).withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
#Override
public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
Log.d(TAG, "position clicked: " + position);
Fragment fragment = MenuFragment.newInstance();
switch (position) {
case 1:
fragment = MenuFragment.newInstance();
break;
case 2:
fragment = KitchenFragment.newInstance();
break;
default:
fragment = new Fragment();
}
fm.beginTransaction().replace(R.id.content_frame, fragment).commit();
return false;
}
})
.withFireOnInitialOnClick(true)
.withSavedInstance(savedInstanceState)
.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
#Override
public boolean onNavigationClickListener(View view) {
Log.d(TAG, "CLICK in DNL");
if (!drawer.getActionBarDrawerToggle().isDrawerIndicatorEnabled()) {
onBackPressed();
return true;
} else
return false;
}
})
.build();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.d(TAG, "CLICK OIS");
switch (item.getItemId()) {
case R.id.action_settings:
return true;
case android.R.id.home:
getFragmentManager().popBackStackImmediate();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState = drawer.saveInstanceState(outState);
super.onSaveInstanceState(outState);
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen())
drawer.closeDrawer();
else if (getFragmentManager().getBackStackEntryCount() == 1) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
drawer.getActionBarDrawerToggle().syncState();
getFragmentManager().popBackStack();
} else if (getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStack();
else
super.onBackPressed();
}
#Override
public void setFirstSelected() {
drawer.setSelection(1);
}
}
I'm trying to trace a Click in mToolbar.setNavigationOnClickListener
and withOnDrawerNavigationListener and onOptionsItemSelected.
None of the listeners not reacted for clicking.
How you see i use Activity that launches Fragment (1), which in turn lets Fragment (2 and 3). In 2 and 3 Fragment in OnCreate i use ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true); , and I need to by pressing the back button (in toolbar), returning the previous fragment, and not open Drawer
The MaterialDrawer already handles all the listeners for you. If you need to do an action after the drawer opens or closes you can provide the listener via the DrawerBuilder
For the icon you have this listener:
OnDrawerNavigationListener
https://github.com/mikepenz/MaterialDrawer/blob/develop/library/src/main/java/com/mikepenz/materialdrawer/DrawerBuilder.java#L1158
For drawer close / open this listener:
OnDrawerListener
https://github.com/mikepenz/MaterialDrawer/blob/develop/library/src/main/java/com/mikepenz/materialdrawer/DrawerBuilder.java#L1116
I suggest you to create new Activity using android studio wizard. File->New->Activity->Navigation Drawer Activity.
In that case ActionBarDrawerToaggle is used
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
This toggle contains click listener which handle open/close drawer functionality for you.
Also you can that item clicks implemented through OnNavigationItemSelectedListener.onNavigationItemSelected(MenuItem item)

Categories

Resources