Fragment re-created on bottom navigation view item selected

后端 未结 15 2544
长发绾君心
长发绾君心 2020-12-07 23:55

Following is my code for bottom navigation view item selected

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationI         


        
相关标签:
15条回答
  • 2020-12-08 00:31

    There are several test cases involved in proper navigation , I am pasting my code with all test cases checked.

    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            switch (item.getItemId()) {
                case R.id.dashboard:
                    Fragment fragment;
                    fragment = fragmentManager.findFragmentByTag(DashboardFragment.TAG);
    
                    if (fragment == null) {
                        fragment = new DashboardFragment();
                        fragmentTransaction.add(R.id.frame, fragment, DashboardFragment.TAG);
                    } else {
                        fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
                        fragmentTransaction.attach(fragment);
                    }
                    fragmentTransaction.setPrimaryNavigationFragment(fragment);
                    fragmentTransaction.commitNow();
                    return true;
                case R.id.expenses:
                    fragment = fragmentManager.findFragmentByTag(ExpenseFragment.TAG);
                    if (fragment == null) {
                        fragment = new ExpenseFragment();
                        fragmentTransaction.add(R.id.frame, fragment, ExpenseFragment.TAG);
                    } else {
                        fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
                        fragmentTransaction.attach(fragment);
                    }
                    fragmentTransaction.setPrimaryNavigationFragment(fragment);
                    fragmentTransaction.commitNow();
                    return true;
                case R.id.vehicle_parts:
                    Bundle bundle = new Bundle();
                    bundle.putInt("odometer", vehicle.getOdometer());
                    bundle.putString("vehicle_id", vehicle.get_id());
                    fragment = fragmentManager.findFragmentByTag(PartsFragment.TAG);
                    if (fragment == null) {
                        fragment = new PartsFragment();
                        fragment.setArguments(bundle);
                        fragmentTransaction.add(R.id.frame, fragment, PartsFragment.TAG);
    
                    } else {
                        fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
                        fragmentTransaction.attach(fragment);
                    }
                    fragmentTransaction.setPrimaryNavigationFragment(fragment);
                    fragmentTransaction.commitNow();
                    return true;
                case R.id.blog:
                    fragment = fragmentManager.findFragmentByTag(BlogFragment.TAG);
    
                    if (fragment == null) {
                        fragment = new BlogFragment();
                        fragmentTransaction.add(R.id.frame, fragment, BlogFragment.TAG);
    
                    } else {
                        fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
                        fragmentTransaction.attach(fragment);
                    }
                    fragmentTransaction.setPrimaryNavigationFragment(fragment);
                    fragmentTransaction.commitNow();
                    return true;
            }
            return false;
    
    0 讨论(0)
  • 2020-12-08 00:32

    I've improved @Viven's answers and written it with Kotlin. My version instantiates fragment only for the first time, hides/shows. I'm new at Kotlin so tell me if I can improve anything.

    We need to hold a id to tag map:

    private val fragmentTags = hashMapOf(
            R.id.action_home to "home_fragment",
            R.id.action_profile to "profile_fragment"
    )
    

    The listener code:

    bottomNavigation.run {
        setOnNavigationItemSelectedListener { menuItem ->
            supportFragmentManager.beginTransaction()
                    .let { transaction ->
                        // hide current fragment
                        supportFragmentManager.primaryNavigationFragment?.let {
                            // if selected fragment's tag is same, do nothing.
                            if (it.tag == fragmentTags[menuItem.itemId]) {
                                return@setOnNavigationItemSelectedListener true
                            }
    
                            transaction.hide(it)
                        }
    
                        var fragment  = supportFragmentManager.findFragmentByTag(fragmentTags[menuItem.itemId])
    
                        if (fragment == null) {
                            // instantiate fragment for the first time
                            fragment = when(menuItem.itemId) {
                                R.id.action_home -> HomeFragment()
                                R.id.action_profile -> ProfileFragment()
                                else -> null
                            }?.also {
                                // and add it 
                                transaction.add(R.id.frame, it, fragmentTags[menuItem.itemId])
                            }
                        } else {
                            // if it's found show it 
                            transaction.show(fragment)
                        }
    
    
                        transaction
                                .setPrimaryNavigationFragment(fragment)
                                .setReorderingAllowed(true)
                    }.commitNowAllowingStateLoss()
    
            return@setOnNavigationItemSelectedListener true
        }
    
        //bottomNavigation things
        itemIconTintList = null
        selectedItemId = R.id.action_home
    }
    
    0 讨论(0)
  • 2020-12-08 00:33

    I solved this problem by adding a ViewPager to which I delegated all my navigation fragments. Its adapter (FragmentPagerAdapter) doesn't recreate the fragments instances when the user navigates through the BotoomNavigationView.

    To achieve this, you have to complete 5 easy steps:

    1. add a ViewPager to your layout;
    2. implement its adapter:

      class YourNavigationViewPagerAdapter(fm: FragmentManager,
                                           private val param1: Int,
                                           private val param2: Int)
      
          : FragmentPagerAdapter(fm) {
      
          override fun getItem(p0: Int) = when(p0) {
              0 -> NavigationFragment1.newInstance(param1, param2)
              1 -> NavigationFragment2.newInstance(param1, param2)
              2 -> NavigationFragment3.newInstance(param1, param2)
              else -> null
          }
      
          override fun getCount() = 3
      }
      
    3. don't forget to set the new adapter:

      yourViewPager.adapter = YourNavigationViewPagerAdapter(supportFragmentManager, param1, param2)
      
    4. set a OnNavigationItemSelectedListener to your BottomNavigationView like the following:

      yourBottomNavigationView.setOnNavigationItemSelectedListener {
      
          when(it.itemId) {
      
              R.id.yourFirstFragmentMenuItem -> {
                  yourViewPager.currentItem = 0
                  true
              }
      
              R.id.yourSecondFragmentMenuItem -> {
                  yourViewPager.currentItem = 1
                  true
              }
      
              R.id.yourThirdFragmentMenuItem -> {
                  yourViewPager.currentItem = 2
                  true
              }
      
      
              else -> false
          }
      }
      
    5. set a OnPageChangeListener to your ViewPager like the following:

      yourViewPager.addOnPageChangeListener(object : 
      ViewPager.OnPageChangeListener {
          override fun onPageScrollStateChanged(p0: Int) {
      
          }
      
          override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {
      
          }
      
          override fun onPageSelected(p0: Int) {
              yourBottomNavigationView.menu.getItem(p0).isChecked = true
          }
      
      })
      
    6. enjoy :)

    0 讨论(0)
  • 2020-12-08 00:34

    setOnNavigationItemReselectedListener would be a better solution for that

    0 讨论(0)
  • 2020-12-08 00:36

    The best way i found to do it.

    private void replace_fragment(Fragment fragment) {
    
            String tag = fragment.getClass().getSimpleName();
            FragmentTransaction tr = getSupportFragmentManager().beginTransaction();
    
            Fragment curFrag = getSupportFragmentManager().getPrimaryNavigationFragment();
            Fragment cacheFrag = getSupportFragmentManager().findFragmentByTag(tag);
    
            if (curFrag != null)
                tr.hide(curFrag);
    
            if (cacheFrag == null) {
                tr.add(R.id.main_frame, fragment, tag);
            } else {
                tr.show(cacheFrag);
                fragment = cacheFrag;
            }
    
            tr.setPrimaryNavigationFragment(fragment);
            tr.commit();
    
        }
    
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
                = new BottomNavigationView.OnNavigationItemSelectedListener() {
    
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    
                switch (item.getItemId()) {
                    case R.id.nav_posts:
                        replace_fragment(new PostsFragment());
                        return true;
                    case R.id.nav_stores:
                        replace_fragment(new StoresFragment());
                        return true;
                    case R.id.nav_chats:
                        replace_fragment(new DiscussionsFragment());
                        return true;
                    case R.id.nav_account:
                        replace_fragment(new ProfileFragment());
                        return true;
                }
                return false;
            }
        };
    
    0 讨论(0)
  • 2020-12-08 00:43

    I faced the same problem and finally i i found the solution, you can try this code. it's work for me.

    import android.support.annotation.NonNull;
    import android.support.design.widget.BottomNavigationView;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.MenuItem;
    import android.widget.FrameLayout;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    public BottomNavigationView bv;
    public home_fragment home;
    public account_fragment afrag;
    public other_fragment other;
    public FrameLayout fr;
    android.support.v4.app.Fragment current;
    //public FragmentTransaction frt;
        public static int temp=0;
        final Fragment fragment11 = new account_fragment();
        final Fragment fragment22 = new home_fragment();
        final Fragment fragment33 = new other_fragment();
        final FragmentManager fm = getSupportFragmentManager();
        Fragment active = fragment11;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            bv=(BottomNavigationView) findViewById(R.id.navigationView);
    
    
            fm.beginTransaction().add(R.id.main_frame, fragment33, "3").hide(fragment33).commit();
            fm.beginTransaction().add(R.id.main_frame, fragment22, "2").hide(fragment22).commit();
            fm.beginTransaction().add(R.id.main_frame,fragment11, "1").commit();
    bv.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.account:
                            fm.beginTransaction().hide(active).show(fragment11).commit();
                            active = fragment11;
                            return true;
    
                        case R.id.home1:
                            fm.beginTransaction().hide(active).show(fragment22).commit();
                            active = fragment22;
                            return true;
    
                        case R.id.other:
                            fm.beginTransaction().hide(active).show(fragment33).commit();
                            active = fragment33;
                            return true;
                    }
                    return false;
                }
            });
          bv.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
              @Override
              public void onNavigationItemReselected(@NonNull MenuItem item) {
                  Toast.makeText(MainActivity.this, "Reselected", Toast.LENGTH_SHORT).show();
    
              }
          });
    
    
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题