Crearea de vizualizări compuse pe Android

Atunci când construiți aplicații complexe, veți dori adesea să reutilizați același grup de vizualizări în diferite locuri ale aplicației. O modalitate de a rezolva această problemă este crearea unei vizualizări care încapsulează logica și aspectul unui grup de vizualizări, astfel încât să le puteți reutiliza fără a copia codul în diferite locuri ale proiectului. În acest tutorial, veți învăța cum să utilizați vederi combinate pentru a crea vizionări personalizate ușor de reutilizat.

1. Introducere

Pe Android, o vizualizare compusă dintr-un grup de vizualizări se numește vizualizare combinată sau o componentă complexă. În acest tutorial, veți construi un control pentru a selecta o valoare dintr-o listă care derulează de la o latură în alta. Vom numi compusul un spinner lateral, deoarece vizualizarea implicită a SDK Android pentru a alege o valoare dintr-o listă se numește spinner. Următorul ecran ilustrează ceea ce vom crea în acest tutorial.

2. Configurarea proiectului

Pentru a începe, trebuie să creați un nou proiect Android cu versiunea Android 4.0 ca nivel minim SDK necesar. Acest proiect ar trebui să conțină doar o activitate goală numită Activitate principala. Activitate nu are nimic altceva decât inițializarea aspectului, după cum puteți vedea în fragmentul de cod următor.

clasa publica MainActivity extinde Activitatea @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); 

Structura pentru Activitate principala este situat în /res/layout/activity_main.xml fișier și ar trebui să conțină numai un gol RelativeLayout în care vizualizarea compusului va fi afișată mai târziu.

 

3. Creați o vizualizare compus

Pentru a crea o vizualizare combinată, trebuie să creați o clasă nouă care să gestioneze vizualizările în vizualizarea compus. Pentru spinnerul lateral, aveți nevoie de două Buton vizualizări pentru săgeți și a TextView pentru a afișa valoarea selectată.

Pentru a începe, creați /res/layout/sidespinner_view.xml fișierul de dispunere pe care îl vom folosi pentru clasa spinner laterală, asigurându-vă că ambalați cele trei vederi într-o  etichetă.

 

Apoi, trebuie să creați SideSpinner clasa care umple acest aspect și stabilește săgețile ca imagini de fundal pentru butoane. În acest moment, aspectul compus nu face nimic, deoarece nu există nimic de arătat încă.

clasa publica SideSpinner extinde LinearLayout butonul privat Button mPreviousButton; butonul privat mNextButton; public SideSpinner (Context context) super (context); initializeViews (context);  Public SideSpinner (Context context, AttributeSet attrs) super (context, attrs); initializeViews (context);  public SideSpinner (Context context, AttributeSet attrs, int defStyle) super (context, attrs, defStyle); initializeViews (context);  / ** * Infuzează vizualizările în aspect. * * @param context * contextul curent pentru vizualizare. * / void private initializeViews (Context context) LayoutInflater inflater = (LayoutInflater) context .getSystemService (Context.LAYOUT_INFLATER_SERVICE); inflater.inflate (R.layout.sidespinner_view, acest lucru);  @Override protejate void onFinishInflate () super.onFinishInflate (); // Setează imaginile pentru butoanele anterioare și următoare. Utilizează // imaginile încorporate astfel încât să nu fie nevoie să adăugați imagini, dar într-o aplicație reală imaginile ar trebui să fie în pachetul de aplicații // astfel încât acestea să fie întotdeauna disponibile. mPreviousButton = (buton) acest .findViewById (R.id.sidespinner_view_previous); mPreviousButton .setBackgroundResource (android.R.drawable.ic_media_previous); mNextButton = (buton) acest .findViewById (R.id.sidespinner_view_next); mNextButton .setBackgroundResource (android.R.drawable.ic_media_next); 

Veți observa că vizualizarea combinată extinde LinearLayout vizualizați grupul. Aceasta înseamnă că orice aspect care utilizează vizualizarea compus are acces la atributele layout-ului liniar. Ca rezultat, aspectul pentru vizualizarea compus este un pic diferit de obicei, tag-ul root este a  în loc de eticheta pentru un grup de vizualizare ca  sau .

