Udostępnij za pośrednictwem


Tworzenie fragmentu

Aby utworzyć fragment, klasa musi dziedziczyć z Android.App.Fragment metody , a następnie zastąpić metodę OnCreateView . OnCreateView zostanie wywołana przez działanie hostingu, gdy czas umieścić fragment na ekranie i zwróci wartość View. Typowa OnCreateView metoda spowoduje utworzenie tego View przez zawyżanie pliku układu, a następnie dołączenie go do kontenera nadrzędnego. Cechy kontenera są ważne, ponieważ system Android zastosuje parametry układu elementu nadrzędnego do interfejsu użytkownika fragmentu. Zostało to przedstawione w poniższym przykładzie:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    return inflater.Inflate(Resource.Layout.Example_Fragment, container, false);
}

Powyższy kod zwiększy widok Resource.Layout.Example_Fragmenti doda go jako widok podrzędny do kontenera ViewGroup .

Uwaga

Klasy podrzędne fragmentów muszą mieć publiczny domyślny konstruktor argumentu.

Dodawanie fragmentu do działania

Istnieją dwa sposoby, na które fragment może być hostowany wewnątrz działania:

  • Deklaratywnie — fragmenty mogą być używane deklaratywnie w .axml plikach układu przy użyciu tagu <Fragment> .

  • Programowo — fragmenty mogą być również tworzone dynamicznie przy użyciu interfejsu FragmentManager API klasy.

Użycie programowe za pośrednictwem FragmentManager klasy zostanie omówione w dalszej części tego przewodnika.

Deklaratywne używanie fragmentu

Dodanie fragmentu wewnątrz układu wymaga użycia tagu <fragment> , a następnie zidentyfikowania fragmentu przez podanie atrybutu class lub atrybutu android:name . Poniższy fragment kodu pokazuje, jak za pomocą atrybutu class zadeklarować fragmentelement :

<?xml version="1.0" encoding="utf-8"?>
<fragment class="com.xamarin.sample.fragments.TitlesFragment"
            android:id="@+id/titles_fragment"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />

W następnym fragmencie kodu pokazano, jak zadeklarować element fragment przy użyciu atrybutu android:name w celu zidentyfikowania klasy Fragment:

<?xml version="1.0" encoding="utf-8"?>
<fragment android:name="com.xamarin.sample.fragments.TitlesFragment"
            android:id="@+id/titles_fragment"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />

Po utworzeniu działania system Android utworzy wystąpienie każdego fragmentu określonego w pliku układu i wstawi widok utworzony OnCreateView zamiast Fragment elementu. Fragmenty, które są deklaratywne dodawane do działania, są statyczne i pozostaną w działaniu do momentu jego zniszczenia; Nie można dynamicznie zastępować ani usuwać takiego fragmentu w okresie istnienia działania, do którego jest dołączony.

Każdy fragment musi mieć przypisany unikatowy identyfikator:

  • android:id — podobnie jak w przypadku innych elementów interfejsu użytkownika w pliku układu, jest to unikatowy identyfikator.

  • android:tag — ten atrybut jest unikatowym ciągiem.

Jeśli żadna z poprzednich dwóch metod nie zostanie użyta, fragment przyjmie identyfikator widoku kontenera. W poniższym przykładzie, w którym ani nie podano, ani android:tag nie android:id podano, system Android przypisze identyfikator fragment_container do fragmentu:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="+@id/fragment_container"
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

        <fragment class="com.example.android.apis.app.TitlesFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
</LinearLayout>

Przypadek nazwy pakietu

System Android nie zezwala na wielkie litery w nazwach pakietów; Zgłosi wyjątek podczas próby nadmuchania widoku, jeśli nazwa pakietu zawiera wielkie litery. Jednak platforma Xamarin.Android jest bardziej forgiving i będzie tolerować wielkie litery w przestrzeni nazw.

Na przykład oba poniższe fragmenty kodu będą działać z platformą Xamarin.Android. Jednak drugi fragment kodu spowoduje android.view.InflateException zgłoszenie przez czystą aplikację systemu Android opartą na języku Java.

<fragment class="com.example.DetailsFragment" android:id="@+id/fragment_content" android:layout_width="match_parent" android:layout_height="match_parent" />

LUB

<fragment class="Com.Example.DetailsFragment" android:id="@+id/fragment_content" android:layout_width="match_parent" android:layout_height="match_parent" />

Cykl życia fragmentu

Fragmenty mają własny cykl życia, który jest nieco niezależny od cyklu życia działania hostingu, ale nadal ma to wpływ. Na przykład po wstrzymaniu działania wszystkie skojarzone z nim fragmenty są wstrzymane. Na poniższym diagramie przedstawiono cykl życia fragmentu.

Flow diagram illustrating the Fragment lifecycle

Metody cyklu życia tworzenia fragmentów

