Laborator 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: 1 M. Apetrii
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). 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. Informații suplimentare despre modul de utilizare al elementelor de tip Fragments se pot obține din curs sau de de la adresa: http://developer.android.com/guide/components/fragments.html Pentru exemplificare, urmați pașii prezentați mai jos: Pas 1 Creăm un nou proiect cu numele Ex_Fragments și FragmentActivity. Pas 2 In FragmentActivity.java vom avea public class FragmentActivity extends AppCompatActivity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_fragment); Pas 3 Pentru zona de import vom avea: import android.app.fragmenttransaction; import android.app.listfragment; import android.content.intent; import android.os.bundle; import android.app.activity; import android.app.fragment; import android.content.res.configuration; import android.support.v7.app.appcompatactivity; import android.util.typedvalue; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.widget.arrayadapter; import android.widget.listview; import android.widget.scrollview; import android.widget.textview; 2 M. Apetrii
Pas 4 In același folder cu FragmentActivity.java vom crea fișierul Resurse.java în care vom defini tablourile ce vor conține titlurile și valorile de afișat. public final class Resurse { * tabloul static cu lista titlurilor. public static final String[] TITLURI = { "TITLU I", "TITLU II", "TITLU III", "TITLU IV", "TITLU V" ; * tabloul static cu textele asociate titlurilor public static final String[] DETALII = { "Text asociat lui TITLU I.", "Text asociat lui TITLU II.", "Text asociat lui TITLU III.", "Text asociat lui TITLU IV.", "Text asociat lui TITLU V." ; Pas 6 Vom declara în clasa FragmentActivity fragment-ul din stânga, lista titlurilor. public static class FragmentTitluri extends ListFragment { public void onactivitycreated(bundle savedinstancestate) { super.onactivitycreated(savedinstancestate); // Populam lista dintr-un tablou static. setlistadapter(new ArrayAdapter<String>(getActivity(), android.r.layout.simple_list_item_activated_1, mape3.ex_fragments.resurse.titluri)); Pas 7 În folderul layout vom da fișierului activity_fragment.xml conținutul următor (pentru modul Portret) <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="mape3.ex_fragments.fragmentactivity$fragmenttitluri" 3 M. Apetrii
android:id="@+id/titluri" android:layout_width="match_parent" android:layout_height="match_parent" /> </merge> Pas 8 În folderul layout-land vom da fișierului activity_fragment.xml conținutul următor (pentru modul Landscape) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="mape3.ex_fragments.fragmentactivity$fragmenttitluri" android:id="@+id/titluri" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/detalii" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" android:background="?android:attr/detailselementbackground" /> </LinearLayout> Pas 9 Testam proiectul până în acest moment. În timpul testului, emulatorul poate comuta între modurile Portret/Landscape prin combinația de taste Ctrl+F11. Pas 10 În clasa FragmentTitluri definim variabilele: int elementselectat = 0; boolean tiplandscape; Pas 11 Funcției onactivitycreated din clasa FragmentTitluri îi adăugăm codul: // Testam daca este vizibil Activity-ul definit pentru modul Landscape View cadrudetalii = getactivity().findviewbyid(r.id.detalii); tiplandscape = cadrudetalii!= null && cadrudetalii.getvisibility() == View.VISIBLE; if (savedinstancestate!= null) { // determinam elenmentul selectat. elementselectat = savedinstancestate.getint("curchoice", 0); if (tiplandscape) { // afisam detalii despre elementul selectat getlistview().setchoicemode(listview.choice_mode_single); afiseazadetalii(elementselectat); 4 M. Apetrii
Pas 12 În clasa FragmentTitluri definim funcția afiseazadetalii * functia care afiseaza detalii despre elementul selectat void afiseazadetalii(int index) { elementselectat = index; if (tiplandscape) { // evidentiem elementul selectat getlistview().setitemchecked(index, true); //... else { //... Pas 13 Testam proiectul până în acest moment comutând între modurile Portret/Landscape. Pas 14 Vom declara în clasa FragmentActivity fragment-ul din dreapta care va contine detalii despre elementul selectat. public static class FragmentDetalii extends Fragment { * Cream o noua instanta pentru FragmentDetalii care va afisa textul corespunzator lui index. public static FragmentDetalii newinstance(int index) { FragmentDetalii f = new FragmentDetalii(); // preluam argumentele Bundle args = new Bundle(); args.putint("index", index); f.setarguments(args); return f; public int daindexselectat() { return getarguments().getint("index", 0); public View oncreateview(layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { if (container == null) { return null; //cream elementele pentru vizualizare ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); int padding = (int)typedvalue.applydimension(typedvalue.complex_unit_dip, 4, getactivity().getresources().getdisplaymetrics()); text.setpadding(padding, padding, padding, padding); scroller.addview(text); text.settext(resurse.detalii[daindexselectat()]); 5 M. Apetrii
return scroller; Pas 15 În clasa FragmentTitluri modificăm funcția afiseazadetalii void afiseazadetalii(int index) { elementselectat = index; if (tiplandscape) { // evidentiem elementul selectat getlistview().setitemchecked(index, true); nevoie // Verificam ce element este deja afisat si il inlocuim daca este FragmentDetalii detalii = (FragmentDetalii) getfragmentmanager().findfragmentbyid(r.id.detalii); if (detalii == null detalii.daindexselectat()!= index) { // Construim un fragment nou detalii = FragmentDetalii.newInstance(index); // inlocuim fragmentul existent cu cel nou. FragmentTransaction ft = getfragmentmanager().begintransaction(); ft.replace(r.id.detalii, detalii); ft.settransition(fragmenttransaction.transit_fragment_fade); ft.commit(); else { //... Pas 16 Testam proiectul până în acest moment comutând între modurile Portret/Landscape. Pas 17 În clasa FragmentTitluri adăugăm metodele public void onsaveinstancestate(bundle outstate) { super.onsaveinstancestate(outstate); outstate.putint("curchoice", elementselectat); public void onlistitemclick(listview l, View v, int position, long id) { afiseazadetalii(position); Pas 18 Testam proiectul până în acest moment comutând între modurile Portret/Landscape. 6 M. Apetrii
Pas 19 Pentru vizualizarea detaliilor și în modul Portret vom crea în FragmentActivity un nou Activity * Este al doilea "Activity" care se va afisa cand ecranul nu este suficient de lat (modul Portret). public static class DetaliiTitluActivity extends Activity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); if (getresources().getconfiguration().orientation== Configuration.ORIENTATION_LANDSCAPE) { // nu este necesar in modul Landscape. finish(); return; if (savedinstancestate == null) { // facem legatura cu fragmentul FragmentDetalii. FragmentDetalii detalii = new FragmentDetalii(); detalii.setarguments(getintent().getextras()); getfragmentmanager().begintransaction().add(android.r.id.content, detalii).commit(); Pas 20 Adăugăm acest nou Activity în AndroidManifest.xml <activity android:name=".fragmentactivity$detaliititluactivity" /> Pas 21 În funcția afiseazădetalii, pe ramura else adăugăm // Lansam o noua activitate pentru a afisa afragentul cu detalii // despre elementul selectat. Intent intent = new Intent(); intent.setclass(getactivity(), DetaliiTitluActivity.class); intent.putextra("index", index); startactivity(intent); Pas 22 Testam proiectul în forma finală, comutând între modurile Portret/Landscape. Exemplu pentru utilizarea senzorilor (se utilizează și elemente de tip Fragment) 7 M. Apetrii