Când adăugați vizualizarea combinată la aspectul Activitate principala, eticheta pentru vizualizarea compus va acționa ca o  etichetă. O clasă de vizualizare combinată poate deriva din orice clasă care derivă din ViewGroup, dar în acest caz aspectul liniar este cel mai potrivit, deoarece vederile sunt planificate orizontal.

4. Adăugați Vizualizarea Compus într-un Layout

În acest moment, proiectul se compilează dar nimic nu este vizibil, deoarece imaginea compus nu este în aspectul Activitate principala. Vederea de tip spinner lateral trebuie adăugată la aspectul activității ca orice altă vizualizare. Numele etichetei este numele complet al SideSpinner clasa, inclusiv spațiul de nume.

Pentru a adăuga spinnerul lateral la Activitate principala, adăugați următoarele la aspectul relativ din /res/layout/activity_main.xml fişier.

Atributele disponibile în eticheta sunt atributele layoutului liniar de la SideSpinner clasa pe care am creat-o extinde LinearLayout clasă. Dacă lansați proiectul, partea spinner trebuie să fie vizibilă, dar nu conține încă valori.

5. Adăugați metode pentru Vizualizarea compusului

Există încă câteva lucruri care lipsesc dacă vrem să folosim de fapt spinnerul lateral. Ar trebui să adăugăm noi valori spinnerului, să selectăm o valoare și să obținem valoarea selectată.

Cea mai ușoară modalitate de a adăuga comportamente noi la o vizualizare combinată este adăugarea de noi metode publice la SideSpinner clasă. Aceste metode pot fi utilizate de oricare Activitate care are o referință la vedere.

CharSequence privat [] mSpinnerValues ​​= null; private int mSelectedIndex = -1; / ** * Setează lista de valori în spinner, selectând prima valoare * în mod implicit. * * @param values ​​* valorile de setat în spinner. * / void setValues ​​public (valorile CharSequence []) mSpinnerValues ​​= valori; // Selectați primul element al matricei de șir implicit din moment ce // lista de valori sa schimbat. setSelectedIndex (0);  / ** * Setează indexul selectat al rotorului. * * @ param index * indicele valorii pe care o selectați. * / void publice setSelectedIndex (int index) // Dacă nu sunt setate valori pentru spinner, nu faceți nimic. dacă (mSpinnerValues ​​== null || mSpinnerValues.length == 0) retur; // Dacă valoarea indexului este nevalidă, nu faceți nimic. dacă (index < 0 || index >= mSpinnerValues.length) retur; // Setați indexul curent și afișați valoarea. mSelectedIndex = index; TextView currentValue; curentValue = (TextView) acest .findViewById (R.id.sidespinner_view_current_value); currentValue.setText (mSpinnerValues ​​[index]); // Dacă este afișată prima valoare, ascundeți butonul anterior. dacă (mSelectedIndex == 0) mPreviousButton.setVisibility (INVISIBLE); altceva mPreviousButton.setVisibility (VISIBLE); // Dacă este afișată ultima valoare, ascundeți următorul buton. dacă (mSelectedIndex == mSpinnerValues.length - 1) mNextButton.setVisibility (INVISIBLE); altceva mNextButton.setVisibility (VISIBLE);  / ** * Obține valoarea selectată a rotorului, sau null dacă nu este setat încă un index valid * selectat. * * @ reveniți la valoarea selectată a rotorului. * / CharSequence public getSelectedValue () // Dacă nu sunt setate valori pentru spinner, returnați un șir gol. dacă (mSpinnerValues ​​== null || mSpinnerValues.length == 0) returnați ""; // Dacă indexul curent este nevalid, returnați un șir gol. dacă (mSelectedIndex < 0 || mSelectedIndex >= mSpinnerValues.length) returnați ""; retur mSpinnerValues ​​[mSelectedIndex];  / ** * Obține indexul selectat al rotorului. * * @ întoarceți indexul selectat al rotorului. * / public int getSelectedIndex () retur mSelectedIndex; 

onFinishInflate metoda de vizualizare combinată se numește atunci când toate vederile din plan sunt umflate și gata de utilizare. Acesta este locul unde puteți adăuga codul dvs. dacă doriți să modificați afișările în vizualizarea compus.

Cu metodele pe care tocmai le-ați adăugat la SideSpinner clasa, comportamentul pentru butoanele care selectează valoarea anterioară și următorul poate fi acum adăugat. Înlocuiți codul existent în onFinishInflate cu următoarele metode:

