Separate Back Stack for each tab in BottomNavigationView Android using Fragments

前端 未结 5 2059
梦毁少年i
梦毁少年i 2020-12-13 07:27

I\'m implementing BottomNavigationView for navigation in an Android app. I am using Fragments to set the content for each tab.

I know how to set up one

5条回答
  •  忘掉有多难
    2020-12-13 07:39

    Finally, I found the solution, it was inspired by a previous answer on StackOverflow: Separate Back Stack for each tab in Android using Fragments
    I only have replaced TabHost with BottomNavigationView and here is the code:
    Main Activity

    public class MainActivity extends AppCompatActivity {
    
    private HashMap> mStacks;
    public static final String TAB_HOME  = "tab_home";
    public static final String TAB_DASHBOARD  = "tab_dashboard";
    public static final String TAB_NOTIFICATIONS  = "tab_notifications";
    
    private String mCurrentTab;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
    
        mStacks = new HashMap>();
        mStacks.put(TAB_HOME, new Stack());
        mStacks.put(TAB_DASHBOARD, new Stack());
        mStacks.put(TAB_NOTIFICATIONS, new Stack());
    
        navigation.setSelectedItemId(R.id.navigation_home);
    }
    
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {
    
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    selectedTab(TAB_HOME);
                    return true;
                case R.id.navigation_dashboard:
                    selectedTab(TAB_DASHBOARD);
                    return true;
                case R.id.navigation_notifications:
                    selectedTab(TAB_NOTIFICATIONS);
                    return true;
            }
            return false;
        }
    
    };
    
    private void gotoFragment(Fragment selectedFragment)
    {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.content, selectedFragment);
        fragmentTransaction.commit();
    }
    
    private void selectedTab(String tabId)
    {
        mCurrentTab = tabId;
    
        if(mStacks.get(tabId).size() == 0){
          /*
           *    First time this tab is selected. So add first fragment of that tab.
           *    Dont need animation, so that argument is false.
           *    We are adding a new fragment which is not present in stack. So add to stack is true.
           */
            if(tabId.equals(TAB_HOME)){
                pushFragments(tabId, new HomeFragment(),true);
            }else if(tabId.equals(TAB_DASHBOARD)){
                pushFragments(tabId, new DashboardFragment(),true);
            }else if(tabId.equals(TAB_NOTIFICATIONS)){
                pushFragments(tabId, new NotificationsFragment(),true);
            }
        }else {
          /*
           *    We are switching tabs, and target tab is already has atleast one fragment.
           *    No need of animation, no need of stack pushing. Just show the target fragment
           */
            pushFragments(tabId, mStacks.get(tabId).lastElement(),false);
        }
    }
    
    public void pushFragments(String tag, Fragment fragment, boolean shouldAdd){
        if(shouldAdd)
            mStacks.get(tag).push(fragment);
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        ft.replace(R.id.content, fragment);
        ft.commit();
    }
    
    public void popFragments(){
      /*
       *    Select the second last fragment in current tab's stack..
       *    which will be shown after the fragment transaction given below
       */
        Fragment fragment = mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2);
    
      /*pop current fragment from stack.. */
        mStacks.get(mCurrentTab).pop();
    
      /* We have the target fragment in hand.. Just show it.. Show a standard navigation animation*/
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        ft.replace(R.id.content, fragment);
        ft.commit();
    }
    
    @Override
    public void onBackPressed() {
        if(mStacks.get(mCurrentTab).size() == 1){
            // We are already showing first fragment of current tab, so when back pressed, we will finish this activity..
            finish();
            return;
        }
    
        /* Goto previous fragment in navigation stack of this tab */
        popFragments();
    }
    

    }

    Home fragment example

    public class HomeFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_home, container, false);
        Button gotoNextFragment = (Button) view.findViewById(R.id.gotoHome2);
    
        gotoNextFragment.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ((MainActivity)getActivity()).pushFragments(MainActivity.TAB_HOME, new Home2Fragment(),true);
            }
        });
        return view;
    }
    

    }

提交回复
热议问题