Замена TabActivity на FragmentActivity и фрагменты

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

Я хочу поместить FragmentActivities для каждой вкладки. Потому что в моем приложении я буду использовать 4 вкладки, и на каждой из вкладок будет действительно сложный контент. В результате мне нужно иметь FragmentActivity для каждой вкладки, чтобы управлять фрагментами, которые я буду помещать на каждую вкладку в отдельном контейнере.

РЕШЕНИЕ:

После ответов и поиска в Интернете я нашел решение. В соответствии с решением, которое я нашел, я отслеживаю фрагменты в отдельном стеке для каждой вкладки на хосте вкладок. Вот мой репозиторий на GitHub, я создал небольшой пример приложения для этой задачи.


person osayilgan    schedule 10.09.2012    source источник


Ответы (2)


Поскольку TabActivity устарела, мне нужно найти способ сделать это с помощью фрагментов.

Если вы не хотите использовать TabActivity - забудьте о том, чтобы вставлять FragmentActivities в содержимое вкладки.

Напоминаю, что можно использовать TabWidget без TabActivity. Итак, вы можете попробовать это решение:

  1. Создайте только один файл FragmentActivity.
  2. Поместите TabWidget в макет FragmentActivity. Сделайте высоту содержимого TabWidget = 0.
  3. Под TabWidget в XML объявите контейнер для вас Fragments (например, FrameLayout).
  4. В FragmentActivity просто укажите, какая вкладка выбрана (TabHost.OnTabChangeListener), и поместите нужную Fragment в контейнер.
  5. Поместите логику программы (которая была ранее в разных действиях) в разные фрагменты.

Или вы можете создать FragmentActivity с TabWidget, и вместо переключения Fragment вы можете напрямую поместить Fragment в содержимое каждой вкладки.

Например, если у вас есть 3 вкладки и 3 фрагмента, попробуйте то, что я делаю. Вызовите showFragmentX, когда вам нужно изменить один фрагмент на другой.

public class Test extends FragmentActivity {

private Fragment1 fragment1=new Fragment1();
private Fragment2 fragment2=new Fragment2();
private Fragment3 fragment3=new Fragment3();

private void showFragment1(){
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.fragments_container, fragment1);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.commit();
}

private void showFragment2(){
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.fragments_container, fragment2);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.commit();
}

private void showFragment3(){
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.fragments_container, fragment3);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    ft.commit();
}

@Override
protected void onCreate(Bundle arg0) {
    // TODO Auto-generated method stub
    super.onCreate(arg0);
    setContentView(R.layout.fragmentactivity_layout);
}
}

Если вы сделаете это, ваши переменные fragmentX не будут удаляться каждый раз, когда вы помещаете их в fragment_container. Они будут жить, пока жив твой FragmentActivity. Взгляните на жизненный цикл фрагментов. Только OnCreateView и onDestroyView методы фрагментов будут вызываться снова и снова, пока вы replace выполняете переход от одного фрагмента к другому.

Также у Фрагментов есть свой метод onSaveInstanceState, в котором вы можете сохранить состояние вашего фрагмента. Например: пользователь ввел свое имя в editText фрагмента1. Если вы хотите сохранить эти данные (строку имени), пока пользователь обнаруживает другие фрагменты, вам следует

1. сохранить строку имени в методе onSaveInstanceState фрагмента1
2. в методе onCreateView фрагмента1 проверить пакет saveInstanceState, если он не нулевой - заполнить edittext строкой, полученной из пакета.

public class Fragment1 extends Fragment {

EditText nameEditText;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    View fragment1View=inflater.inflate(R.layout.fragment1_layout, container, false);
    nameEditText=(EditText) fragment1View.findViewById(R.id.edittext_name);

    //check for saved data. if it is not null - fill your edittext with saved string
    if(savedInstanceState!=null){
        String nameString=(String) savedInstanceState.get("nameString");
        nameEditText.setText(nameString);
    }
    return fragment1View;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //save data that user have entered
    outState.putString("nameString", nameEditText.getText().toString());
}

}

