2016-01-22 4 views
5

Схема моего приложения для Android-планшета состоит из списка элементов и подробного представления. Когда выбран элемент списка, соответствующий контент отображается в представлении деталей.Как вырезать фрагменты на backstack, которые соответствуют их тегам фрагмента?

+--------+-------------+ 
| Item 1 |    | 
+--------+ Item  | 
| Item 2 | details | 
+--------+    | 
| Item 3 |    | 
+--------+-------------+ 

Подробности просмотра является Fragment который программно раздували в FrameLayout заполнитель:

<FrameLayout 
    android:id="@+id/detail_fragment_placeholder" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

Вот является Fragment операции:

getSupportFragmentManager() 
    .beginTransaction() 
    .replace(containerViewId, fragment, fragmentTag) 
    .addToBackStack(backStackStateName) 
    .commit(); 

Несколько экземпляров [Dx] из DetailsFragment добавлены до упора, когда пользователь выбирает один элемент за другим.

   [D3] 
     [D2] [D2] 
[D1] -> [D1] -> [D1] 

Таким образом, пользователь должен нажать кнопку НАЗАД несколько раз, чтобы совать экземпляры из backstack опустошить детали просмотра.

Как я могу заменить существующий экземпляр [Dx] из DetailsFragment на backstack когда fragmentTag существующего fragment соответствует fragmentTag нового fragment?

[D1] -> [D2] -> [D3] 
+0

Вы хотите заменить только верхний фрагмент, если он имеет то же самое тег или любой фрагмент с тем же тегом в стеке? – Michael

+0

@Michael Если есть группа фрагментов с тем же тегом aka. тот же тип поверх стека Я хочу уменьшить/заменить их одним пропущенным фрагментом. – JJD

+1

Нет простого способа добиться этого. Проверьте этот ответ http://stackoverflow.com/a/22125826/1320616 –

ответ

1

Я не уверен, что правильно понял ваш вопрос. Если вы хотите заменить несколько фрагментов на какой-либо тэг с верхней части backstack одним фрагментом с тем же тегом, вы можете использовать следующий подход.

Вместо того, чтобы использовать теги для идентификации фрагментов, устанавливают разные имена стоп-кадра для фрагментов разных типов. Вы все еще можете использовать тег фрагмента, но это не поможет в решении этой конкретной проблемы. Затем удалите фрагменты из backstack вручную по одному, пока не появится фрагмент с другим именем backstack сверху или без фрагментов.

public void addFragment(final int containerViewId, final Fragment fragment, 
     final String backStackName, final boolean replace) { 
    final FragmentManager fragmentManager = getSupportFragmentManager(); 

    if (replace) { 
     while (fragmentManager.getBackStackEntryCount() > 0) { 
     final int last = fragmentManager.getBackStackEntryCount() - 1; 
     final FragmentManager.BackStackEntry entry = 
      fragmentManager.getBackStackEntryAt(last); 
     if (!TextUtils.equals(entry.getName(), backStackName)) { 
      break; 
     } 

     fragmentManager.popBackStackImmediate(); 
     } 
    } 

    fragmentManager 
     .beginTransaction() 
     .replace(containerViewId, fragment) 
     .addToBackStack(backStackName) 
     .commit(); 
    fragmentManager.executePendingTransactions(); 
    } 

Теперь, если вы сделаете следующие вызовы ваш backstack будет содержать только fragment1 и fragment4.

addFragment(R.id.container, fragment1, "D2", false); 
addFragment(R.id.container, fragment2, "D1", false); 
addFragment(R.id.container, fragment3, "D1", false); 
addFragment(R.id.container, fragment4, "D1", true); 

UPDATE:

В данном конкретном случае следующий код был достаточно:

getSupportFragmentManager().popBackStack(
    backStackStateName, FragmentManager.POP_BACK_STACK_INCLUSIVE); 
getSupportFragmentManager() 
    .beginTransaction() 
    .replace(containerViewId, fragment, fragmentTag) 
    .addToBackStack(backStackStateName) 
    .commit(); 

https://github.com/tuxmobil/CampFahrplan/pull/148

+0

