Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 904
Ankit Tale Avatar asked May 09 '17 12:05

Ankit Tale


People also ask

How do you keep a bottom nav bar from being pushed up on keyboard?

Try removing this: android:windowSoftInputMode="adjustResize" from AndroidManifest. xml This should help. You have 3 options for what to do when the keyboard shows- scroll the app such that the cursor is onscreen, resize the app in the remaining space, or nothing. Number 2 is probably the closest to what you want.

How do I create a bottom navigation view?

Right-click on the res folder and select Android Resource Directory. Make sure to select the resource type as a menu. Now create the bottom_menu.


2 Answers

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:

  1. Know how many fragments there are in the stack before the commit
  2. If the fragment is not "home type", save it to the stack before the commit

  3. 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);
            }
        }
    });
}
like image 52
marco Avatar answered Oct 07 '22 01:10

marco


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);
}
like image 41
Shailesh Bandil Avatar answered Oct 07 '22 02:10

Shailesh Bandil