Програмно поверніться до попереднього фрагмента в backstack


218

Скажіть, у мене є діяльність, у якій програмно додано фрагменти:

private void animateToFragment(Fragment newFragment, String tag) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.fragment_container, newFragment, tag);
    ft.addToBackStack(null);
    ft.commit();
}

Який найкращий спосіб повернутися до попереднього фрагмента, який було видно?

Я знайшов функцію триггера за допомогою кнопок при натисканні кнопки в Android, але я думаю, що імітувати подію із зворотним ключем - це не правильний шлях для цього (і я також не можу змусити його працювати):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));

Виклик finish()просто закриває діяльність, яка мене не цікавить.

Чи є кращий шлях для цього?

Відповіді:


354

Подивіться на getFragmentManager().popBackStack()методи (їх можна вибрати декілька)

http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack ()


91
getFragmentManager().popBackStackImmediate();зробив трюк. Дякую.
— Aske B.

1
Де я б поклав цей метод? У моєму вкладці слухача?
— rasen58

1
не бачачи коду, важко сказати ... але він повинен пройти в розділі коду, який виконується, коли потрібно "закрити" поточний фрагмент і повернутися до попереднього фрагмента.
— безглуздий

1
як щодо getSupportFragmentManager ()
— ViliusK

5
Не забудьте додати у свій код "addToBackStack (" тег ")". "fragmentManager.beginTransaction (). Замінити (R.id.content_frame, фрагмент) .addToBackStack (" тег "). commit ();" якщо ви пишете addToBackStack (null), він буде обробляти його самостійно, але якщо ви дасте тег, слід обробити його вручну.
— Халед Сайф

129

Щоб детальніше зупинитися на інших наданих відповідях, це моє рішення (розміщене в діяльності):

@Override
public void onBackPressed(){
    FragmentManager fm = getFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        Log.i("MainActivity", "popping backstack");
        fm.popBackStack();
    } else {
        Log.i("MainActivity", "nothing on backstack, calling super");
        super.onBackPressed();  
    }
}

5
і чому це відбувається. У прикладі фрагментів developer.android.com/training/basics/fragments/index.html вони не переважають надподавленою подією, і все ж вони здатні виконати резервний фрагмент. Я використав trasaction.addToBackStack (null); але нічого не відбувається. Чи можете ви пояснити, чому?
— Муртаза Хуршід Хуссей

@MurtazaHussain вам, мабуть, слід задати нове запитання, якщо ви хочете допомогти з цим. Трохи важко зрозуміти, що відбувається, не дивлячись на більше коду.
— Кайл Фальконер

2
У моєму випадку мені довелося це зробити fm.getBackStackEntryCount() > 1, щоб відкликати активність, коли в стеку є лише перший фрагмент.
— Facundo Olano

3
Android вже зробив це для вас: "Коли на задній стеці є об'єкти FragmentTransaction і користувач натискає кнопку" Назад ", FragmentManager виконує останню транзакцію із заднього стека та виконує зворотну дію (наприклад, видалення фрагмента, якщо транзакція додав це). " (Джерело)
— artkoenig

29

Коли ми оновлюємо / додаємо фрагменти,

Потрібно включати .addToBackStack().

getSupportFragmentManager().beginTransaction()
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
    .addToBackStack(null)
    .commit();

Після цього, якщо ми дамо getFragments.popBackStackImmediate()волю, повернеться правдою, якщо ми додамо / оновимо фрагменти, і повернемося до поточного екрану.


7

Додайте ці рядки до методу onBackPress (). метод popBackStackImmediate () поверне вас до попереднього фрагмента, якщо у вас є якийсь фрагмент на задній стек `

if(getFragmentManager().getBackStackEntryCount() > 0){
     getFragmentManager().popBackStackImmediate();
}
else{
    super.onBackPressed();
}

`


5

Це рішення ідеально підходить для навігації по фрагментах на нижній панелі, коли ви хочете закрити додаток при натисканні на спинку в первинному фрагменті.

З іншого боку, коли ви відкриєте вторинний фрагмент (фрагмент у фрагменті), який у моєму коді визначений як "DetailedPizza", він поверне попередній стан первинного фрагмента. Ура!

Внутрішні заходи із натиснутою спиною ставлять так:

Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");

if (home instanceof FragmentDetailedPizza && home.isVisible()) {
    if (getFragmentManager().getBackStackEntryCount() != 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
} else {
    //Primary fragment
    moveTaskToBack(true);
}

І запустіть інший фрагмент на зразок цього:

Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();

3

Ці відповіді не спрацьовують, якщо я не додав addToBackStack () до моєї транзакції з фрагментами, але ви можете використовувати:

getActivity().onBackPressed();

від вашого будь-якого фрагмента повернутися на один крок назад;


1

Програмно поверніться до попереднього фрагмента, використовуючи наступний код.

if ( getFragmentManager().getBackStackEntryCount() > 0) 
{
          getFragmentManager().popBackStack();
          return;
}
super.onBackPressed();

1

Щоб цей фрагмент з’явився знову, просто додайте той фрагмент до заднього кута, який ви хочете, щоб він був натиснутою назад, наприклад:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Fragment fragment = new LoginFragment();
        //replacing the fragment
        if (fragment != null) {
            FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.content_frame, fragment);
            ft.addToBackStack("SignupFragment");
            ft.commit();
        }
    }
});

У наведеному вище випадку я відкриваюсь, LoginFragmentколи Button buttonнатискається, зараз користувач перебуває SignupFragment. Отже, якщо addToBackStack(TAG)викликається, де TAG = "SignupFragment", тоді, коли натиснута кнопка "назад" LoginFragment, ми повертаємось до SignUpFragment.

Щасливе кодування!


Я думаю, TAG не впливає, навіть може бути нульовим.
— CoolMind

1

Додавши fragment_tran.addToBackStack(null)останній фрагмент, я в змозі повернутися до останнього фрагмента.

додавання нового фрагмента :

view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.container, new ChangePassword());
            transaction.addToBackStack(null);
            transaction.commit();
        }
    });

1

Я прийшов сюди, шукаючи таку ж ідею, і тим часом я придумав власну, що, на мою думку, не так вже й погано і працює, якщо з ViewPager.

Отож, що я зробив - це перекрити метод onBackPress у батьківській діяльності, що містить viewPager, і встановити його завжди повертатись до мінус 1 позиції, поки не досягне першого фрагмента, а потім закриє активність.

@Override
public void onBackPressed() {
    if(viewPager.getCurrentItem()>0){
        viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
    } else {
        super.onBackPressed();
        this.close();
    }
}

private void close(){
    this.finish();
}

Це може мати падіння, як-от воно щоразу повертається в один бік, тому воно може не спрацювати, якщо є вкладки і ви перемикаєте позиції з пропущеними фрагментами (від 0 до 2, а потім натискання назад приведе вас до 1, а не 0)

У моєму випадку тхо, з 2 фрагментами в viewPager без вкладок, це робить роботу чудово.


На подібне питання вже відповіли. stackoverflow.com/questions/10863572 / ...
— AtifSayings

0

Спробуйте нижче код:

@Override
    public void onBackPressed() {
        Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
        if (myFragment != null && myFragment instanceof StepOneFragment) {
            finish();
        } else {
            if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                getSupportFragmentManager().popBackStack();
            } else {
                super.onBackPressed();
            }
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.