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.
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.
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.
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.
Î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.
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.
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 boolean
, culoare
, dimensiune
, enum
, întreg
, pluti
ș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ă.
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 (SparseArraycontainer) // 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);
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.