Following is my code for bottom navigation view item selected
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationI
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;
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
}
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:
ViewPager
to your layout;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
}
don't forget to set the new adapter:
yourViewPager.adapter = YourNavigationViewPagerAdapter(supportFragmentManager, param1, param2)
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
}
}
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
}
})
enjoy :)
setOnNavigationItemReselectedListener would be a better solution for that
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;
}
};
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();
}
});
}
}