Sunteți pe pagina 1din 10

Curs 6

Fragments
Un fragment reprezintă o porțiune dintr-un Activity. Într-un activity se pot combina mai multe
fragmente ți un fragment se poate reutiliza în activități multiple. Un fragment poate fi privit ca
secțiunea modulară a unei activități care are propriul său ciclu de viață, primește propriile
evenimente de intrare și care poate fi adăugată sau eliminată în timp ce activitatea se execută.

Un fragment trebuie să fie întotdeauna încorporat într-o activitate și ciclul de viață al


fragmentului este afectat în mod direct de ciclul de viață al activității gazdă. De exemplu, atunci
când activitatea este întreruptă sunt întrerupte toate fragmentele sale, iar atunci când activitatea
este distrusă sunt distruse toate fragmentele. Când o activitate rulează, fragmentele sale pot fi
manipulate independent, putând fi adăugate sau să eliminate. Acest lucru este deosebit de
important, deoarece un fragment modular permite diverse combinații de fragmente pentru diferite
dimensiuni de ecran.

(sursa: android.com)

Un fragment poate fi adăugat unui Activity direct în fișierul xml (layout) cu tagul <fragment>,
sau din cod prin adăugarea acestuia la un ViewGroup existent.

Fragmentele se utilizează cel mai des pentru:

 Reutilizarea unor părți ale ecranului, inclusiv vizualizarea și logica evenimentelor, în


moduri diferite, în activități diferite (ex.: utilizarea aceleiași liste în diferite surse de date
dintr-o aplicație).

1 M. Apetrii
 Adaptarea conținutului la dimensiunile ecranului (ex.: versiunea de tabletă a unei
activități are un aspect mult diferit față de versiunea pentru telefon, diferit față de de
versiunea pentru TV).
 Adaptarea conținutului la orientarea ecranului (ex.: versiunea portret a unei activități are
un aspect mult diferit față de versiunea peisaj). Fragmentele permit ambelor orientări să
reutilizeze elementele partajate.

Un fragment, la fel cu o activitate, are un fișier XML (de aspect) și o clasă Java care trebuie să
moștenească clasa Fragment.
Pentru a putea încorpora un fragment, activitatea trebuie să moștenească clasa FragmentActivity
sau AppCompatActivity, care adaugă suport pentru managerul de fragmente.

Exemplu:
ex_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />

</LinearLayout>

FragmentulMeu.java
public class FragmentulMeu extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
// Definim fisierul xml al fragmentului
return inflater.inflate(R.layout.ex_fragment, parent, false);
}

// se apeleaza imediat dupa onCreateView().


@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
//orice configurare pentru elemente de tip View trebuie sa apara
aici
// ...
}
}

Parametrul parent trecut la onCreateView() este părintele ViewGroup (de la aspectul


activității), în care va fi inserat fragmentul. Parametrul savedInstanceState este un
Bundle care furnizează date referitoare la instanța anterioară a fragmentului, dacă fragmentul

2 M. Apetrii
este reluat.

Metoda inflate() are trei argumente:


 ID-ul de resursei (layout-ului)
 Elementul de tip ViewGroup care va fi parintele layout-ului fragmentului.
 O variabilă booleană care indică dacă layout-ul fragmentului sa fie sau nu atașat la
ViewGroup-ul parinte (al doilea parametru)

Există două moduri de a adăuga un fragment unei activități: dinamic folosind Java și static
folosind XML.

Modul static –direct in XML

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<fragment
android:name="mape3.ex_fragments.FragmentulMeu"
android:id="@+id/fragmentulMeu"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

Modul dinamic- în codul Java

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<FrameLayout
android:id="@+id/id_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
...
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.your_placeholder, new FragmentulMeu());
ft.commit();
...

În metoda add() primul argument este ViewGroup-ul în care trebuie plasat fragmentul
specificat prin ID, iar al doilea parametru este fragmentul de adăugat.
La final trebuie apelată metoda commit(), pentru ca modificările să aibă efect.

Managementul fragmentelor într-un activity este un element de tip FragmentManager, care


poate fi obținut prin metoda getFragmentManager(). Printre altele, acesta dă fragmente
care există în activitate, cu findFragmentById()sau findFragmentByTag(), elimina

3 M. Apetrii
fragmente din stiva cu popBackStack(), înregistrează un ascultător pentru modificări ale
stivei, cu addOnBackStackChangedListener ().

Ca răspuns la interacțiunea cu utilizatorul, un fragment poate fi adăugat (add()), eliminat


