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

Тъй като TabActivity е отхвърлен, трябва да намеря начин да го направя с Fragments. Работил съм с Fragments, преди да разбера как работи, но имам нужда от ръководство, за да създам своя хост на раздели с FragmentActivities. Намерих няколко примера в интернет и всички те са за поставяне на фрагменти в контейнер за разделите.

Това, което искам, е да поставя FragmentActivities за всеки раздел. Тъй като в моето приложение ще използвам 4 раздела и всеки от разделите има наистина сложно съдържание в него. В резултат на това трябва да имам FragmentActivity за всеки раздел, за да управлявам фрагментите, които ще поставя под всеки раздел в отделен контейнер.

РЕШЕНИЕ:

След отговори и търсене в интернет намерих решение. Според решението, което намерих, следя фрагментите в отделен стек за всеки раздел под хост на раздела. Ето моето GitHub хранилище, създадох малко примерно приложение за този проблем.


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


Отговори (2)


Тъй като TabActivity е отхвърлен, трябва да намеря начин да го направя с Fragments.

Ако не искате да използвате TabActivity - забравете за поставянето на FragmentActivities в съдържанието на раздела.

Напомням, че можете да използвате TabWidget без TabActivity. Така че можете да опитате това решение:

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

Или можете да създадете FragmentActivity с TabWidget и вместо да превключвате Fragments, можете директно да поставите Fragments в съдържанието на всеки раздел.

Например, ако имате 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 прехвърляте един фрагмент към друг.

Също така Fragments има техния onSaveInstanceState метод, където можете да запазите състоянието на вашия фрагмент. Например: потребителят въвежда името си в editText на fragment1. Ако искате да запазите тези данни (низ от име), докато потребителят открие други фрагменти, трябва

1.запазете низ от име в onSaveInstanceState метода на fragment1
2. в метода onCreateView на fragment1 проверете пакета savedInstanceState, ако не е null - попълнете 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
Да, разбрах, но това не е нещото, което питам. Работил съм с фрагменти и знам как става. Нещото, което не знам е, че: Да приемем, че сме в първия раздел и извиках друг фрагмент в случай, че потребителят кликне върху бутона, за втората стъпка промених раздела на втория, така че тук това ще замени данните в него с фрагмента на втория раздел, нали? Но също така искам да запазя нещата, които са променени в първия раздел. Така че по този начин, ако просто заменя фрагментите onTabChange, това няма да запази промененото преди това съдържание в предишния раздел. Някаква идея ? - 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

Подходът за поставяне на съдържанието на раздела в отделни дейности е отхвърлен, тъй като сега имаме Fragment Framework. Трябва да поставите сложното съдържание на разделите във фрагменти и да разменяте тези фрагменти, когато потребителят избира раздели.

Препоръчителното решение за това е да използвате ActionBar с навигация Tab, вместо да използвате изпълнимия модул TabHost.

person Zsombor Erdődy-Nagy    schedule 10.09.2012
comment
Благодаря за отговора, имам някои притеснения относно използването му. Например, ако поставя фрагмент за първия раздел, ще ми трябва навигация в рамките на същия раздел и доколкото знам, ние използваме само един контейнер за цели раздели и фрагментите в него, така че след добавяне на няколко фрагмента към основен контейнер в първия раздел, ще го променя на втори раздел, така че когато го направя, това ще премахне всички фрагменти, които съм създал и поставил в контейнера в първия раздел и ще постави втория фрагмент в главния контейнер, - person osayilgan; 10.09.2012
comment
което означава, че всички данни, които създадох в първия раздел, ще бъдат изтрити и заменени с втори фрагмент? Какво ще стане, ако се върна към първия раздел? Ще го пресъздам ли? - person osayilgan; 10.09.2012