Poniższa lista przedstawia przepływ różnych wywołań zwrotnych w cyklu życia fragmentu podczas jego tworzenia:

  • OnInflate() — wywoływana podczas tworzenia fragmentu w ramach układu widoku. Może to być wywoływane natychmiast po utworzeniu fragmentu deklaratywnie z pliku układu XML. Fragment nie jest jeszcze skojarzony z jego działaniem, ale element Activity, Bundle i AttributeSet z hierarchii widoków są przekazywane jako parametry. Ta metoda jest najlepiej używana do analizowania atrybutu AttributeSet i zapisywania atrybutów, które mogą być używane później przez fragment.

  • OnAttach() — wywoływana po skojarzeniu fragmentu z działaniem. Jest to pierwsza metoda, która ma zostać uruchomiona, gdy fragment jest gotowy do użycia. Ogólnie rzecz biorąc, fragmenty nie powinny implementować konstruktora ani zastępować konstruktora domyślnego. Wszystkie składniki wymagane dla fragmentu powinny zostać zainicjowane w tej metodzie.

  • OnCreate() — wywoływana przez działanie w celu utworzenia fragmentu. Po wywołaniu tej metody hierarchia widoku działania hostingu może nie zostać całkowicie utworzone, więc fragment nie powinien polegać na żadnych częściach hierarchii widoku działania do późniejszego momentu w cyklu życia fragmentu. Na przykład nie należy używać tej metody do wykonywania żadnych poprawek ani korekt interfejsu użytkownika aplikacji. Jest to najwcześniejsza godzina, w której fragment może rozpocząć zbieranie potrzebnych danych. Fragment jest uruchomiony w wątku interfejsu użytkownika w tym momencie, więc należy unikać długiego przetwarzania lub wykonywać to przetwarzanie w wątku w tle. Tę metodę można pominąć, jeśli wywoływana jest funkcja SetRetainInstance(true). Ta alternatywa zostanie opisana bardziej szczegółowo poniżej.

  • OnCreateView() — tworzy widok fragmentu. Ta metoda jest wywoływana po zakończeniu metody OnCreate() działania. W tym momencie można bezpiecznie wchodzić w interakcje z hierarchią widoków działania. Ta metoda powinna zwrócić widok, który będzie używany przez fragment.

  • OnActivityCreated() — Wywoływana po działaniu Activity.OnCreate została ukończona przez działanie hostingu. W tej chwili należy wykonać ostateczne poprawki interfejsu użytkownika.

  • OnStart() — Wywoływana po wznowieniu działania zawierającego. Dzięki temu fragment jest widoczny dla użytkownika. W wielu przypadkach fragment będzie zawierać kod, który w przeciwnym razie znajduje się w metodzie OnStart() działania.

  • OnResume() — jest to ostatnia metoda wywoływana, zanim użytkownik będzie mógł wchodzić w interakcję z fragmentem. Przykładem rodzaju kodu, który powinien zostać wykonany w tej metodzie, byłoby włączenie funkcji urządzenia, z którymi użytkownik może wchodzić w interakcję, na przykład aparatu, z którego korzystają usługi lokalizacji. Usługi takie jak te mogą spowodować nadmierne wyczerpanie baterii, jednak i aplikacja powinna zminimalizować ich użycie, aby zachować żywotność baterii.

Metody cyklu życia zniszczenia fragmentów

Na następnej liście wyjaśniono metody cyklu życia, które są wywoływane jako fragment, jest niszczony:

  • OnPause() — Użytkownik nie może już wchodzić w interakcje z fragmentem. Taka sytuacja istnieje, ponieważ niektóre inne operacje fragmentu modyfikują ten fragment lub działanie hostingu jest wstrzymane. Istnieje możliwość, że działanie hostujące ten fragment może być nadal widoczne, czyli działanie w fokusie jest częściowo przezroczyste lub nie zajmuje pełnego ekranu. Gdy ta metoda stanie się aktywna, jest to pierwsze wskazanie, że użytkownik opuszcza fragment. Fragment powinien zapisać wszelkie zmiany.

  • OnStop() — Fragment nie jest już widoczny. Działanie hosta może zostać zatrzymane lub operacja Fragment modyfikuje ją w działaniu. To wywołanie zwrotne służy do tego samego celu co Activity.OnStop.

  • OnDestroyView() — Ta metoda jest wywoływana w celu oczyszczenia zasobów skojarzonych z widokiem. Jest to wywoływane, gdy widok skojarzony z fragmentem został zniszczony.

  • OnDestroy() — Ta metoda jest wywoływana, gdy fragment nie jest już używany. Jest on nadal skojarzony z działaniem, ale fragment nie działa już. Ta metoda powinna zwolnić wszystkie zasoby, które są używane przez fragment, takie jak SurfaceView , które mogą być używane dla aparatu fotograficznego. Tę metodę można pominąć, jeśli wywoływana jest funkcja SetRetainInstance(true). Ta alternatywa zostanie opisana bardziej szczegółowo poniżej.

  • OnDetach() — Ta metoda jest wywoływana tuż przed tym, jak fragment nie jest już skojarzony z działaniem. Hierarchia widoku fragmentu już nie istnieje, a wszystkie zasoby używane przez fragment powinny zostać zwolnione w tym momencie.