(remove()), înlocuit (replace()) etc. O asemenea operație se numește o tranzacție și poate
fi efectuată folosind FragmentTransaction. O asemenea instanță se poate obține din
FragmentManager cu beginTransaction().

Exemplu de înlocuire a unui fragment cu altul (cu păstrarea stării anterioare în stivă):

// Cream un fragment si o tranzactie


Fragment newFragment = new ExempluFragment();
FragmentTransaction transaction =
getFragmentManager().beginTransaction();

// Inlocuim continutul vechi din fragment_container cu acest


// fragment si adaugam tranzactia in stiva
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Se executa tranzactia (operatia)


transaction.commit();

Prin apelarea addToBackStack(), tranzacția este salvată în stivă, astfel încât utilizatorul
poate să aducă înapoi fragmentul anterior prin apăsarea butonului Back.
Pentru a prelua fragmente din stiva, trebuie să suprascriem metoda onBackPressed () în
activitatea principală:

@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}

Dacă nu se suprascrie metoda onBackPressed() și există o activitate anterioară în stivă,


apăsarea butonului Back va face ca aplicația să revină la această activitate. Dacă nu există o
activitate anterioară în stivă, apăsarea butonului Back va face ca aplicația să se închidă.

Un fragment conține metode similare cu o activitate, cum ar fi onCreate(), onStart(),


onPause() și onStop(). Ciclul de viață al unui fragment este prezentat în figura de mai jos.

4 M. Apetrii
(sursa: android.com)

Principalele metode care ar trebui suprascrie:

onCreate()
Sistemul invocă această metodă la crearea fragmentului. De obicei aici se inițializează
componentele esențiale ale fragmentului.

onCreateView()
Sistemul invocă această metodă atunci când se desenează interfața cu utilizatorul a fragmentului.
Această metodă trebuie să întoarcă un element de tipul View. Se poate returna null dacă
fragmentul nu oferă o interfață de utilizare. Elementul de tip View returnat de
onCreateView() se poate obține dintr-un fisier xml definit în folderul layout.

onAttach()
Sistemul invocă această metodă la atașarea fragmentului la o activitate.

onPause()
Sistemul invocă această metodă atunci când utilizatorul da primul semn că utilizatorul părăsește
fragmentul (aceasta nu înseamnă întotdeauna că fragmentul este distrus). Se folosește de obicei
pentru a salvarea datelor în afara sesiunii utilizatorului curent (persistența datelor).

5 M. Apetrii
Comunicarea cu fragmentele

În general fragmentele comunică numai cu activitatea părinte, permițând activității să gestioneze


intrările și ieșirile de date din fiecare fragment. Excepție de la această regulă fac fragmentele de
dialog dintr-un alt fragment sau fragmentele copii imbricate. Ambele cazuri sunt situații în care
un fragment a imbricat fragmente copil și, prin urmare, li se permite să comunice în sus către
părintele lor (care este un fragment).

Există trei moduri în care un fragment și o activitate pot comunica:


Bundle - Activitatea poate construi un fragment și poate crea argumente
Metode - Activitatea poate apela metode ale unui fragment
Listener - Fragmentul poate declanșa evenimente ascultător la o activitate prin intermediul unei
interfețe

Comunicarea cu un fragment este, în general, astfel:


 activitățile pot crea fragmente cu date în timpul execuției
 activitățile pot transmite date către fragmente existente utilizând metodele ale acestuia
 fragmentele pot comunica cu activitatea părinte folosind o interfață și ascultători
 fragmentele care trebuie să transmită date altor fragmente fac acest lucru prin intermediul
activității părinte
 fragmentele pot transmite date către și din fragmente de dialog, fragmente copil imbricate

Comunicarea prin intermediul argumentelor:


Deoarece clasa Fragment are doar un constructor fără argumente, se va declara o metodă statică
newInstance care va crea un Fragment cu argumente, utilizând metoda setArguments.

Exemplu:

public class DemoFragment extends Fragment {


public static DemoFragment newInstance(int argInt, String argStr) {
DemoFragment fragmentDemo = new DemoFragment();
Bundle args = new Bundle();
args.putInt("Numar", argInt);
args.putString("Titlu", argStr);
fragmentDemo.setArguments(args);
return fragmentDemo;
}
}

Argumentele vor putea fi accesate în metoda onCreate.


public class DemoFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// preluam argumentele
int nr = getArguments().getInt("Numar", 0);
String titlu = getArguments().getString("Titlu", "");
}
...
}

