Как реализовать onBackPressed() в фрагментах?
Есть ли способ реализовать onBackPressed()
в Android Fragment аналогично тому, как мы реализуем в Android Activity?
Поскольку жизненный цикл фрагмента не имеет onBackPressed()
. Есть ли какой-либо другой альтернативный способ переместить onBackPressed()
в фрагменты Android 3.0?
Ответы
Ответ 1
Я решил таким образом переопределить onBackPressed
в Activity. Все FragmentTransaction
являются addToBackStack
перед коммитом:
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}
}
Ответ 2
Я думаю, что лучшее решение
JAVA SOLUTION
Создать простой интерфейс:
public interface IOnBackPressed {
/**
* If you return true the back press will not be taken into account, otherwise the activity will act naturally
* @return true if your processing has priority if not false
*/
boolean onBackPressed();
}
И в вашей деятельности
public class MyActivity extends Activity {
@Override public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
super.onBackPressed();
}
} ...
}
Наконец в вашем фрагменте:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
КОТЛИН РЕШЕНИЕ
1 - Создать интерфейс
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
2 - Подготовьте свою деятельность
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
3 - Внедрите в свой целевой фрагмент
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
Ответ 3
В соответствии с ответом @HaMMeRed здесь есть псевдокод, как он должен работать.
Допустим, что ваше основное действие называется BaseActivity
, у которого есть дочерние фрагменты (например, в примере SlidingMenu lib).
Вот шаги:
Сначала нам нужно создать интерфейс и класс, который реализует свой интерфейс, чтобы иметь общий метод
-
Создать интерфейс класса OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
-
Создайте класс, который реализует навыки OnBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
@Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
-
С тех пор мы будем работать над нашим кодом BaseActivity
и его фрагментами
-
Создайте собственный слушатель поверх своего класса BaseActivity
protected OnBackPressedListener onBackPressedListener;
-
создать метод для установки слушателя в BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
-
в переопределении onBackPressed
реализовать что-то вроде этого
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
-
в вашем фрагменте в onCreateView
вы должны добавить наш прослушиватель
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
View view = ... ;
//stuff with view
return view;
}
Voila, теперь, когда вы щелкаете назад в фрагменте, вы должны поймать свой обычай по обратному методу.
Ответ 4
Это сработало для меня: fooobar.com/questions/25335/...
@Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button click listener
return true;
}
return false;
}
});
}
Ответ 5
Если вам нужна такая функциональность, вам нужно переопределить ее в своей деятельности, а затем добавить интерфейс YourBackPressed
для всех ваших фрагментов, который вы вызываете для соответствующего фрагмента при каждом нажатии кнопки назад.
Изменение: я хотел бы добавить свой предыдущий ответ.
Если бы я делал это сегодня, я бы использовал трансляцию или, возможно, заказанную трансляцию, если бы ожидал, что другие панели будут обновляться в унисон на панель основного/основного контента.
LocalBroadcastManager
в библиотеке поддержки может помочь в этом, и вы просто отправляете трансляцию в onBackPressed
и подписываетесь на интересующие вас фрагменты. Я думаю, что Messaging является более изолированной реализацией и будет лучше масштабироваться, поэтому сейчас это будет моя официальная рекомендация по внедрению. Просто используйте действие Intent
в качестве фильтра для вашего сообщения. отправьте только что созданный ACTION_BACK_PRESSED
, отправьте его из своей деятельности и прослушайте в соответствующих фрагментах.
Ответ 6
Ничто из этого легко реализовать и не будет функционировать оптимальным образом.
Фрагменты имеют вызов метода onDetach, который выполнит задание.
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
ЭТО БУДЕТ РАБОТАТЬ.
Ответ 7
Просто добавьте addToBackStack
, пока вы переходите между своими фрагментами, как показано ниже:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
если вы пишете addToBackStack(null)
, он будет обрабатывать его сам по себе, но если вы дадите тег, вы должны обработать его вручную.
Ответ 8
так как этот вопрос и некоторые ответы более пяти лет, позвольте мне поделиться своим решением. Это продолжение и модернизация ответа от @oyenigun
UPDATE:
В нижней части этой статьи я добавил альтернативную реализацию, используя абстрактное расширение фрагмента, которое вообще не будет включать Activity, что было бы полезно для людей с более сложной иерархией фрагментов, включающих вложенные фрагменты, которые требуют различного обратного поведения.
Мне нужно было реализовать это, потому что некоторые из фрагментов, которые я использую, имеют меньшие представления, которые я бы хотел убрать с помощью кнопки "Назад" , например, появление небольших информационных просмотров и т.д., но это хорошо для всех, кто должен переопределить поведение обратной кнопки внутри фрагментов.
Сначала определите интерфейс
public interface Backable {
boolean onBackPressed();
}
Этот интерфейс, который я называю Backable
(я сторонник соглашений об именах), имеет единственный метод onBackPressed()
, который должен возвращать значение boolean
. Нам нужно принудительно ввести логическое значение, потому что нам нужно будет знать, нажала ли кнопка "назад" заднее событие. Возврат true
означает, что он имеет, и никаких дальнейших действий не требуется, иначе false
говорит, что действие по умолчанию по-прежнему должно иметь место. Этот интерфейс должен быть собственным файлом (желательно в отдельном пакете с именем interfaces
). Помните, что разделение ваших классов на пакеты является хорошей практикой.
Во-вторых, найдите верхний фрагмент
Я создал метод, который возвращает последний объект Fragment
в обратном стеке. Я использую теги... если вы используете идентификаторы, внесите необходимые изменения. У меня есть этот статический метод в классе утилит, который касается состояний навигации и т.д., Но, конечно, поставьте его там, где он вам больше всего подходит. Для назидания я поместил мой в класс под названием NavUtils
.
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
Убедитесь, что количество обратных стеков больше 0, иначе ArrayOutOfBoundsException
может быть запущено во время выполнения. Если он не больше 0, верните значение null. Мы проверим значение null позже...
В-третьих, реализация в фрагменте
Внедрите интерфейс Backable
в любом фрагменте, где вам необходимо переопределить поведение кнопки "Назад" . Добавьте метод реализации.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
В переопределении onBackPressed()
введите любую логику, в которой вы нуждаетесь. Если вы хотите, чтобы кнопка "назад" на не удаляла задний стек (поведение по умолчанию), верните true, что ваше заднее событие было поглощено. В противном случае верните false.
Наконец, в вашей деятельности...
Переопределите метод onBackPressed()
и добавьте к нему эту логику:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
Мы получаем текущий фрагмент в обратном стеке, затем выполняем нулевую проверку и определяем, реализует ли он наш интерфейс Backable
. Если это так, определите, было ли событие поглощено. Если это так, мы закончили с onBackPressed()
и можем вернуться. В противном случае обработайте его как обычное обратное нажатие и вызовите метод super.
Второй вариант не включать активность
Иногда вы не хотите, чтобы Activity обрабатывала это вообще, и вам нужно обрабатывать его непосредственно внутри фрагмента. Но кто говорит, что не может иметь фрагменты с API обратной печати? Просто добавьте фрагмент в новый класс.
Создайте абстрактный класс, который расширяет фрагмент и реализует интерфейс View.OnKeyListner
...
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
Как вы можете видеть, любой фрагмент, который расширяет BackableFragment
, автоматически захватывает обратные клики с помощью интерфейса View.OnKeyListener
. Просто позвоните абстрактному методу onBackButtonPressed()
из внедренного метода onKey()
, используя стандартную логику, чтобы распознать нажатие кнопки "Назад" . Если вам нужно зарегистрировать ключевые клики, отличные от кнопки "Назад" , просто не забудьте вызвать метод super
при переопределении onKey()
в вашем фрагменте, иначе вы отмените поведение в абстракции.
Прост в использовании, просто расширяйте и реализуйте:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Так как метод onBackButtonPressed()
в суперклассе является абстрактным, после расширения вы должны реализовать onBackButtonPressed()
. Он возвращает void
, потому что ему просто нужно выполнить действие внутри класса фрагмента и не нужно передавать абсорбцию пресса обратно в Activity. Убедитесь, что вы вызываете метод Activity onBackPressed()
, если все, что вы делаете с помощью кнопки "Назад" , не требует обработки, иначе кнопка "Назад" будет отключена... и вы не хочу этого!
ПредостереженияКак вы можете видеть, это устанавливает прослушиватель ключей в корневой вид фрагмента, и нам нужно будет сфокусировать его. Если в фрагменте есть какие-либо редактируемые тексты (или любые другие фокусы), которые расширяют этот класс (или другие внутренние фрагменты или представления, имеющие одинаковую), вам придется обрабатывать их отдельно. Там хорошая статья о расширении EditText, чтобы потерять фокус на обратном нажатии.
Я надеюсь, что кто-то найдет это полезным. Счастливое кодирование.
Ответ 9
Решение прост:
1) Если у вас есть класс базового фрагмента, который все фрагменты расширяются, добавьте в него этот класс, иначе создайте такой класс базового фрагмента
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2) В классе Activity переопределите onBackPressed следующим образом:
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3) В классе "Фрагмент" добавьте требуемый код:
@Override
public void onBackPressed()
{
setUpTitle();
}
Ответ 10
onBackPressed()
вызывает отрыв фрагмента из Activity.
В ответ на @Sterling Diaz я думаю, что он прав. НО какая-то ситуация будет неправильной. (например, поворот экрана)
Итак, я думаю, мы могли бы определить, достигнуть ли isRemoving()
целей.
Вы можете записать его в onDetach()
или onDestroyView()
. Это работа.
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
Ответ 11
Хорошо, я сделал это так, и он работает для меня
Простой интерфейс
FragmentOnBackClickInterface.java
public interface FragmentOnBackClickInterface {
void onClick();
}
Пример реализации
MyFragment.java
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
то просто переопределите onBackPressed в действии
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> frags = getSupportFragmentManager().getFragments();
Fragment lastFrag = getLastNotNull(frags);
//nothing else in back stack || nothing in back stack is instance of our interface
if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
super.onBackPressed();
} else {
((FragmentOnBackClickInterface) lastFrag).onClick();
}
}
private Fragment getLastNotNull(List<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
Ответ 12
Вам следует добавить интерфейс к вашему проекту, как показано ниже:
public interface OnBackPressed {
void onBackPressed();
}
И тогда вы должны реализовать этот интерфейс на своем фрагменте;
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
И вы можете инициировать это событие onBackPressed под вашими действиями в событии onBackPressed, как показано ниже:
public class MainActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
if (currentFragment instanceof OnBackPressed) {
((OnBackPressed) currentFragment).onBackPressed();
}
super.onBackPressed();
}
}
Ответ 13
Если вы используете EventBus, это, вероятно, гораздо более простое решение:
В вашем фрагменте:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
getSupportFragmentManager().popBackStack();
}
и в вашем классе Activity вы можете определить:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
super.onBackPressed();
}
@Override
public void onBackPressed() {
EventBus.getDefault().post(new BackPressedMessage(true));
}
BackPressedMessage.java - это просто объект POJO
Это супер чистое, и нет проблем с интерфейсом/реализацией.
Ответ 14
Это всего лишь небольшой код, который сделает трюк:
getActivity().onBackPressed();
Надеюсь, это поможет кому-то:)
Ответ 15
это мое решение:
в MyActivity.java:
public interface OnBackClickListener {
boolean onBackClick();
}
private OnBackClickListener onBackClickListener;
public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
this.onBackClickListener = onBackClickListener;
}
@Override
public void onBackPressed() {
if (onBackClickListener != null && onBackClickListener.onBackClick()) {
return;
}
super.onBackPressed();
}
и Фрагмент:
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
Ответ 16
Как насчет использования onDestroyView()?
@Override
public void onDestroyView() {
super.onDestroyView();
}
Ответ 17
@Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);
return true;
}
return false;
}
});
}
Ответ 18
Не используйте метод ft.addToBackStack(), чтобы при нажатии кнопки "Назад" ваша деятельность будет завершена.
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Ответ 19
Просто выполните следующие действия:
Всегда добавляя фрагмент,
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
Затем в основном действии переопределите onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
Чтобы обработать кнопку "Назад" в вашем приложении,
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
Что это!
Ответ 20
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
в свой фрагмент добавьте следующее, не забудьте реализовать интерфейс mainacctivity.
public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
@Override
public void doBack() {
//BackPressed in activity will call this;
}
}
Ответ 21
Очень короткий и сладкий ответ:
getActivity().onBackPressed();
Объяснение всего сценария моего дела:
У меня есть FragmentA в MainActivity,
Я открываю FragmentB из FragmentA (FragmentB является дочерним или вложенным фрагментом FragmentA)
Fragment duedateFrag = new FragmentB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();
Теперь, если вы хотите перейти в FragmentA из FragmentB, вы можете просто поместить getActivity().onBackPressed();
в FragmentB.
Ответ 22
В жизненном цикле деятельности всегда обратная кнопка Android обращается к транзакциям FragmentManager, когда мы использовали FragmentActivity или AppCompatActivity.
Чтобы обработать стопку назад, нам не нужно обрабатывать счетчик стоп-кадра или тег что-либо, но мы должны сохранить фокус при добавлении или замене фрагмента. Пожалуйста, найдите следующие фрагменты, чтобы обрабатывать обратные кнопки,
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
}
Здесь я не буду добавлять стопку для моего домашнего фрагмента, потому что это главная страница моего приложения. Если добавить addToBackStack в HomeFragment, то приложение будет ждать, чтобы удалить все frament в acitivity, тогда мы получим пустой экран, поэтому я соблюдаю следующее условие:
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
Теперь вы можете увидеть ранее добавленный фрагмент на acitvity, и приложение выйдет при достижении HomeFragment. вы также можете посмотреть следующие фрагменты.
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
Ответ 23
Согласно примечаниям к выпуску AndroidX, androidx.activity 1.0.0-alpha01
выпущен и представляет ComponentActivity
, новый базовый класс существующих FragmentActivity
и AppCompatActivity
. И этот релиз приносит нам новую функцию:
Теперь вы можете зарегистрировать OnBackPressedCallback
через addOnBackPressedCallback
для получения onBackPressed()
вызовов onBackPressed()
без необходимости переопределять метод в вашей деятельности.
Ответ 24
Вы можете зарегистрировать фрагмент в действии, чтобы справиться с прессой:
interface BackPressRegistrar {
fun registerHandler(handler: BackPressHandler)
fun unregisterHandler(handler: BackPressHandler)
}
interface BackPressHandler {
fun onBackPressed(): Boolean
}
использование:
Во фрагменте:
private val backPressHandler = object : BackPressHandler {
override fun onBackPressed(): Boolean {
showClosingWarning()
return false
}
}
override fun onResume() {
super.onResume()
(activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}
override fun onStop() {
(activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
super.onStop()
}
В деятельности:
class MainActivity : AppCompatActivity(), BackPressRegistrar {
private var registeredHandler: BackPressHandler? = null
override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }
override fun onBackPressed() {
if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
}
}
Ответ 25
Лучшее решение,
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
super.onBackPressed();
finish();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
finish();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
else {
fm.popBackStack();
if (fm.getFragments().size() <= 1) {
finish();
}
return;
}
}
}
}
}
Ответ 26
Это просто, если у вас есть A Activity A, и вы делаете 3 фрагмента, такие как B, C и D. Теперь, если вы находитесь в фрагменте B или C и onBackPressed
, вы хотите каждый раз перемещаться по фрагменту D. просто переопределить метод onBackPressed()
в основном действии A, а также при переходе к любому фрагменту, затем передайте TAG или имя этого фрагмента, с помощью которого вы узнали этот фрагмент в основном действии A.
Я приводил пример того, с помощью которого вы можете легко понять, что....
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();
}
или если вы переходите от фрагмента B к фрагменту C.. и нажимаете назад, вы хотите выйти на фрагмент D... как ниже
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
}
});
Теперь вам нужно просто переопределить метод onBackPressed() в основной активности... как показано ниже.
@Override
public void onBackPressed() {
FragmentManager fragmentManager =getSupportFragmentManager();
if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
Fragment fragment = new D_Fragment();
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
getSupportActionBar().setTitle("D fragment ");
} else {
super.onBackPressed();
}
}
Ответ 27
Я использовал другой подход следующим образом:
- шина событий Otto для связи между Activity и его фрагментами
- Стек в Activity, содержащий пользовательские обратные действия, завернутые в
Runnable
, который определяет вызывающий фрагмент
- Когда в управляющей активности вызывается
onBackPressed
, она выдает самое последнее пользовательское обратное действие и выполняет его Runnable
. Если в стеке ничего нет, по умолчанию super.onBackPressed()
вызывается
Полный подход с примером кода включен здесь в качестве ответа на этот другой вопрос SO.
Ответ 28
Я знаю это слишком поздно, но у меня была такая же проблема на прошлой неделе. Ни один из ответов не помог мне. Затем я играл с кодом, и это сработало, так как я уже добавил фрагменты.
В вашей деятельности установите OnPageChangeListener
для ViewPager
, чтобы вы знали, когда пользователь находится во втором действии. Если он находится во втором действии, сделайте логическое true
следующим образом:
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(0);
mViewPager.addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mSectionsPagerAdapter.instantiateItem(mViewPager, position);
if(position == 1)
inAnalytics = true;
else if(position == 0)
inAnalytics = false;
}
@Override
public void onPageScrolled(int position, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
Теперь проверяем логическое значение, когда нажимаем кнопку "Назад", и устанавливаем текущий элемент в свой первый фрагмент:
@Override
public void onBackPressed() {
if(inAnalytics)
mViewPager.setCurrentItem(0, true);
else
super.onBackPressed();
}
Ответ 29
Фрагмент:
Сделайте BaseFragment, разместив метод:
public boolean onBackPressed();
Активность:
@Override
public void onBackPressed() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (!fragment.isVisible()) continue;
if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
return;
}
}
}
super.onBackPressed();
}
Ваша активность будет выполняться над прикрепленными и видимыми фрагментами и вызовет onBackPressed() для каждого из них и прервется, если один из них вернет "true" (это означает, что он был обработан, поэтому нет дальнейшие действия).
Ответ 30
Хорошо, ребята, я наконец нашел хорошее решение.
В вашей функции onCreate() в вашей работе, в которой ваши фрагменты добавят слушателя с заменой backstack следующим образом:
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
List<Fragment> f = fragmentManager.getFragments();
//List<Fragment> f only returns one value
Fragment frag = f.get(0);
currentFragment = frag.getClass().getSimpleName();
}
});
(Также добавление моего fragmenManager объявляется в действия O Теперь каждый раз, когда вы меняете фрагмент, текущий фрагмент String станет именем текущего фрагмента. Затем в действиях onBackPressed() вы можете управлять действиями вашей кнопки возврата так:
@Override
public void onBackPressed() {
switch (currentFragment) {
case "FragmentOne":
// your code here
return;
case "FragmentTwo":
// your code here
return;
default:
fragmentManager.popBackStack();
// default action for any other fragment (return to previous)
}
}
Я могу подтвердить, что этот метод работает для меня.