В Android 4.2 библиотека поддержки получила поддержку вложенных фрагментов, см. Здесь . Я поигрался с ним и обнаружил интересное поведение / ошибку в отношении заднего стека и getChildFragmentManager () . При использовании getChildFragmentManager () и addToBackStack (String name) при нажатии кнопки возврата система не спускается по стеку назад к предыдущему фрагменту. С другой стороны, при использовании getFragmentManager () и addToBackStack (String name) при нажатии кнопки возврата система возвращается к предыдущему фрагменту.
Для меня такое поведение неожиданно. Нажав кнопку «Назад» на моем устройстве, я ожидаю, что последний добавленный фрагмент в задний стек будет извлечен, даже если фрагмент был добавлен в задний стек в диспетчере дочерних фрагментов.
Это правильное поведение? Это ошибка? Есть ли способ решить эту проблему?
пример кода с getChildFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
пример кода с getFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Ответы:
Это решение может быть лучшей версией ответа @Sean:
Опять же, я подготовил это решение на основе ответа @Sean выше.
Как сказал @ AZ13, это решение возможно только в ситуациях дочерних фрагментов одного уровня. В случае с многоуровневыми фрагментами работы становятся немного сложными, поэтому я рекомендую попробовать это решение только в том возможном случае, который я сказал. знак равно
Примечание. Поскольку
getFragments
метод теперь является частным, это решение не сработает. Вы можете проверить комментарии по ссылке, которая предлагает решение этой ситуации.источник
getFragments
теперь публично.Похоже на ошибку. Взгляните на: http://code.google.com/p/android/issues/detail?id=40323
Для обходного пути я успешно использовал (как было предложено в комментариях):
источник
Настоящий ответ на этот вопрос находится в функции транзакции фрагмента, называемой setPrimaryNavigationFragment.
Вы должны установить эту функцию для исходного родительского фрагмента, когда активность добавляет его. У меня есть функция replaceFragment внутри моей активности, которая выглядит так:
Это дает вам такое же поведение, как если бы вы возвращались с обычного фрагмента B обратно на фрагмент A, за исключением того, что теперь это происходит и с дочерними фрагментами!
источник
Это решение может быть лучшей версией ответа @ismailarilik:
Версия вложенного фрагмента
источник
SupportFragmentManager
а вместо негоFragmentManager
?С этим ответом он будет обрабатывать рекурсивную обратную проверку и давать каждому фрагменту возможность переопределить поведение по умолчанию. Это означает, что у вас может быть фрагмент, на котором размещен ViewPager, что-то особенное, например, прокрутка к странице, которая используется в качестве заднего стека, или прокрутка до домашней страницы, а затем при следующем обратном нажатии на выход.
Добавьте это в свою Activity, которая расширяет AppCompatActivity.
Добавьте это в свой BaseFragment или в класс, от которого вы можете унаследовать все свои фрагменты.
источник
Этот код будет перемещаться по дереву менеджеров фрагментов и возвращать последний из добавленных фрагментов, в котором есть фрагменты, которые он может выскочить из стека:
Вызов метода:
источник
Причина в том, что ваше действие происходит от FragmentActivity, который обрабатывает нажатие клавиши BACK (см. Строку 173 FragmentActivity .
В нашем приложении я использую ViewPager (с фрагментами), и каждый фрагмент может иметь вложенные фрагменты. Я справился с этим следующим образом:
void onBackKeyPressed()
Также обратите внимание, что я использую
getChildFragmentManager()
в фрагментах для правильного размещения фрагментов. Вы можете увидеть обсуждение и объяснение в этом посте разработчиков Android .источник
если вы используете фрагмент во фрагменте, используйте
getChildFragmentManager()
если вы используете дочерний фрагмент и замените его, используйте
getParentFragmentManager()
если оба не работают, попробуйте это
getActivity().getSupportFragmentManager()
источник
Я смог обработать фрагмент обратного стека, добавив к родительскому фрагменту этот метод в методе onCreate View () и передав корневое представление.
Метод isEnableFragmentBackStack () - это логический флаг, позволяющий узнать, когда я нахожусь на основном или следующем фрагменте.
Убедитесь, что при фиксации фрагмента, который должен иметь стек, вы должны добавить метод addToBackstack.
источник
Это решение может быть лучше, поскольку оно проверяет все уровни вложенных фрагментов:
в своей деятельности
onBackPressed
вы можете просто назвать это так:источник
Спасибо всем за помощь, у меня работает эта (измененная версия):
ПРИМЕЧАНИЕ. Возможно, вы также захотите установить цвет фона этих вложенных фрагментов в соответствии с цветом фона окна темы приложения, поскольку по умолчанию они прозрачны. В некоторой степени выходит за рамки этого вопроса, но это достигается путем разрешения атрибута android.R.attr.windowBackground и установки фона представления фрагмента на этот идентификатор ресурса.
источник
Более 5 лет и этот вопрос по-прежнему актуален. Если вы не хотите использовать fragmentManager.getFragments () из-за его ограничений. Расширьте и используйте следующие классы:
NestedFragmentActivity.java
NestedFragment.java
Объяснение:
Каждое действие и фрагмент, расширенный из вышеупомянутых классов, управляет своим собственным обратным стеком для каждого из своих дочерних элементов, дочерних элементов детей и т. Д. Backstack - это просто запись тегов / идентификаторов «активного фрагмента». Поэтому предостережение - всегда предоставлять тег и / или идентификатор для вашего фрагмента.
При добавлении в backstack в childFragmentManager вам также потребуется вызвать addToParentBackStack (). Это гарантирует, что тег / идентификатор фрагмента будет добавлен в родительский фрагмент / действие для последующих всплывающих окон.
Пример:
источник
Я реализовал это правильно, если до сих пор никто не нашел ответа
просто добавьте этот метод в дочерний вложенный фрагмент
источник
Я решил эту проблему, сохранив текущий открытый фрагмент в свойстве активности. Затем я переопределяю метод
Вот как я добавляю дочерний фрагмент в текущий открытый фрагмент из самого себя.
Это xml-макет родительского фрагмента и добавленного фрагмента
источник
После наблюдения за некоторыми решениями, представленными здесь, я обнаружил, что для обеспечения гибкости и контроля для родительского фрагмента относительно того, когда он выталкивает стек или когда обратное действие должно игнорироваться им, я предпочитаю использовать такую реализацию:
Определение интерфейса «ParentFragment»:
}
Переопределение onBackPressed в родительском действии (или в BaseActivity):
А затем разрешите родительскому фрагменту обрабатывать его так, как он хочет, например:
Это позволяет не думать, что есть какой-то законный дочерний фрагмент, который нужно удалить, например, при использовании пейджера просмотра (и количество записей в обратном стеке> 0).
источник
Если у вас есть
DialogFragment
вложенные фрагменты, «обходной путь» будет немного другим. Вместо того, чтобы устанавливатьonKeyListener
дляrootView
, вам нужно сделать это с помощьюDialog
. Также вы будете настраивать a,DialogInterface.OnKeyListener
а неView
тот. Конечно, помнитеaddToBackStack
!Вот что вам нужно сделать в onCreateDialog
источник
Dialog
(неDialogFragment
), и слушатель, который вы используете, естьDialogInterface.OnKeyListener
- код работает и завершен (и используется). Почему бы вам не рассказать о своей ситуации, и, возможно, я смогу помочь.для ChildFragments это работает ..
источник