@Override protejat void onFinishInflate () // Când controalele din layout se fac umflate, setați // apelurile de apel pentru săgețile laterale. super.onFinishInflate (); // Când apăsați butonul anterior, selectați valoarea precedentă // din listă. mPreviousButton = (buton) acest .findViewById (R.id.sidespinner_view_previous); mPreviousButton .setBackgroundResource (android.R.drawable.ic_media_previous); mPreviousButton.setOnClickListener (noul OnClickListener () public void onClick (Vizualizare vizualizare) if (mSelectedIndex> 0) int newSelectedIndex = mSelectedIndex - 1; setSelectedIndex (newSelectedIndex);); // Când apăsați următorul buton, selectați următorul element din lista //. mNextButton = (buton) acest .findViewById (R.id.sidespinner_view_next); mNextButton .setBackgroundResource (android.R.drawable.ic_media_next); mNextButton.setOnClickListener (noul OnClickListener () public void onClick (Vizualizare vizualizare) if (mSpinnerValues! = null && mSelectedIndex < mSpinnerValues.length - 1)  int newSelectedIndex = mSelectedIndex + 1; setSelectedIndex(newSelectedIndex);   ); // Select the first value by default. setSelectedIndex(0); 

Cu noul creat setValues și setSelectedIndex metode, putem inițializa spinner-ul lateral din codul nostru. Ca și în cazul oricărei alte vizualizări, trebuie să găsiți vizualizarea laterală în planul cu findViewById metodă. Apoi, putem apela orice metodă publică pe vizualizare din obiectul returnat, inclusiv pe cele pe care tocmai le-am creat.

Următorul fragment de cod arată cum să actualizați onCreate metodă a Activitate principala pentru a afișa o listă de valori în spinnerul lateral, folosind setValues metodă. De asemenea, putem selecta a doua valoare din listă în mod implicit invocând setSelectedIndex metodă.

clasa publica MainActivity extinde Activitatea @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Inițializează spinner-ul lateral din cod. Fructe SideSpinnerSpinner; fruitsSpinner = (SideSpinner) acest .findViewById (R.id.sidespinner_fruits); CharSequence fruitList [] = "Apple", "Orange", "Pear", "Struguri"; fruitsSpinner.setValues ​​(fruitList); fruitsSpinner.setSelectedIndex (1); 

Dacă lansezi aplicația, partea spinner trebuie să funcționeze conform așteptărilor. Este afișată lista de valori și valoarea portocale este selectat în mod implicit.

6. Adăugați atribute de aspect în Vizualizarea compus

Vizualizările disponibile în SDK-ul Android pot fi modificate prin cod, dar unele atribute pot fi, de asemenea, setate direct în aspectul corespunzător. Să adăugăm un atribut spinner-ului lateral, care stabilește valorile pe care trebuie să le afișeze spinner-ul lateral.

Pentru a crea un atribut personalizat pentru vizualizarea compus, trebuie mai întâi să definim atributul în /res/values/attr.xml fişier. Fiecare atribut al vizualizării compuse trebuie grupat într-un stil cu a etichetă. Pentru spinnerul lateral, numele clasei este folosit așa cum se arată mai jos.

    

În  eticheta, Nume atributul conține identificatorul folosit pentru a se referi la noul atribut din layout și format atributul conține tipul atributului nou.

Pentru lista valorilor, referinţă este utilizat deoarece atributul se referă la o listă de șiruri de caractere definite ca o resursă. Tipurile de valoare care sunt utilizate în mod normal în layouts pot fi utilizate pentru atributele personalizate, inclusiv booleanculoaredimensiuneenumîntregpluti și şir.

Iată cum se definește resursa pentru o listă de șiruri de caractere valorile atributul spinner-ului lateral se va referi la. Acesta trebuie adăugat la /res/values/strings.xml fișier după cum se arată mai jos.

  Castravete Cartof Roșie Ceapă Suc de fructe  

Pentru a testa noul valorile atribut, creați o vedere laterală spinner în Activitate principala aspect sub partea de spinner existentă. Atributul trebuie să fie prefixat cu un spațiu de nume adăugat la RelativeLayout, precum xmlns: sidespinner = "http://schemas.android.com/apk/res-auto". Acesta este aspectul final din /res/layout/activity_main.xml ar trebui să arate ca.

   

