Android Honeycomb: как изменить фрагменты в FrameLayout, не создавая их заново? - PullRequest
14 голосов
/ 31 мая 2011

возможно ли переключаться между фрагментами, не создавая их постоянно?Если да, то как?

В документации я нашел пример замены фрагментов.

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

Но я не хочу создавать свои фрагменты с нуля каждый раз, когда они мне нужны.

Я также нашел этот пример сокрытия / показа фрагментов:

// The content view embeds two fragments; now retrieve them and attach
// their "hide" button.
FragmentManager fm = getFragmentManager();
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1));
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2));

Но как мне создать фрагмент с идентификатором вне XML-файла?

Я думаю, это может быть связано с этим вопросом , но ответа нет.: /

Большое спасибо заранее, медуза

Редактировать:

Вот как я это делаю сейчас:

Fragment shown = fragmentManager.findFragmentByTag(shownFragment);

//...

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);

//switch statetement for menu selection, just one example:

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET);
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show();
if (set == null)
{
        set = new SettingsFragment();
        fragmentTransaction.add(R.id.framelayout_content, set, SET);
}
else fragmentTransaction.show(set);
shownFragment = SET;
fragmentTransaction.commit();

Если я вызову настройки, затем что-то еще, а затем вернусь к настройкам, тост сначала выдаст мне «null», а затем «Settings: SettingsFragment {40ef ...».

, если я заменяю fragmentTransaction.add(R.id.framelayout_content, set, SET); на fragmentTransaction.replace(R.id.framelayout_content, set, SET);, я получаю «null», «null», «null» ... так что кажется, что фрагмент не найден по тегу.

Edit2:

Добавление fragmentTransaction.addToBackStack(null); добилось цели.:) Это позволяет полностью спрятать / запомнить, какой фрагмент отображается как часть, поэтому я полагаю, что это наиболее элегантное решение для этого.

Я нашел этот учебник весьма полезным по теме.

Edit3:

Глядя на свой код, я понял, что могу избавиться от некоторых частей, поэтому я изменил его на:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);
Settings set = (Settings) fragmentManager.findFragmentByTag(SET);
if (set == null) set = new Settings();

fragmentTransaction.replace(R.id.framelayout_content, set, SET);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Однако это вызвалоIllegalStateException: Fragment already added, почти так же, как здесь .Есть ли простой способ предотвратить это?В противном случае я думаю, что мог бы вернуться к биту скрытия / показа.

Ответы [ 4 ]

5 голосов
/ 01 июня 2011

Это может зависеть от того, что вы пытаетесь избежать повторного создания.

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

В вашем примере, например, когда вы нажмете кнопку возврата из вашего нового фрагмента, будет показан предыдущий фрагмент (выполучите onCreateView, onActivityCreated, но не onCreate), чтобы фрагмент не создавался как таковой.Что касается вашего нового фрагмента, вы все равно можете сохранить его, если планируете использовать его снова, обновляя любое внутреннее состояние, как требуется, например, в onCreate или onActivityCreated.

РЕДАКТИРОВАТЬ:

Еслиу вас просто есть список меню, в котором каждая запись вызывает отдельный фрагмент в правой панели, тогда добавление в задний стек - это не то, что вам нужно.Для этого вам может потребоваться вызвать add(...) для каждого фрагмента заранее и просто скрыть / показать каждый фрагмент по мере необходимости (я не проверял это).В противном случае я бы предложил сохранить ссылку на каждый фрагмент, позвонив по номеру replace(...), чтобы выбрать другой пункт меню, чтобы гарантировать, что вы не добавите в задний стек.

4 голосов
/ 08 июня 2011

Чтобы избежать

IllegalStateException: фрагмент уже добавлен

Я нашел обходной путь, который мне подходит: используйте remove(AFrag) и add(BFrag) в своемтранзакция, вместо replace().

Похоже, что это ошибка: 4-й комментарий в принятом ответе .

1 голос
/ 04 июня 2012
fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK);

, если вы добавите. setTransition.exit transit_exit_mask, тогда предыдущие виды не придут

0 голосов
/ 31 мая 2011

Я нашел способ, используя функцию "tag":

//...
fragmentTransaction.add(R.id.framelayout_content, fragment1, "foo");
fragmentTransaction.add(R.id.framelayout_content, fragment2, "bar");

//...

fragmentManager.findFragmentByTag("foo");
fragmentManager.findFragmentByTag("bar");

Однако, похоже, это работает немного асинхронно.Вызов findFragmentByTag сразу после commit вернет null.Только позже, в моем случае в событии OnOptionsItemSelected были найдены фрагменты.

Также есть функция с именем findFragmentById(int), но она не очень полезна.Идентификатор, если он не указан в макете XML, совпадает с идентификатором контейнера, поэтому в данном случае R.id.framelayout_content.Если позже вы вызовете функцию с этим идентификатором, вы сможете получить доступ только к одному из прикрепленных фрагментов.(Я думаю, что это последний, но не проверил. Хотя, кажется, он всегда один и тот же.)

Я не сразу нашел способ найти «активный» фрагментиз моего FrameLayout, так что я думаю, что я собираюсь где-то сохранить тег последнего показанного фрагмента.

...