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

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

Jabeer
источник
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 без вкладок, он прекрасно справляется со своей задачей.

Grzesiek Eman
источник
На подобный вопрос уже дан ответ. 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();
            }
        }
    }
Адарш
источник