W tej lekcji:
Do przeczytania:
Do wypróbowania:
Pobierz przykładowy interfejs.
Jeśli projektujesz aplikację z myślą o obsłudze ekranów o różnych rozmiarach, możesz wykorzystać te same fragmenty w różnych konfiguracjach, tak by zapewnić użytkownikowi optymalny interfejs w zależności od dostępnego na ekranie miejsca.
Na przykład na telefonie komórkowym najlepszą opcją może być interfejs jednopanelowy wyświetlający tylko jeden fragment na raz. Z kolei na tablecie, dysponującym szerszym ekranem, na którym można wyświetlić więcej informacji, lepszym wyjściem może być ustawienie fragmentów obok siebie.
Klasa FragmentManager
zawiera metody umożliwiające zaprojektowanie dynamicznego interfejsu poprzez dodawanie, usuwanie i zamienianie fragmentów aktywności w czasie wykonywania.
Dodawanie fragmentu do aktywności w czasie wykonywania
Zamiast definiować fragmenty aktywności w pliku szablonu — za pomocą elementu <fragment>
, tak jak pokazano w lekcji poprzedniej — można je dodawać do aktywności w czasie wykonywania. Jest to niezbędne, jeśli planujesz zamieniać fragmenty w czasie istnienia aktywności.
Do wykonania transakcji, np. dodania lub usunięcia elementu, konieczne jest skorzystanie z klasy FragmentManager
w celu utworzenia egzemplarza klasy FragmentTransaction — dostarczy on API potrzebny do dodania, usunięcia czy zamienienia fragmentów lub wykonania innych transakcji.
Jeśli aktywność umożliwia usuwanie i zamienianie fragmentów, należy dodać początkowy fragment (lub kilka z nich) do aktywności podczas wykonywania metody onCreate()
.
Co ważne — zwłaszcza w przypadku fragmentów dodawanych w czasie wykonywania — fragment musi mieć w szablonie swój kontener View
, w którym będzie przechowywany szablon fragmentu.
Poniższy szablon stanowi alternatywną wersję szablonu zaprezentowanego w poprzedniej lekcji, w którym wyświetlany jest tylko jeden fragment na raz. Aby podmienianie fragmentów było możliwe, szablon aktywności zawiera pustą klasę FrameLayout
, która pełni funkcję kontenera dla fragmentów.
Warto zwrócić uwagę, że nazwa pliku jest taka jak nazwa szablonu z poprzedniej lekcji, jednak katalog szablonu nie zawiera kwalifikatora large
. Szablon jest zatem wykorzystywany na urządzeniach o mniejszych ekranach, gdzie jest zbyt mało miejsca na jednoczesne wyświetlenie obydwu fragmentów.
res/layout/news_articles.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Wewnątrz aktywności wywołaj metodę getSupportFragmentManager()
, aby pobrać klasę FragmentManager korzystającą z API z biblioteki pomocniczej. Następnie wywołaj metodę beginTransaction()
w celu utworzenia transakcji FragmentTransaction
i dodaj fragment za pomocą metody add()
.
Korzystając z tego samego egzemplarza klasy FragmentTransaction
można wykonać wiele transakcji na fragmentach. Kiedy już będziesz gotowy na wprowadzenie zmian, musisz wywołać metodę commit()
.
Oto przykład, jak można dodać fragment do poprzedniego szablonu:
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// sprawdź, czy aktywność korzysta z wersji szablonu z kontenera
// fragment_container szablonu FrameLayout
if (findViewById(R.id.fragment_container) != null) {
// Jeśli jednak przywracamy szablon z poprzedniego stanu,
// to nie musimy nic robić; zostanie wykonane polecenie return, w przeciwnym razie
// fragmenty mogłyby się na siebie nakładać
if (savedInstanceState != null) {
return;
}
// tworzy nowy fragment, który zostanie umieszczony w szablonie aktywności
HeadlinesFragment firstFragment = new HeadlinesFragment();
// jeśli aktywność została uruchomiona za pomocą specjalnych instrukcji z
// intencji, przekaż do fragmentu za pośrednictwem intencji dane w postaci argumentów
firstFragment.setArguments(getIntent().getExtras());
// dodaj fragment do kontenera fragment_container szablonu FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
}
Ponieważ fragment został dodany do kontenera FrameLayout
w czasie wykonywania — a nie zdefiniowany w szablonie aktywności za pomocą elementu <fragment>
— można go w aktywności usunąć lub zamienić z innym fragmentem.
Zastępowanie jednego fragmentu innym
Procedura zamienia fragmentów przypomina usuwanie, jednak zamiast metody add()
potrzebna jest metoda replace()
.
Pamiętaj, że przy okazji wykonywania transakcji na fragmentach, np. usuwania czy dodawania, często warto umożliwić użytkownikowi opcję „powrotu”, która cofnie zmianę. W tym celu należy wywołać metodę addToBackStack()
przed potwierdzeniem transakcji FragmentTransaction
.
Oto przykład ilustrujący zamienianie jednego fragmentu na inny:
// utwórz fragment i przekaż mu argument określający artykuł, który ma być wyświetlony
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// zamień całą zawartość widoku fragment_container na ten fragment
// i dodaj transakcję do stosu tylnego, aby użytkownik miał możliwość powrotu
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// potwierdź transakcję
transaction.commit();
Metoda addToBackStack()
przyjmuje opcjonalny parametr łańcuchowy, który określa unikalną nazwę danej transakcji. Nazwa ta potrzebna jest jedynie jeśli planujesz wykonać jakieś zaawansowane operacje na fragmentach z wykorzystaniem API elementu FragmentManager.BackStackEntry
.
Zamiast „stosu tylnego”, dla BackStack odpowiedniejsze było by tłumaczenie „stosu wstecznego”.
Pozdrawiam