Фрагмент повторно создан в нижней части экрана навигации
Ниже приведен мой код для выбранного пункта просмотра нижней навигации
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.action_one:
// Switch to page one
fragment = FragmentA.newInstance();
break;
case R.id.action_two:
// Switch to page two
fragment = FragmentB.newInstance();
break;
case R.id.action_three:
// Switch to page three
fragment = FragmentC.newInstance();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.container,fragment,"TAG").commit();
return true;
}
});
Теперь моя проблема возникает каждый раз, когда фрагмент воссоздается и не хочет, чтобы фрагмент был воссоздан каждый раз, когда я также пытался добавить addToBackStack (null), но в этом случае на кнопке "Назад" продолжает выталкивать фрагменты из стека, t хотите.
Можно ли отобразить фрагменты на нижней навигационной панели без повторного создания фрагмента
Ответы
Ответ 1
С поддержкой библиотеки v26 вы можете сделать это
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
Fragment curFrag = mFragmentManager.getPrimaryNavigationFragment();
if (curFrag != null) {
fragmentTransaction.detach(curFrag);
}
Fragment fragment = mFragmentManager.findFragmentByTag(tag);
if (fragment == null) {
fragment = new YourFragment();
fragmentTransaction.add(container.getId(), fragment, tag);
} else {
fragmentTransaction.attach(fragment);
}
fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.commitNowAllowingStateLoss();
Ответ 2
Будьте внимательны при использовании replace
. Даже если вы предоставляете фрагмент, который уже существует в памяти, replace
перезапустит жизненный цикл фрагмента. Чтобы избежать перезапуска, методы объекта транзакции включают в себя add
, show
и hide
, которые могут быть использованы для отображения правильного фрагмента без перезапуска.
private fun switchFragment(index: Int) {
val transaction = supportFragmentManager.beginTransaction()
val tag = fragments[index].tag
// if the fragment has not yet been added to the container, add it first
if (supportFragmentManager.findFragmentByTag(tag) == null) {
transaction.add(R.id.container, fragments[index], tag)
}
transaction.hide(fragments[navigationBar.currentTabPosition])
transaction.show(fragments[index])
transaction.commit()
}
Ответ 3
Попробуйте следующее:
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
switch (item.getItemId()) {
case R.id.action_one:
// Switch to page one
if (!(currentFragment instanceof FragmentA)) {
fragment = FragmentA.newInstance();
}
break;
case R.id.action_two:
// Switch to page two
if (!(currentFragment instanceof FragmentB)) {
fragment = FragmentB.newInstance();
}
break;
case R.id.action_three:
// Switch to page three
if (!(currentFragment instanceof FragmentC)) {
fragment = FragmentC.newInstance();
}
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "TAG").commit();
return true;
}
});
Это получит текущий фрагмент в container
, и если вы снова нажмете на этот фрагмент, который не будет добавлять фрагмент.
Ответ 4
Я столкнулся с той же проблемой и, наконец, я нашел решение, вы можете попробовать этот код. это работает для меня.
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();
}
});
}
}
Ответ 5
Казалось, это хорошо работает для меня. Вместо того, чтобы прикреплять и отсоединять, я использую show или hide, чтобы поддерживать состояние фрагмента.
public void changeFragment(Fragment fragment, String tagFragmentName) {
FragmentManager mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
Fragment currentFragment = mFragmentManager.getPrimaryNavigationFragment();
if (currentFragment != null) {
fragmentTransaction.hide(currentFragment);
}
Fragment fragmentTemp = mFragmentManager.findFragmentByTag(tagFragmentName);
if (fragmentTemp == null) {
fragmentTemp = fragment;
fragmentTransaction.add(R.id.frame_layout, fragmentTemp, tagFragmentName);
} else {
fragmentTransaction.show(fragmentTemp);
}
fragmentTransaction.setPrimaryNavigationFragment(fragmentTemp);
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.commitNowAllowingStateLoss();
}
Ответ 6
setOnNavigationItemReselectedListener будет лучшим решением для этого
Ответ 7
Используйте setOnNavigationItemReselectedListener следующим образом:
private BottomNavigationView.OnNavigationItemReselectedListener onNavigationItemReselectedListener
= new BottomNavigationView.OnNavigationItemReselectedListener() {
@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
Toast.makeText(MainActivity.this, "Reselected", Toast.LENGTH_SHORT).show();
}
};
и вызовите его, используя:
navigation.setOnNavigationItemReselectedListener(onNavigationItemReselectedListener);
Ответ 8
Я решил эту проблему, добавив ViewPager
которому я делегировал все свои фрагменты навигации. Его адаптер (FragmentPagerAdapter
) не воссоздает экземпляры фрагментов, когда пользователь перемещается через BotoomNavigationView
.
Для этого вам необходимо выполнить 5 простых шагов:
- добавьте
ViewPager
в свой макет; -
реализовать свой адаптер:
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
}
-
не забудьте установить новый адаптер:
yourViewPager.adapter = YourNavigationViewPagerAdapter(supportFragmentManager, param1, param2)
-
установите OnNavigationItemSelectedListener
для вашего BottomNavigationView
следующим образом:
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
}
}
-
установите OnPageChangeListener
для вашего ViewPager
следующим образом:
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
}
})
-
наслаждаться :)
Ответ 9
В правильной навигации участвуют несколько тестовых случаев, я вставляю свой код со всеми проверенными тестами.
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;
Ответ 10
Я улучшил ответы @Viven и написал это с Kotlin. Моя версия создает фрагмент только в первый раз, скрывает/показывает. Я новичок в Котлине, так скажите мне, могу ли я что-то улучшить.
Нам нужно держать идентификатор, чтобы пометить карту:
private val fragmentTags = hashMapOf(
R.id.action_home to "home_fragment",
R.id.action_profile to "profile_fragment"
)
Код слушателя:
bottomNavigation.run {
setOnNavigationItemSelectedListener { menuItem ->
supportFragmentManager.beginTransaction()
.let { transaction ->
// hide current fragment
supportFragmentManager.primaryNavigationFragment?.let {
// if selected fragment tag is same, do nothing.
if (it.tag == fragmentTags[menuItem.itemId]) {
[email protected] 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 found show it
transaction.show(fragment)
}
transaction
.setPrimaryNavigationFragment(fragment)
.setReorderingAllowed(true)
}.commitNowAllowingStateLoss()
[email protected] true
}
//bottomNavigation things
itemIconTintList = null
selectedItemId = R.id.action_home
}
Ответ 11
Я написал функцию расширения в Kotlin для того же.
fun FragmentManager.switch(containerId: Int, newFrag: Fragment, tag: String) {
var current = findFragmentByTag(tag)
beginTransaction()
.apply {
//Hide the current fragment
primaryNavigationFragment?.let { hide(it) }
//Check if current fragment exists in fragmentManager
if (current == null) {
current = newFrag
add(containerId, current!!, tag)
} else {
show(current!!)
}
}
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.setPrimaryNavigationFragment(current)
.setReorderingAllowed(true)
.commitNowAllowingStateLoss()
}
Ответ 12
Ссылка на эту ссылку работает точно! Он заслуживает награды...