Aplicațiile mobile Android se bazează pentru eficienta si utilitatea pe interfețe compuse din ferestre de dialog, controale vizuale variate, grafica 2D si alte elemente multimedia. Platforma Android permite programatorilor sa utilizeze doua metode de proiectare/definire a interfețelor utilizator: procedural prin utilizarea de instrucțiuni din cod sau declarativ prin definirea de fișiere descriptive XML.
In acest articol vom dezvolta o aplicație mobila Android simpla pentru a face o analiza privind proiectarea procedurala vs. cea declarativa a interfeței cu utilizatorul.
Procedural înseamnă sa utilizezi cod Java pentru proiectarea interfeței cu utilizatorul. Acest lucru este ceva obișnuit in proiectarea interfețelor Swing pe platforma JSE sau in proiectarea interfețelor utilizator in MIDlet-uri J2ME. Pentru ca fiecare element al interfeței cu utilizatorul este gestionat de instante ale unor diferite clase, proiectarea interfeței înseamnă sa construiești si sa gestionezi aceste instante.
Declarativ înseamnă sa folosești un limbaj de marcare descriptiv, ca XHTML sau XML, pentru a descrie interfața cu utilizatorul. Acest lucru este similar cu modul in care paginile HTML (cele simple) sunt construite. Designerul descrie aspectul paginii si browser-ul Web interpretează si generează interfața cu utilizatorul.
Unele subiecte si concepte amintite in acest articol au fost descrise in detaliu in:
- Tutorial Android (01) – Instrumente necesare si configurare mediu de lucru
- Android Tutorial (02) – Concepte, activitati si resurse ale unei aplicatii Android
- Tutorial Android (03) – Cum sa dezvolti, testezi si sa intelegi o aplicatie de tip Hello World
Alte subiecte care fac parte din acest tutorial Android sunt accesibile prin intermediul Tutorial Android – Descriere si cuprins.
Aplicația mobila Android dezvoltata pentru aceasta analiza procedural vs declarativ arata astfel:
Interfața cu utilizatorul a aplicației dezvoltate se bazează pe o singura activitate care are un layout liniar cu 2 controale: un TextView si un Button.
Cum se gestionează interfața unei aplicații mobile Android folosind instante de tip View si ViewGroup
Interfata aplicatiei Android este definita de unul sau mai multe formulare/ferestre. Fiecare fereastra este controlata printr-o instanta de tip Activity care are un ciclu de viata complex (Android Tutorial (02) – Concepte, activitati si resurse ale unei aplicatii Android). Componentele vizuale ale activitatii sunt construite folosind obiecte de tip ViewGroup si View.
- Clasa View este parintele pentru o ierarhie mare de controale vizuale, widget-uri, cum ar fi textbox-uri, checkbox-uri, butoane, ….
- Clasa ViewGroup este baza pentru o ierarhie de layout-uri, folosite pentru a gestiona colectii de widget-uri si pentru a defini arhitectura interfetei (liniara, relativa, tabelara).
Widget-urile sunt afisate numai in cazul in care se adauga la layout-ul activitatii. Pentru abordarea procedurala acestea trebuie adaugate la colectia de View-uri a layout-ului prin apelul metodei addView(). Pentru abordarea declarativa, widget-urile se definesc in interiorul nodului XML aferent layout-ului.
Diagrama urmatoare descrie o parte din framework-ul de widget-uri Android, care are ca radacina clasa View.
Aceste doua clase si subclasele lor reprezinta elemente de baza pentru dezvoltarea interfetelor aplicatiilor Android. Interfata unei activitati este definita de:
- o subclasa de tip
ViewGroup
, caLinearLayout
,RelativeLayout
,TableLayout
,FrameLayout
care defineste layout-ul si ajuta la proiectarea interfetei si la pozitionarea controalelor, este posibil sa aspecte cuib si joi defini interfetele complexe, dar keel in vedere faptul ca interfata cu utilizatorul este limitat de dimensiunea ecranului si cele mai multe ori, EqualLogic eficienta simplitatea si usurinta in utilizare; - una sau mai multe componente
View
sauViewGroup
(unele controale vizuale, cum ar fiCalendar View
sau Data Picker sunt subclase de tipViewGroup
).
Daca ne aruncam o privire la o interfata de tip Android
putem observa ca exista o relatie intre instantele de tip ViewGroup
si cele de tip View
care defineste o arhitectura arborescenta pentru interfata. Aceasta ierarhie are ca radacina un nod ViewGroup
:
Cum se definește interfața Android într-un mod procedural
Dupa cum s-a precizat mai devreme in acest articol, proiectarea interfetei intr-un mod programatic inseamna sa folosesti instructiuni Java. Aceasta a fost si este singura cale pentru unele platforme de dezvoltare si este posibil deoarece totul de pe interfata reprezinta o resursa gestionata de catre un obiect.
Pentru a proiecta interfata programatic sau procedural trebuie sa se inteleaga framework-ul si sa se cunoasca relatia dintre elementele de pe interfata si clasele lor. De asemenea, relatia parinte-copil dintre componentele vizuale este importanta deoarece unele controale definesc containere sau colectii folosite pentru a administra controale de tip copil sau sub-controale.
Dupa cum se observa in prima sectiune a acestui articol si in Android Tutorial (02) – Concepte, activitati si resurse ale unei aplicatii Android, fereastra unei aplicatii Android este gestionata de catre o clasa de tip Activity. Aceasta este ceea ce obtinem atunci când construim un proiect Android cu urmatoarele proprietatile:
- Project name: HelloWorldAndroid
- Create new project in workspace: verificat (valoare implicita)
- Use default location: in mod implicit in spatiul de lucru Eclipse sau il puteti modifica
- Build target: selectati Android 2.3.3 ( Turta dulce) ;
- Application name: Hello World Android (nume in bara de titlu cerere)
- Package name: eu.itcsolutions.tutorial.android
- Create Activity: HelloActivity (lasati bifata optiunea si setati numele de activitate)
- Min SDK Version: 10
package eu.itcsolutions.tutorial.android; import android.app.Activity; import android.os.Bundle; public class HelloActivity extends Activity { /** Apelata cand Activitatea este creata. */ @Override public void onCreate(Bundle savedInstanceState) { //apel al metodei din clasa de baza super.onCreate(savedInstanceState); //setare layout display setContentView(R.layout.main); } }
Eclipse si plugin-ul ADT genereaza o simpla aplicatie Android, care are doar o singura fereastra/formular. De asemenea, solutia generata supradefineste metoda onCreate (Bundle savedInstanceState), ce reprezinta handler implicit pentru evenimentul de creare a activitatii. Acesta este un moment bun pentru a defini interfata cu utilizatorul. De asemenea, Eclipse genereaza o interfata simpla, care are un aspect liniar si care afiseaza mesaj Hello Android. Deoarece interfata este generata declarativ (metoda recomandata de Google) scoateti sau comentati instructiunile:
//incarcare layout definit intr-o abordare declarativa //setContentView(R.layout.main);
In acest fel, vom proiecta intreaga interfata din codul Java al aplicatiei:
1. Primul lucru pe care trebuie sa-l facem este sa deschidem documentatia API-ului Android, in special sectiunea referitoare la pachetul android.widget. Numarul mare de clase, metode si proprietati face imposibila invatarea pe de rost a API-ului si, daca doriti sa va amintiti sau sa gasiti o metoda este mult mai usor sa verificati documentatia pentru acea clasa.
2. Prima modificare a solutiei generate este facuta pentru a modifica textul din bara de titlu. Aceasta este o proprietate a activitatii si este initializata de metoda setTitle()
. Toate modificarile sunt facute in metoda onCreate(Bundle savedInstanceState)
:
@Override public void onCreate(Bundle savedInstanceState) { //apel al metodei din clasa de baza super.onCreate(savedInstanceState); //definire text in bara de titlu a ferestrei this.setTitle("First Android Application"); }
3. Pentru a defini si pentru a controla pozitia controalelor vizuale pe ecran, vom construi un layout liniar. Acesta va avea o orientare verticala deoarece ne propunem ca elementele interfetei sa fie plasate in layout intr-o ordine sus -> jos:
//definire si creare layout liniar LinearLayout mainLayout; mainLayout = new LinearLayout(this); //definire orientare verticala mainLayout.setOrientation(1);
4. Definim un container pentru informațiile de tip text. În Android etichetele text sunt gestionate de un widget de tip TextView. Pentru text se va defini valoarea de tip String ( setText()
), dimensiunea ( setTextSize()
) si culoarea ( setTextColor()
). De asemenea, vom aplica stilul bold si italic fontului sans serif implicit al sistemului ( setTypeface()
), folosind clasa Typeface. Pentru culoare vom folosi o culoare de sistem, predefinita (clasa Color), dar o putem defini folosind o combinatie RGB:
TextView txtInfo = new TextView(this); txtInfo.setText("Hello World Android !"); txtInfo.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC); txtInfo.setTextSize(20); txtInfo.setTextColor(Color.GREEN); //txtInfo.setTextColor(Color.rgb(0, 255, 0));
5. Construim o instanta de tip buton ce va conține textul Click me!.
Button btnClick = new Button(this); //definire text buton btnClick.setText("Click me !");
6. Odată ce widget-urile de pe interfața cu utilizatorul au fost create, asta nu inseamna ca vor fi si afisate. Pentru a le face vizibile, trebuie sa le adaugam pe layout:
mainLayout.addView(txtInfo); mainLayout.addView(btnAbout);
7. Setam obiectul layout creat ca display pentry activitate:
//definire layout display pentru Activitate this.setContentView(mainLayout);
Dupa ultimul pas, interfata cu utilizatorul arata ca aceasta:
Ceea ce vrem sa facem in continuare este sa centram continutul eranului si sa stabilim o serie de proprietati pentru buton.
8. Pentru a gestiona pozitia (pe ambele axe, verticale si orizontale) continutului din interiorul layout-ului este folosita metoda setGravity (int greutate)
. Metoda foloseste ca argumente o combinatie de valori predefinite . Pentru combinatia Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL
vom centra pe verticala si pe orizontala continutul layout-ului:
mainLayout.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
9. In mod implicit latimea TextView-ului si a Button-ului este egala cu latimea containerului-parinte (in acest exemplu layout-ul de tip LinearLayout). Pentru a controla aceste proprietati, putem folosi clasa LayoutParams care poate fi utilizata pentru a defini greutatea, latime, inaltime si pozitia elementului de tip View. Odata ce structura de tip LayoutParams a fost creata, acesta este legata de elementul de tip View folosind metoda setLayoutParams(LayoutParams Params).
Daca vrem sa se defineasca latimea elementului TextView ca fiind egala cu continutul sau, plus un padding, atunci parametrul pentru latime din instanta de tip LayoutParams va avea valoarea WRAP_CONTENT. Pentru buton vom folosi o latime predefinite de 120 pixeli (este mai indicat sa se foloseasca dp – device independent pixel ca unitate de masura).
//definire LayoutParams pentru TextView //width - latime egala cu continutul //height - inaltime egala cu continutul android.widget.LinearLayout.LayoutParams txtLayoutParams = new LinearLayout.LayoutParams( android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT); //setare LayoutParams txtInfo.setLayoutParams(txtLayoutParams); //definire LayoutParams pentru Button //width - latime de 120 px //height - inaltime egala cu continutul android.widget.LinearLayout.LayoutParams btnLayoutParams = new LinearLayout.LayoutParams( 120, android.view.ViewGroup.LayoutParams.WRAP_CONTENT); //setare LayoutParams btnClick.setLayoutParams(btnLayoutParams);
- Atentie !
- Strucura LayoutParams este definita in pachetul android.widget.LinearLayout, dar constantele LayoutParams.WRAP_CONTENT si LayoutParams.MATCH_PARENT (inlocuieste LayoutParams.FILL_PARENT) si clasa din care provin sunt definite in pachetul android.view.ViewGroup.
Adaugarea instructiunilor anterioare, inainte de apelul setContentView() , vom obtine interfata dorita pentru aplicatia Android:
Cum se defineste interfata Android intr-un mod declarativ
Limbajele de programare si instrumentele de dezvoltare au evoluat pentru a permite programatorilor sa dezvolte aplicatii mai complexe si sa se concentreze asupra functionalitatii solutiei, asupra arhitecturii si mai putin asupra scrierii codului. Interfata cu utilizatorul reprezinta o componenta importanta a aplicatiei, dar nucleul si functionalitatea este data de codul sursa din spatele ei. Fara acesta, interfata cu utilizatorul este inutila, deoarece nu face nimic.
Designul declarativ al interfetei, pentru aplicatii Android, este bazata pe limbajul descriptiv XML (asemanator XHTML sau HTML), care poate fi usor de citit si de inteles de catre programatori cu putine cunostinte pe platforma Android. În ciuda posibilitatii de a folosi cod pentru a proiecta interfata, este recomandat sa utilizati abordare declarativa sau descriptiva, deoarece:
arhitectura interfetei aplicatiei Android este arborescenta; radacina este reprezentata de un element ViewGroup iar elementele de tip widget-uri descriu frunzele acestei structuri; relatia parinte-copil dintre elemente si elementul radacina unic sunt conditii care permit utilizarea de fisiere XML (acestea au o structura arborescenta cu reguli identice);
fisierul XML poate fi editat cu un editor de text simplu iar sintaxa este foarte simpla in comparatie cu limbajul Java;
nu necesita cunostinte de programare in Java;
fiecare clasa Java folosita pentru layout si widget-uri are un echivalent reprezentat de un element XML (cu foarte putine exceptii); cum limbajul XML este case-sensitive ca si Java, elementele au nume identic cu clasele (de exemplu clasa Java, TextView are echivalenul <TextView>);
documentatia API-ului Android descrie atât clasele cat si elementele XML;
proprietatile obiectelor sunt definite folosind atribute XML cu forma android::property_name = “valoare”;
aveti posibilitatea sa modificati design-ul bazat pe XML, fara a recompila codul sursa; fisierele XML sunt preprocesate intr-un format binar comprimat, dar acest lucru poate fi realizat independent de compilarea codului sursa.
Fisierele XML care contin descrierea interfetei sunt plasate in subdirectorul \res\layout\ din proiectul Android (pentru o descriere detaliata a componentelor proiectului Android cititi Tutorial Android (03) – Cum sa dezvolti, testezi si sa intelegi o aplicatie de tip Hello World si Android Tutorial (02) – Concepte, activitati si resurse ale unei aplicatii Android).
Pentru un proiect initial Android, plugin-ul Eclipse ADT genereaza un layout initial, care este descris in fisierul main.xml din subdirectorul \res\aspect\. De asemenea, o instructiune din metoda supradefinita onCreate () seteaza pentru ecranul principal aspectul definit in main.xml.
//R este clasa ce contine ID-urile pentru resurse setContentView(R.layout.main);
Forma initiala generata de plugin-ul Eclipse este:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout>
Prima declaratie este o informatie necesara pentru un document XML.Atributul encoding defineste setul de caractere utilizat in documentul XML.
Citind documentul main.xml este usor sa observi ca ecranul este definit printr-un LinearLayout cu o orientare verticala care umple ecranul si care contine un element TextView.
Pentru a modifica intr-un mod declarativ aplicatia Android propusa (descrisa de prima imagine) trebuie sa editam fisierul main.xml. Acest lucru poate fi realizat in Eclipse folosind fie editorul vizual (Graphical Layout) fie editorul de text XML.
Editorul grafic al layout-ului (Graphical Layout) a evoluat si a devenit un instrument foarte util pentru proiectarea rapida interfetei. Insa pentru a stabili valorile proprietatilor este mai rapida abordarea bazata pe editorul de text XML, care are un meniu contextual inteli-sense activat cu Ctrl + Space. În acest exemplu simplu, vom folosi editorul de text.
Un alt document XML important este strings.xml din subdirectorul \res\values\ (Tutorial Android (03) – Cum sa dezvolti, testezi si sa intelegi o aplicatie de tip Hello World si Android Tutorial (02) – Concepte, activitati si resurse ale unei aplicatii Android). Initial, fisierul contine doua valori de tip sir de caractere, hello si app_name. A doua valoare reprezinta textul din bara de titlu a ferestrei principale.
strings.xml NU este utilizat doar de designul declarativ al interfetei. Este o resursa globala pentru proiectul Android si elementele sale pot fi referite din codul sursa Java si din documente XML pentru layout.
Atentie! Atributele android: layout_width
si android:layout_height
sunt obligatorii pentru orice widget si layout ViewGroup
. Fara unul dintre ele veti obtine o exceptie RuntimeException
.
1. Deschideti documentatia pachetului android.widget si resetati fisierul main.xml stergand layout-ul generat; deoarece nu afecteaza interfata si este o informatie specifica XML lasati prima declaratie:
<?xml version="1.0" encoding="utf-8"?>
2. Ca si in cazul abordarii procedurale, prima modificare a solutiei este schimbarea textului din bara de titlu a ferestrei principale. Acest lucru se realizeaza prin modificarea elementului app_name din fisierul strings.xml. Stabilim “First Android Application” ca noua valoare.
Atunci cand editati fisierul layout XML in editorul de text Eclipse (NU editorul Graphical Layout) utilizati meniul inteli-sens contextual si functia de autocomplete. Meniul contextual este activat cu Ctrl + Space si este de foarte mare ajutor deoarece sugereaza posibile atribute si valori.
3. In fisierul main.xml (al carui continut a fost sters la pasul 1) vom defini nodul radacina, care este un layout liniar cu o orientare verticala. Atributul xmlns:android =”http://schemas.android.com/apk/res/android” este o informatie obligatorie pe platforma Android, deoarece aceasta defineste namespace-ul XML pentru Android.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
Comparativ cu declaratiile Java din soluţia programatica, atributele care definesc latimea si inaltimea layout-ului, sunt necesare pentru elementul . Fara ele, veti obţine un RuntimeException.
4. In layout-ul liniar vom adauga un element de tip TextView. Cele mai bune practici Android cu privire la utilizarea valorilor constante recomanda utilizarea fisierelor XML din directorul \res\values\ (string.xml pentru valori String constante) pentru definirea acestora. Aceste valori pot fi accesate in mod direct din codul sursa, asa cum am facut in abordarea procedurala apeland metoda setText(), sau din fisierul XML asociat layout-ului. Deci, vom pune valoarea TextView-ului direct in descrierea din main.xml, folosind android:attribut text. Pentru definirea dimensiunii textului vom folosi atributul android:textSize. Pentru font si stil folosim android:typeface si android:textStyle. Culoarea textului este setata folosind atributul android:textColor si o valoare #RGB. Nu uitati sa setati atributele layout_width si layout_height. Deoarece ne dorim ca textul sa ocupe un spatiu vizibil egal cu continutul sau, stabilim valoarea wrap_content pentru cele doua atribute.
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World Android !" android:textSize="20px" android:textColor="#0f0" android:typeface="sans" android:textStyle="bold|italic" />
5. Pentru a adauga un buton la aspectul liniar, in interiorul elementului<LinearLayout> … </ LinearLayout> vom defini un element <Button> care are valoarea “Click me !” pentru atributul android:text. Nu uitati sa setati atributele layout_width si layout_height. Pentru buton stabilim latimea, atributul layout_width, la 120 pixeli.
<Button android:layout_width="120px" android:layout_height="wrap_content" android:text="Click me !" />
6. In mod implicit, orice widget definit in fisierul main.xml sau alt layout, va fi afisat atunci când layout-ul este incarcat. In comparatie cu abordarea programatica nu trebuie facut altceva pentru a le adauga pe display (in solutie programatica se construieste instanta si se adauga cu addView() in layout).
7. Pentru a gestiona pozitia (pe ambele axe, verticala si orizontala) continutului in interiorul layout-ului este folosit atributul android:layout_gravity. Acest atribut utilizeaza ca valori o combinatie de constante predefinite ce sunt separate prin | (SAU logic). Pentru combinatia “center_vertical | center_horizontal” centram continutul layout-ului pe verticala si pe orizontala:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" >
8. Incarcam layout-ul pentru a fi afisat de Activitatea. Acest lucru se face in metoda onCreate() din clasa derivata din Activity prin apelul metodei setContentView():
Daca rulati aplicatia Android ar trebui sa obtineti acelasi display ca cel generat programatic in prima sectiune a acestui articol.
Design procedural vs. declarativ de interefete Android
Aceasta ultima comparatie a celor doua abordari va poate ajuta sa trageti propriile concluzii cu privire la avantajele si posibilitatile fiecarei metode utilizata pentru a proiecta interfata cu utilizatorul a aplicatiilor mobile Android:
Design Procedural al interfetei Android
Design Programatic al interfetei Android
- utilizand cod sursa Java in metoda
onCreate()
a claseiActivity
- definind element XML in fisierul
main.xml
din subdirectorul\res\layout\
al proiectului Android
//definire text din title bar this.setTitle( "First Android Application");
editarea elementului
<string name="app_name"> First Android Application </string>
in fisierul strings.xml al proiectului
//definire layout iniar LinearLayout mainLayout; mainLayout = new LinearLayout(this); //center the content mainLayout.setGravity( Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); //set vertical orientation mainLayout.setOrientation(1);
<LinearLayout xmlns:android="http://schemas.android.com/..." android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity= "center_vertical|center_horizontal" > </LinearLayout> * – elementul xmlns:android este afisat partial
TextView txtInfo = new TextView(this); txtInfo.setText( "Hello World Android !"); //definire LayoutParams //width - egala cu continutul //height - egala cu continutul LinearLayout.LayoutParams txtLayoutParams = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //setare LayoutParams txtInfo.setLayoutParams( txtLayoutParams); txtInfo.setTextSize(20); txtInfo.setTypeface( Typeface.SANS_SERIF, Typeface.BOLD_ITALIC); txtInfo.setTextColor(Color.GREEN);
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World Android !" android:textSize="20dp" android:textColor="#0f0" android:typeface="sans" android:textStyle="bold|italic" />
Button btnClick = new Button(this); //definire text buton btnClick.setText( "Click me !"); //definire LayoutParams //width - 120 px //height - egala cu continutul LinearLayout.LayoutParams btnLayoutParams = new LinearLayout.LayoutParams( 120, ViewGroup.LayoutParams.WRAP_CONTENT ); //setare LayoutParams btnClick.setLayoutParams(btnLayoutParams);
<Button android:layout_width="120px" android:layout_height="wrap_content" android:text="Click me !" />
//adaugare controale la layout mainLayout.addView(txtInfo); mainLayout.addView(btnClick);
definirea elementelor <TextView>
si <Button>
intre <LinearLayout>
si </LinearLayout>
//definire layout pentru activitate this.setContentView(mainLayout);
//definire layout pentru activitate this.setContentView(R.layout.main);
Alte subiecte care fac parte din acest tutorial Android sunt accesibile prin intermediul articolului Tutorial Android – Descriere si cuprins.
Daca ai probleme cu exemplele sau crezi ca nu ai inteles elementele descrise, pune o intrebare in zona de comentarii si iti vom raspunde imediat. De asemenea, orice sugestie sau obervatie care duce la imbunatatirea materialului este bine venita.
Daca ti-a placut sau ti-a fost util acest tutorial atunci spune-le si altora despre el sau arunca-ti o privire pe reclamele din aceasta pagina. Referirea acestui material este cel mai bun mod de a aprecia autorul.
Comments are closed.