În cele din urmă, SideSpinner clasa trebuie modificată pentru a citi textul valorile atribut. Valoarea fiecărui atribut al vizualizării este disponibilă în AttributeSet obiect care este trecut ca parametru al constructorului vizualizării.

Pentru a obține valoarea obiceiului dvs. valorile atribut, suntem primul apel obtainStyledAttributes metodă a AttributeSet obiect cu numele stilului care conține atributul. Aceasta returnează lista de atribute pentru acel stil ca a TypedArray obiect.

Apoi vom numi metoda getter a TypedArray obiect care are tipul corect pentru atributul dorit, trecând identificatorul atributului ca parametru. Următorul bloc de coduri arată modul de modificare a constructorului dispozitivului de împingere laterală pentru a obține lista de valori și a le seta în spinnerul lateral.

public SideSpinner (Context context) super (context); initializeViews (context);  Public SideSpinner (Context context, AttributeSet attrs) super (context, attrs); TypedArray typedArray; typedArray = contextul .obtainStyledAttributes (attrs, R.styleable.SideSpinner); mSpinnerValues ​​= tastatArray .getTextArray (R.styleable.SideSpinner_values); typedArray.recycle (); initializeViews (context);  public SideSpinner (Context context, AttributeSet attrs, int defStyle) super (context, attrs, defStyle); TypedArray typedArray; typedArray = contextul .obtainStyledAttributes (attrs, R.styleable.SideSpinner); mSpinnerValues ​​= tastatArray .getTextArray (R.styleable.SideSpinner_values); typedArray.recycle (); initializeViews (context); 

Dacă lansați aplicația, ar trebui să vedeți două rotitoare laterale care funcționează independent una de cealaltă.

7. Salvați și restaurați starea

Ultimul pas pe care trebuie să-l finalizăm este salvarea și restabilirea stării vizualizării complexe. Atunci când o activitate este distrusă și recreată, de exemplu, atunci când dispozitivul este rotit, valorile vederilor native cu un identificator unic sunt salvate și restaurate automat. Acest lucru nu este în prezent valabil pentru spinnerul lateral.

Starea opiniilor nu este salvată. Identificatorii opiniilor din SideSpinner clasa nu este unică, deoarece poate fi refolosită de mai multe ori. Aceasta înseamnă că suntem responsabili pentru salvarea și restaurarea valorilor vizualizărilor în vizualizarea compus. Facem acest lucru prin implementarea onSaveInstanceState, onRestoreInstanceState, și dispatchSaveInstanceState metode. Următorul bloc de coduri arată cum se face acest lucru pentru spinnerul lateral.

/ ** * Identificator pentru statul care salvează indexul selectat de * spinnerul lateral. * / String static privat STATE_SELECTED_INDEX = "SelectedIndex"; / ** * Identificator pentru starea super clasa. * / String static privat STATE_SUPER_CLASS = "SuperClass"; @Override protejat Parcelable onSaveInstanceState () Bundle Bundle = Bundle nou (); bundle.putParlabilă (STATE_SUPER_CLASS, super.onSaveInstanceState ()); bundle.putInt (STATE_SELECTED_INDEX, mSelectedIndex); pachet de returnare;  @Override protejat void onRestoreInstanceState (Stare parcelabilă) if (instanță de Bundle) Bundle Bundle = (Bundle) de stat; super.onRestoreInstanceState (bundle .getParcelable (STATE_SUPER_CLASS)); setSelectedIndex (bundle.getInt (STATE_SELECTED_INDEX));  altceva super.onRestoreInstanceState (state);  @Override protejate void dispatchSaveInstanceState (SparseArray container) // Asigură-te că starea copilului din ecranul // spinner nu este salvată din moment ce rezolvăm starea în // onSaveInstanceState. super.dispatchFreezeSelfOnly (container);  @Override protejate void dispatchRestoreInstanceState (SparseArray container) // Asigură faptul că starea copilului din partea laterală a spinner-ului nu este restabilită, deoarece vom gestiona starea din // onSaveInstanceState. super.dispatchThawSelfOnly (container); 

Concluzie

Spinătorul lateral este acum complet. Ambele rotoare laterale funcționează conform așteptărilor și valorile lor sunt restabilite dacă activitatea este distrusă și recreată. Acum puteți aplica ceea ce ați învățat pentru a reutiliza orice grup de vizualizări într-o aplicație Android utilizând vizualizări compuse.

Cod