PopBackStack, но оставить первый фрагмент в Android
Я работаю над транзакцией фрагмента, и backstack выглядит так:
fragA => fragB => fragC => fragD
Я хотел бы вернуться к fragA после возвращения из fragD
fragD => onBackPress => fragA
Итак, я попробовал код как:
getChildFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
но он очищает весь backstack, как я могу сохранить первый фрагмент в backstack? большое спасибо
6 ответов
Например, вы можете сделать следующее:
- добавить fragA без добавления его в backStack. Так всегда будет в
активность, и не будет реагировать на кнопку назад. - когда вы открываете fragD, вы должны очистить фрагмент BackStack. Поэтому, когда вы нажимаете кнопку "Назад" от D frag, вы возвращаетесь к A.
PS Есть и другие способы, как делать то, что вы хотите. Это зависит...
Поскольку "задний стек" имеет поведение, похожее на стек... последний вошел, первым вышел... последний фрагмент, который вы добавили в задний стек, будет извлечен из заднего стека первым. Вам нужно будет реализовать требуемое поведение вручную, указав собственное. Это не так сложно, используя FragmentManager
методы класса.
Если вы "помечаете" свои фрагменты при добавлении их в транзакцию...
fragmentTransaction.add(new FragmentA(), "FragmentA_Tag");
позже вы можете определить, какой фрагмент показывать при нажатии кнопки "Назад"...
FragmentA f = fragmentManager.findFragmentByTag("FragmentA_Tag");
if(f != null){
f.show();
}
Как вы определяете, какой фрагмент показывать, полностью зависит от вас. Вы можете отслеживать текущий видимый фрагмент или вы можете использовать isHidden
метод Fragment
класс... Кстати, я говорю о нативных фрагментах здесь, а не о поддержке фрагмента библиотеки.
Backstack содержит записи о транзакциях, а не сами фрагменты. Поэтому вам не следует добавлять запись первой транзакции (null -> fragA) в backstack. И все остальные записи транзакции должны быть добавлены в backstack. В этом случае, то вы преформыpopBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Android удалил все фрагменты, кроме fragA, потому что нет никаких записей о том, как был добавлен fragA.
Всего несколько дней назад я начал изучать фрагменты в Android. И я тоже столкнулся с этой проблемой. Здесь я показываю свое решение и как я это решаю. Пожалуйста, исправьте, если мой код неверен. Что мы имеем в это время? Активность, множество фрагментов и их отступление. Мы хотим открыть каждый фрагмент из меню Drawer и очистить все остальные фрагменты из backstack. Но мы должны держать только один фрагмент дома. Когда мы остаемся на фрагменте Home и пользователь нажимает кнопку "Назад", приложение закрывается.
Activity.class
protected void onCreate(Bundle savedInstanceState)
{
...
// adding Home fragment without adding transaction into backstack
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, HomeFragment.newInstance("args"), null);
ft.commit();
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
finish();
}
}
public void addFragmentFromMenu(Fragment fragment){
String backStateName = fragment.getClass().getName();
clearBackStack();
FragmentManager manager = getSupportFragmentManager();
if(manager.getBackStackEntryCount()> 0)
{
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
//fragment not in back stack, create it.
addFragment(fragment, manager, backStateName);
}
}
else // no fragments
{
addFragment(fragment, manager, backStateName);
}
}
public void addFragment(Fragment fragment, FragmentManager manager, String backStateName)
{
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, fragment, backStateName);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
public void clearBackStack() {
getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
И при нажатии на элемент меню ящика
@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_camera) {
addFragmentFromMenu(CameraFragment.newInstance("cam1", "cam2"));
} else if (id == R.id.nav_gallery) {
addFragmentFromMenu(TestFragment.newInstance("test1","test2"));
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Просмотрев много сообщений, я понял это так:
в методе fragC => fragD выполните две транзакции:
1 очистить обратные стеки, fragC => fragA
2 fragA => fragD
Но таким образом исходное состояние fragA может быть уничтожено.
public static void changeFragCtoD(FragmentManager fm, Fragment fragD){
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction
.replace(R.id.containerViewId, new fragAClass())
.commit();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction
.replace(R.id.containerViewId, fragD)
.addToBackStack(fragD.getClass().getName())
.commit();
}
Теперь нажатие на fragD возвращает к fragA.
Я сделал следующим образом. Очистить весь фрагмент, затем добавить первый домашний фрагмент
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack(Constants.TAG_HOME, FragmentManager.POP_BACK_STACK_INCLUSIVE);
((MainActivity) activity).manageFragment(new HomeFragment(), Constants.TAG_HOME);
// write down below function in main activity
public void manageFragment(Fragment fragment, String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
if (!fragmentManager.popBackStackImmediate(tag, 0)) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
}
}
Отметьте мои слова, завершите FragmentTransaction
s добавляются в backstack, а не просто фрагмент, это означает, что даже если вы добавляете и удаляете фрагмент за один вызов транзакции poBackStack()
отменит полную транзакцию. Передача тега в его аргументе выводит всю транзакцию до отмеченной транзакции или даже выводит отмеченную транзакцию (в случаеFragmentManager.POP_BACK_STACK_INCLUSIVE
добавлен к аргументу) Так что больше о том, как вы его добавили, а не о том, как вы его удалили. См. Выполнение транзакций фрагмента
Я знаю, что слишком поздно отвечать на ваш вопрос, но это может быть полезно другим людям. Поскольку я искал решение в течение последних нескольких дней... Я решил это с помощью цикла for, и я думаю, что это самый простой из возможных способов.
Сначала инициализируйте целое число таким образом
int count = getSupportFragmentManager().getBackStackEntryCount();
где getBackStackEntryCount() подсчитает количество транзакций.
А затем непосредственно перед вызовом метода FragmentTransaction в вашем fragD добавьте этот цикл for
for (int i = 0; i < count; i++){
getSupportFragmentManager().popBackStack();
}
цикл for сделает свое дело за вас, а popBackStack() вернет вас к fragA
это выглядит так
int count = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < count; i++){
getSupportFragmentManager().popBackStack();
}
fragmentTransaction.replace(R.id.frame_layout, new FoodFragment(), "Food").addToBackStack(null);
fragmentTransaction.commit();
1) Добавьте первый фрагмент, используя код ниже
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null) {
ft.hide(fm.findFragmentById(R.id.fragment_container));
}
ft.add(R.id.fragment_container, new OneFragment(),OneFragment.class.getCanonicalName())
.addToBackStack(OneFragment.class.getCanonicalName()).commit();
2) Добавить второй фрагмент из первого фрагмента, используя приведенный ниже код
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null) {
ft.hide(fm.findFragmentById(R.id.fragment_container));
}
ft.add(R.id.fragment_container,new TwoFragment(),TwoFragment.class.getCanonicalName())
.addToBackStack(TwoFragment.class.getCanonicalName()).commit();
3) Добавьте третий фрагмент из второго фрагмента, используя код ниже
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null) {
ft.hide(fm.findFragmentById(R.id.fragment_container));
}
ft.add(R.id.fragment_container, new ThreeFragment(),ThreeFragment.class.getCanonicalName())
.addToBackStack(ThreeFragment.class.getCanonicalName()).commit();
4) Добавьте четвертый фрагмент из третьего фрагмента, используя приведенный ниже код
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null) {
ft.hide(fm.findFragmentById(R.id.fragment_container));
}
ft.add(R.id.fragment_container, new FourFragment(),ThreeFragment.class.getCanonicalName())
.addToBackStack(FourFragment.class.getCanonicalName()).commit();
5) onBackPressed(), пожалуйста, напишите ниже код
@Override
public void onBackPressed() {
hideKeyboard(MainActivity.this);
Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (currentFragment.getClass().getName().equalsIgnoreCase(FourFragment.class.getName())) { // Using this code come from third fragment to first fragment
Fragment f = this.getSupportFragmentManager().findFragmentByTag(TwoFragment.class.getCanonicalName());
if (f != null) {
this.getSupportFragmentManager().popBackStackImmediate(f.getClass().getCanonicalName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}else {
super.onBackPressed();
}
}
Вы переопределяете onbackpressed (Mainactivity) и используя getBackStackEntryCount() диспетчера фрагментов, вы можете проверить, не равно ли оно 1 и popbackstack только для этого условия.
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
if (!(getSupportFragmentManager().getBackStackEntryCount() == 1)) {
getSupportFragmentManager().popBackStack() ;
}
}
}