Программно вернуться к предыдущему фрагменту в 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();
}

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

Я обнаружил, что функциональность Trigger back-button при нажатии кнопки в Android, но я думаю, что имитация события back back не является правильным способом (и я тоже не могу заставить его работать):

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();сделал свое дело. Спасибо.
— Аске Б.

1
Где бы я положил этот метод, хотя? В моей вкладке слушатель?
— rasen58

1
не видя код, трудно сказать ... но он должен идти в разделе кода, который выполняется, когда вы хотите «закрыть» текущий фрагмент и вернуться к предыдущему фрагменту.
— застрял

1
как насчет getSupportFragmentManager ()
— ViliusK

5
Не забудьте добавить «addToBackStack (« tag »)» в ваш код. "fragmentManager.beginTransaction () заменить (R.id.content_frame, фрагмент) .addToBackStack (" метки ") совершить ();" . если вы напишите 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 они не перезаписывают событие onbackpressed, и, тем не менее, они могут сделать фрагмент обратно. Я использовал trasaction.addToBackStack (null); но ничего не происходит Вы можете объяснить, почему?
— Муртаза Хуршид Хуссейн

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

2
В моем случае я должен был сделать это fm.getBackStackEntryCount() > 1, чтобы отозвать действие, когда в стеке есть только первый фрагмент.
— Факундо Олано

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(), вернется true, если мы добавим / обновим фрагменты и вернемся к текущему экрану.


7

Добавьте эти строки в ваш метод onBackPressed (). Метод popBackStackImmediate () вернет вас к предыдущему фрагменту, если у вас есть какой-либо фрагмент в заднем стеке `

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

`


5

Это решение отлично работает для навигации по фрагментам в нижней строке, когда вы хотите закрыть приложение при обратном нажатии в основном фрагменте.

С другой стороны, когда вы открываете вторичный фрагмент (фрагмент во фрагменте), который в моем коде определен как «DetailPizza», он вернет предыдущее состояние первичного фрагмента. Ура!

Внутри деятельности на спине нажми поставь вот это:

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();

4

Эти ответы не работают, если у меня нет addToBackStack (), добавленной к моей транзакции фрагмента, но вы можете использовать:

getActivity().onBackPressed();

от любого вашего фрагмента, чтобы вернуться на один шаг назад;


1

Программно вернуться к предыдущему фрагменту, используя следующий код.

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

1

Чтобы сделать этот фрагмент снова, просто добавьте этот фрагмент в backstack, который вы хотите вернуть обратно нажатием, например:

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.

Итак, что я сделал, это переопределил метод onBackPressed в родительском действии, которое содержит 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)

В моем случае, с двумя фрагментами в 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.