Спасибо за подход. Тем не менее, это не работает для меня: нажмите на пункт 1 - показана деталь 1, нажмите на элемент 2 - подробные представления ** пусты **. Обратите внимание, что вы можете [проверить патч самостоятельно] (http://stackoverflow.com/questions/34953590/how-to-squash-fragments-on-the-backstack-which-match-by-their-fragment-tag? noredirect = 1 # comment57733286_34953991). - Также, почему вы заканчиваете с 'executePendingTransactions()'? – JJD

+1

Образец кода ответа отлично работает, но вы просто использовали его неправильно. Вызовите 'sidePane.setVisibility (View.VISIBLE);' после появления фрагментов из backstack, непосредственно перед началом транзакции. 'executePendingTransactions()' необходимо избегать условий гонки при появлении и нажатии фрагментов. Мы поп-фрагменты синхронно, поэтому нам нужно также синхронно нажимать их. – Michael

+0

Интересно. Я также выпустил решение Daniel Nugent 2., если я добавлю 'sidePane.setVisibility (View.VISIBLE);'. Есть ли особая причина, по которой вы предлагаете переключать видимость после появления фрагментов/перед началом транзакции? Он также работал, когда я называю это после завершения всех транзакций. – JJD

1

Вы можете использовать теги и обрабатывать его в onBackPressed(), но я думаю, что это будет чистое решение, чтобы справиться с этим при построении стека обратно. Селективно добавьте в задний стек для каждого FragmentTransaction и добавьте только в задний стек, если это первый экземпляр DetailFragment.

Вот простой пример, который предотвращает данного фрагмента от добавления в стек обратно два раза подряд:

public void replaceFragment(Fragment frag) { 
    FragmentManager fm = getSupportFragmentManager(); 

    if (fm != null){ 
     FragmentTransaction t = fm.beginTransaction(); 
     //you could also use containerViewId in place of R.id.detail_fragment_placeholder 
     Fragment currentFrag = fm.findFragmentById(R.id.detail_fragment_placeholder); 
     if (currentFrag != null && currentFrag.getClass().equals(frag.getClass())) { 
      t.replace(R.id.detail_fragment_placeholder, frag).commit(); 
     } else { 
      t.replace(R.id.detail_fragment_placeholder, frag).addToBackStack(null).commit(); 
     } 
    } 
} 
+0

Соответствует ли ваш 'content_frame' свой« detail_fragment_placeholder »- если это так, обновите фрагмент кода, чтобы его было легче понять. Означает ли ваше решение, что ** один или более ** экземпляров класса DetailFragment представляются как ** один ** стоп-запись - как в 'n: 1'? – JJD

+0

@jjd да, content_frame соответствует вашему идентификатору detail_fragment_placeholder, и вы можете просто использовать containerViewId, как сейчас. Я обновлю ответ! Что касается того, как он работает, он добавляет только первый фрагмент того же типа в заднюю часть, поэтому теперь важно, сколько уровней вы будете вдаваться с DetailsFragments, если вы отпустите назад, вы вернетесь на верхний уровень, прежде чем перейти к DetailsFragment для первый раз. –

+0

Ни один из обоих подходов не делает именно то, что я хочу. Ваш 1-й подход - щелкните по пункту 1 - показана деталь 1, нажмите на пункт 2 - будет показана деталь 2, нажмите «BACK *» - деталь 2 все еще отображается, нажмите «BACK *» - приложение переходит в фоновый режим. --- Ваш второй подход: щелкните по элементу 1 - показана деталь 1, нажмите на элемент 2 - детализированные представления пустые. – JJD

0

Просто найти фрагмент на backstack и заменить его:

Fragment fragment = getSupportFragmentManager().findFragmentByTag("your tag"); 
FragmentTransaction transaction = fm.beginTransaction(); 
transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getName()); 
transaction.addToBackStack("your tag"); 
transaction.commit(); 

И в вашем событии OnClick проверьте, не совпадает ли позиция элемента с текущим элементом, который уже отображается. Если это так, ничего не делайте.

+0

Вы ответили тем же фрагментом кода, который вы можете найти в моем вопросе. Более того, я не нажимаю тот же элемент, но каждый элемент связан с экземпляром класса 'DetailsFragment'. – JJD

+0

Возможно, я не понял ваш вопрос. Была ли ваша проблема не извлекать определенный фрагмент из задней части стола? – gilgil28

+0

Проблема заключается в том, что «пользователю необходимо несколько раз нажимать кнопку * BACK *». – JJD