Musieliśmy zaimplementować dokładnie to samo zachowanie, które ostatnio opisujesz dla aplikacji. Ekrany i ogólny przebieg aplikacji zostały już zdefiniowane, więc musieliśmy się tego trzymać (to klon aplikacji na iOS ...). Na szczęście udało nam się pozbyć ekranowych przycisków wstecz :)
Zhakowaliśmy rozwiązanie przy użyciu mieszanki TabActivity, FragmentActivities (używaliśmy biblioteki obsługi fragmentów) i Fragments. Z perspektywy czasu jestem prawie pewien, że nie była to najlepsza decyzja dotycząca architektury, ale udało nam się to naprawić. Gdybym musiał to zrobić ponownie, prawdopodobnie spróbuję zrobić rozwiązanie bardziej oparte na aktywności (bez fragmentów) lub spróbować mieć tylko jedną aktywność dla zakładek i niech cała reszta będzie widokami (które uważam za znacznie więcej wielokrotnego użytku niż ogólnie czynności).
Tak więc wymagania były takie, aby w każdej zakładce było kilka zakładek i ekranów z możliwością zagnieżdżania:
tab 1
screen 1 -> screen 2 -> screen 3
tab 2
screen 4
tab 3
screen 5 -> 6
itp...
Powiedzmy: użytkownik uruchamia się na karcie 1, przechodzi od ekranu 1 do ekranu 2, a następnie do ekranu 3, a następnie przechodzi do karty 3 i przechodzi od ekranu 4 do 6; jeśli przełączył się z powrotem na kartę 1, powinien ponownie zobaczyć ekran 3, a jeśli nacisnął przycisk Wstecz, powinien wrócić do ekranu 2; Znowu i jest na ekranie 1; przejdź do zakładki 3 i znowu jest na ekranie 6.
Głównym działaniem w aplikacji jest MainTabActivity, które rozszerza TabActivity. Każda zakładka jest powiązana z działaniem, powiedzmy ActivityInTab1, 2 i 3. A potem każdy ekran będzie fragmentem:
MainTabActivity
ActivityInTab1
Fragment1 -> Fragment2 -> Fragment3
ActivityInTab2
Fragment4
ActivityInTab3
Fragment5 -> Fragment6
Każda karta ActivityInTab zawiera tylko jeden fragment na raz i wie, jak zastąpić jeden fragment innym (prawie tak samo jak ActvityGroup). Fajne jest to, że w ten sposób dość łatwo jest utrzymać oddzielne stosy tylne dla każdej karty.
Funkcjonalność każdej karty ActivityInTab była taka sama: umieć nawigować z jednego fragmentu do drugiego i utrzymywać stos, więc umieściliśmy go w klasie bazowej. Nazwijmy to po prostu ActivityInTab:
abstract class ActivityInTab extends FragmentActivity { // FragmentActivity is just Activity for the support library.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_tab);
}
/**
* Navigates to a new fragment, which is added in the fragment container
* view.
*
* @param newFragment
*/
protected void navigateTo(Fragment newFragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, newFragment);
// Add this transaction to the back stack, so when the user presses back,
// it rollbacks.
ft.addToBackStack(null);
ft.commit();
}
}
Activity_in_tab.xml jest po prostu taka:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:isScrollContainer="true">
</RelativeLayout>
Jak widać, układ widoku dla każdej karty był taki sam. Dzieje się tak, ponieważ jest to tylko FrameLayout o nazwie content, który będzie zawierał każdy fragment. Fragmenty to te, które mają widok każdego ekranu.
Tylko dla punktów bonusowych dodaliśmy również mały kod, aby wyświetlić okno dialogowe potwierdzenia, gdy użytkownik naciśnie przycisk Wstecz i nie ma więcej fragmentów, do których można wrócić:
// In ActivityInTab.java...
@Override
public void onBackPressed() {
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0) {
// If there are back-stack entries, leave the FragmentActivity
// implementation take care of them.
super.onBackPressed();
} else {
// Otherwise, ask user if he wants to leave :)
showExitDialog();
}
}
To prawie konfiguracja. Jak widać, każda FragmentActivity (lub po prostu aktywność w systemie Android> 3) dba o całe układanie w stos z własnym FragmentManager.
Działanie takie jak ActivityInTab1 będzie naprawdę proste, pokaże tylko swój pierwszy fragment (tj. Ekran):
public class ActivityInTab1 extends ActivityInTab {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
navigateTo(new Fragment1());
}
}
Następnie, jeśli fragment musi przejść do innego fragmentu, musi wykonać trochę nieprzyjemnego rzucania ... ale nie jest tak źle:
// In Fragment1.java for example...
// Need to navigate to Fragment2.
((ActivityIntab) getActivity()).navigateTo(new Fragment2());
Więc to wszystko. Jestem prawie pewien, że nie jest to bardzo kanoniczne (i na pewno niezbyt dobre) rozwiązanie, więc chciałbym zapytać doświadczonych programistów Androida, jakie byłoby lepsze podejście do uzyskania tej funkcjonalności, a jeśli nie jest to „jak to jest gotowe ”w Androidzie, byłbym wdzięczny, gdybyś wskazał mi jakiś link lub materiał wyjaśniający, w jaki sposób można to zrobić w systemie Android (karty, zagnieżdżone ekrany w kartach itp.). Zapraszam do rozdzielenia tej odpowiedzi w komentarzach :)
Znakiem, że to rozwiązanie nie jest zbyt dobre, jest to, że ostatnio musiałem dodać do aplikacji jakąś funkcjonalność nawigacyjną. Jakiś dziwaczny przycisk, który powinien przenosić użytkownika z jednej karty do drugiej i do zagnieżdżonego ekranu. Robienie tego programowo było uciążliwe, ponieważ problemy „kto-wie-kto” i radzenie sobie z tym, kiedy są fragmentami i działaniami, które zostały faktycznie zainicjowane i zainicjowane. Myślę, że byłoby znacznie łatwiej, gdyby te ekrany i karty były tak naprawdę tylko widokami.
Na koniec, jeśli chcesz przetrwać zmiany orientacji, ważne jest, aby Twoje fragmenty były tworzone za pomocą setArguments / getArguments. Jeśli ustawisz zmienne instancji w konstruktorach twoich fragmentów, będziesz spieprzony. Ale na szczęście to naprawdę łatwe do naprawienia: po prostu zapisz wszystko w setArguments w konstruktorze, a następnie pobierz te rzeczy za pomocą getArguments w onCreate, aby z nich skorzystać.