Вы можете проверить данные перед сохранением. Надеюсь, теперь моя точка зрения ясна.

Также если вы вызовете setRetainInstance(true) в методе onCreateView() вашего fragment - система попытается сохранить состояние фрагмента (со всеми входными данными). ссылка на описание

person ashakirov    schedule 10.09.2012
comment
Спасибо за ответ, но возникает другая проблема, если я помещаю фрагменты вместо действий на вкладки. Например, на первой вкладке я хочу заменить контейнер другим фрагментом в случае, если пользователь нажмет кнопку, а затем, если я изменю вкладку, перейду ко второй, это заменит предыдущие фрагменты. Поэтому, если я снова перейду на первую вкладку, он снова создаст фрагмент, и я не смогу увидеть предыдущую страницу. У вас есть идеи, как от него избавиться? - person osayilgan; 10.09.2012
comment
я отредактировал свой ответ. Взгляните на это. А также есть примеры фрагментов в примерах (ApiDemos). Проверь их. - person ashakirov; 10.09.2012
comment
Да, я понял, но это не то, о чем я спрашиваю. Я работал с фрагментами и знаю, как это работает. Я не знаю, что: предположим, что мы находимся на первой вкладке, и я вызвал другой фрагмент в случае, если пользователь нажимает кнопку, для второго шага я изменил вкладку на вторую, так что здесь это заменит данные в нем с фрагментом второй вкладки верно? Но я также хочу, чтобы все было изменено на первой вкладке. Таким образом, если я просто заменю фрагменты на TabChange, это не сохранит ранее измененное содержимое на предыдущей вкладке. Есть идеи ? - person osayilgan; 10.09.2012
comment
хорошо, я, кажется, понимаю вашу проблему. Я отредактировал свой ответ еще раз! проверить это :) - person ashakirov; 10.09.2012
comment
Я попробую это как можно скорее и дам вам, если что-то произойдет. Спасибо за ответ еще раз :) - person osayilgan; 10.09.2012
comment
Спасибо за ответ, я также внес небольшие изменения в логику, и она работает так, как я хочу. - person osayilgan; 11.09.2012
comment
@osayilgan, не могли бы вы обновить код решением? или если вы разместили его в блоге, укажите ссылку. Спасибо - person Qadir Hussain; 04.04.2013
comment
@QadirHussain Пожалуйста, смотрите изменения в моем вопросе. Вы можете найти образец приложения, содержащий мое решение. Надеюсь, поможет. - person osayilgan; 04.04.2013
comment
Спасибо Лоту за это еще раз. это действительно полезно для меня. - person Qadir Hussain; 04.04.2013

Подход с размещением содержимого вкладок в отдельные действия устарел, поскольку теперь у нас есть структура фрагментов. Вы должны поместить сложное содержимое вкладок во фрагменты и поменять местами эти фрагменты, когда пользователь выбирает вкладки.

Рекомендуемое решение для этого — использовать панель действий с навигацией по вкладкам вместо использования виджета TabHost.

person Zsombor Erdődy-Nagy    schedule 10.09.2012
comment
Спасибо за ответ, у меня есть некоторые опасения по поводу его использования. Например, если я помещу фрагмент для первой вкладки, мне понадобится навигация в пределах той же вкладки, и, насколько я знаю, мы используем только один контейнер для целых вкладок и фрагментов в нем, поэтому после добавления пары фрагментов в основной контейнер на первой вкладке, я изменю его на вторую вкладку, поэтому, когда я это сделаю, это удалит все фрагменты, которые я создал и поместил в контейнер на первой вкладке, а второй фрагмент поместит в основной контейнер, - person osayilgan; 10.09.2012
comment
что означает, что все данные, которые я создал на первой вкладке, будут удалены и заменены вторым фрагментом? Что, если я вернусь на первую вкладку? Я буду воссоздавать его? - person osayilgan; 10.09.2012