Транзакция между фрагментами только внутри одной вкладки ActionBar - PullRequest
7 голосов
/ 24 октября 2011

У меня есть приложение с тремя вкладками (вкладки ActionBar), каждая с одним фрагментом за раз.

TabListener

TabsActivity

Tab1 -> ListFragment1 ->ListFragment2 -> Fragment3

Tab2 -> Tab2Fragment

Tab3 -> Tab3Fragment

Проблема заключается в том, что я создаю FragmentTransaction (внутри OnListItemClicked) из ListFragment1 в ListFragment2, фрагменты внутридругие вкладки также меняются на ListFragment2.

В конце я хочу изменить фрагменты только внутри вкладки и сохранить состояние других вкладок.

Я уже сохраняю состояние (OnSavedInstance ()).Вы знаете, что мне здесь не хватает?

Какой-то код:

public class TabsActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tabs);

        // setup Action Bar for tabs
        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // instantiate fragment for the tab
        Fragment networksFragment = new NetworksFragment();
        // add a new tab and set its title text and tab listener
        actionBar.addTab(actionBar.newTab().setText("Tab1")
                .setTabListener(new TabsListener(ListFragment1)));

        // instantiate fragment for the tab
        Fragment historyFragment = new HistoryFragment();
        // add a new tab and set its title text and tab listener
        actionBar.addTab(actionBar.newTab().setText("Tab2")
                .setTabListener(new TabsListener(Tab2Fragment)));

        // instantiate fragment for the tab
        Fragment settingsFragment = new SettingsFragment();
        // add a new tab and set its title text and tab listener
        actionBar.addTab(actionBar.newTab().setText("Tab3")
                .setTabListener(new TabsListener(Tab3Fragment)));
    }
}

public class TabsListener implements ActionBar.TabListener {

    private Fragment frag;


    // Called to create an instance of the listener when adding a new tab
    public TabsListener(Fragment networksFragment) {
        frag = networksFragment;
    }

    @Override
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {    
        ft.add(R.id.fragment_container, frag, null);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(frag);        
    }
}

public class ListFragment1 extends ListFragment {

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {

        getListView().setItemChecked(position, true);

        ListFragment2 fragment2 = ListFragment2.newInstance(position);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment_container, fragment2);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.addToBackStack(null);
        ft.commit();
    }
}

1 Ответ

6 голосов
/ 21 декабря 2011

Вы ничего не упускаете (или я тоже это упускаю).

1002 * Я искал долго и упорно способ сделать это «правильно», но я не мог найти ничего.В итоге я написал свою собственную логику бэкстека.К сожалению, мой работодатель владеет моим кодом, поэтому я не могу поделиться ни одним из этих дословных слов, но вот мой подход:

Создайте enum с одной записью для каждой из ваших вкладок.Давайте назовем это TabType.Теперь создайте переменную экземпляра tabStacks типа HashMap<TabType, Stack<String>>.Теперь вы можете создать один стек для каждой вкладки - каждый стек представляет собой список тегов, как указано Fragment.getTag().Таким образом, вам не нужно беспокоиться о хранении ссылок на Fragments и о том, исчезнут ли они на вас при повороте устройства.В любое время, когда вам нужна ссылка на Fragment, возьмите правый тег со стека и используйте FragmentManager.findFragmentByTag().

Теперь, когда вы хотите вставить Fragment на вкладку, сгенерируйте новый тег (Я использовал UUID.randomUUID().toString()) и использовал его в своем звонке на FragmentTransaction.add().Затем нажмите на ярлык в верхней части стека для текущей отображаемой вкладки.

Будьте осторожны: , если вы хотите поместить новый фрагмент поверх старого, не remove() старый, так как FragmentManager будет считать, что он пропал, и он будет очищен.Обязательно detach() это, а затем attach() это позже.Используйте remove(), только когда вы постоянно набираете Fragment, и используйте add() только в первый раз, когда вы хотите его показать.

Затем вам придется добавить относительно простую логику кваш TabListener.Когда вкладка не выбрана, просто peek() в ее стеке и detatch() соответствующий фрагмент.Когда выбрана вкладка, peek() вверху этой стопки и attach() этого фрагмента.

Наконец, вам придется иметь дело с причудами жизненного цикла Activity (например, с изменением ориентации).).Сохраните Map из Stacks, а также текущую выбранную вкладку и снова распакуйте ее в onCreate().(Вы не получаете эту упаковку и распаковку бесплатно, но это довольно легко сделать.) К счастью, ваш TabType enum равен Serializable, поэтому его легко положить в Bundle.

...