Korzystanie z klasy SetRetainInstance

Istnieje możliwość określenia fragmentu, że nie należy go całkowicie zniszczyć, jeśli działanie jest tworzone ponownie. Klasa Fragment udostępnia metodę SetRetainInstance w tym celu. Jeśli true zostanie przekazana do tej metody, po ponownym uruchomieniu działania zostanie użyte to samo wystąpienie fragmentu. W takim przypadku wszystkie metody wywołania zwrotnego będą wywoływane z wyjątkiem OnCreate wywołań zwrotnych cyklu życia i OnDestroy . Ten proces jest przedstawiony na diagramie cyklu życia przedstawionym powyżej (według zielonych linii kropkowanych).

Zarządzanie stanem fragmentu

Fragmenty mogą zapisywać i przywracać ich stan podczas cyklu życia fragmentu przy użyciu wystąpienia Bundleklasy . Pakiet umożliwia fragmentowi zapisywanie danych jako par klucz/wartość i jest przydatne w przypadku prostych danych, które nie wymagają dużej ilości pamięci. Fragment może zapisać swój stan za pomocą wywołania metody OnSaveInstanceState:

public override void OnSaveInstanceState(Bundle outState)
{
    base.OnSaveInstanceState(outState);
    outState.PutInt("current_choice", _currentCheckPosition);
}

Po utworzeniu nowego wystąpienia fragmentu stan zapisany w Bundle obiekcie stanie się dostępny dla nowego wystąpienia za pośrednictwem OnCreatemetod , OnCreateViewi OnActivityCreated nowego wystąpienia. W poniższym przykładzie pokazano, jak pobrać wartość current_choice z elementu Bundle:

public override void OnActivityCreated(Bundle savedInstanceState)
{
    base.OnActivityCreated(savedInstanceState);
    if (savedInstanceState != null)
    {
        _currentCheckPosition = savedInstanceState.GetInt("current_choice", 0);
    }
}

Zastępowanie OnSaveInstanceState to odpowiedni mechanizm zapisywania danych przejściowych w fragmentowaniu zmian orientacji, takich jak current_choice wartość w powyższym przykładzie. Jednak domyślna implementacja OnSaveInstanceState programu dba o zapisywanie danych przejściowych w interfejsie użytkownika dla każdego widoku z przypisanym identyfikatorem. Na przykład przyjrzyj się aplikacji, która ma EditText element zdefiniowany w formacie XML w następujący sposób:

<EditText android:id="@+id/myText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

Ponieważ kontrolka EditText ma przypisaną id , fragment automatycznie zapisuje dane w widżecie po OnSaveInstanceState wywołaniu.

Ograniczenia pakietu

Chociaż użycie OnSaveInstanceState ułatwia zapisywanie danych przejściowych, użycie tej metody ma pewne ograniczenia:

  • Jeśli fragment nie zostanie dodany do stosu wstecz, jego stan nie zostanie przywrócony, gdy użytkownik naciśnie przycisk Wstecz .

  • Gdy pakiet jest używany do zapisywania danych, dane te są serializowane. Może to prowadzić do opóźnień przetwarzania.

Współtworzenia menu

Fragmenty mogą współtworzyć elementy w menu ich działania hostingu. Działanie najpierw obsługuje elementy menu. Jeśli działanie nie ma procedury obsługi, zdarzenie zostanie przekazane do fragmentu, co spowoduje jego obsługę.

Aby dodać elementy do menu Działania, fragment musi wykonać dwie czynności. Najpierw fragment musi zaimplementować metodę OnCreateOptionsMenu i umieścić jej elementy w menu, jak pokazano w poniższym kodzie:

public override void OnCreateOptionsMenu(IMenu menu, MenuInflater menuInflater)
{
    menuInflater.Inflate(Resource.Menu.menu_fragment_vehicle_list, menu);
    base.OnCreateOptionsMenu(menu, menuInflater);
}

Menu w poprzednim fragmencie kodu jest zawyżone z następującego kodu XML znajdującego się w pliku menu_fragment_vehicle_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/add_vehicle"
        android:icon="@drawable/ic_menu_add_data"
        android:title="@string/add_vehicle" />
</menu>

Następnie fragment musi wywołać metodę SetHasOptionsMenu(true). Wywołanie tej metody informuje system Android o tym, że fragment zawiera elementy menu umożliwiające współtworzenie menu opcji. Jeśli nie zostanie wykonane wywołanie tej metody, elementy menu fragmentu nie zostaną dodane do menu opcji Działanie. Zazwyczaj odbywa się to w metodzie OnCreate()cyklu życia , jak pokazano w następnym fragmencie kodu:

public override void OnCreate(Bundle savedState)
{
    base.OnCreate(savedState);
    SetHasOptionsMenu(true);
}

Na poniższym ekranie pokazano, jak wyglądałoby to menu:

Example screenshot of My Trips app displaying menu items