În activitatea parinte, fragmentul se poate încărca dinamic astfel:

6 M. Apetrii
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
DemoFragment fragmentDemo = DemoFragment.newInstance(10, "Un titlu");
ft.replace(R.id.fragmentulMeu, fragmentDemo);
ft.commit();

Comunicarea prin intermediul metodelor:


Dacă activitatea părinte dorește să transmită date către un fragment, poate face lucrul acesta
invocând o metodă a acestuia prin intermediul managerului de fragmente.

Exemplu:

public class DemoFragment extends Fragment {


...
public void metoda_de_executat(String arg) {
...
}
}

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.fragmentulMeu);
fragmentDemo.metoda_de_executat("lista parametri");

...
}
...
}

Comunicarea prin intermediul ascultătorilor:


Dacă fragmentul trebuie să comunice cu activitatea atunci acesta poate defini o interfață care va
fi implementată de către activitate.

Exemplu: (android.com)

public class MyListFragment extends Fragment {


// Definim ascultatorul interfetei
private OnItemSelectedListener listener;

// Definim „evenimentul” folosit de fragment pentru comunicare


public interface OnItemSelectedListener {
// pot fi oricate
public void onRssItemSelected(String link);
}

// Pastram ascultatorul (activitatii)


@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnItemSelectedListener) {
listener = (OnItemSelectedListener) context;
} else {
throw new ClassCastException(context.toString()
+ " clasa trebuie sa implementeze
MyListFragment.OnItemSelectedListener");

7 M. Apetrii
}
}

// Putem apela metoda asociata evenimentului, pentru transmiterea


valorilor catre activitatea parinte
public void onSomeClick(View v) {
listener.onRssItemSelected("some link");
}
}

// Activitatea va implementa interfata ascultator a fragmentului


public class RssfeedActivity extends AppCompatActivity implements
MyListFragment.OnItemSelectedListener {
// Un fragment caruia dorim sa-i trimitem datele
DetailFragment fragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rssfeed);
// identificam fragmentul dupa id
fragment = (DetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.detailFragment);
}

// Definim metoda ce se va apela cand fragmentul solicita


// Este implementarea pentru metoda interfetei `OnItemSelectedListener`
@Override
public void onRssItemSelected(String link) {
if (fragment != null && fragment.isInLayout()) {
fragment.setText(link);
}
}
}

FragmentManager este responsabil pentru gestionarea în timp a fragmentelor, inclusiv


adăugarea, eliminarea, ascunderea, afișarea sau navigarea în alt mod între fragmente. Acesta este
de asemenea responsabil pentru găsirea fragmentelor în cadrul unei activități. Metodele
importante disponibile sunt:

Metodă Descriere

Adăugați un nou ascultător pentru


addOnBackStackChangedListener
modificarea stivei de fragmente.
Creează o nouă tranzacție pentru a
beginTransaction()
schimba fragmente în timpul rulării.
Găsește un fragment după id, de obicei
findFragmentById(int id)
dat în structura XML.

8 M. Apetrii
Metodă Descriere

Găsește un fragment după etichetă, de


findFragmentByTag(String tag) obicei, pentru un fragment adăugat în
execuție.
popBackStack() Elimină un fragment din stivă.
executePendingTransactions() Forțează aplicarea tranzacției angajate.

ActionBar Menu Items


Deseori, in programele noastre avem nevoie de meniuri specifice fragmentelor, care apar numai
pentru fragmentul respectiv. Acest lucru se poate face prin adăugarea directă a metodei
onCreateOptionsMenu la fragment. Aceasta funcționează la fel ca cea pentru activitate:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}

Trebuie apoi notificat fragmentul că elementele meniului trebuie încărcate odata cu fragmentul:

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}

Un click pe un element din meniu poate fi captat prin proprietatea onClick sau prin intermediul
metodei onOptionsItemSelected din fragment:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle item selection
switch (item.getItemId()) {
case R.id.edit_item:
// do s.th.
return true;
default:
return super.onOptionsItemSelected(item);
}
}

(sursa: android.com)
9 M. Apetrii
Subclase ale clasei Fragment care pot fi moștenite:

DialogFragment
Folosită pentru crearea casetelor de dialog

ListFragment
Afișează o listă de elemente care sunt gestionate de un „adapter”, similar cu ListActivity.
Acesta oferă mai multe metode, una din cele mai des folosite fiind onListItemClick() (se
apelează atunci când se selectează un element din listă).

10 M. Apetrii

S-ar putea să vă placă și