Layout Tricks: Merging Layouts

Artikkeleissa näytettiin, miten voit käyttää <include />-tagia XML-layouteissa, uudelleenkäyttää ja jakaa layout-koodia. Tässä artikkelissa selitetään <merge />-tunniste ja miten se täydentää <include />-tunnistetta.

<merge />-tunniste luotiin optimoimaan Android-asetteluja vähentämällä näkymäpuiden tasojen määrää. On helpompi ymmärtää ongelma, jonka tämä tagi ratkaisee, tarkastelemalla esimerkkiä. Seuraava XML-asettelu ilmoittaa asettelun, joka näyttää kuvan ja sen otsikon sen päällä. Rakenne on melko yksinkertainen; FrameLayout:aa käytetään pinoamaan TextView:aa ImageView:n päälle:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /></FrameLayout>

Tämä asettelu renderöityy hienosti, eikä siinä näytä olevan mitään vikaa:

Ta FrameLayoutia käytetään otsikon asettamiseen kuvan päälle

Tilanteet muuttuvat mielenkiintoisemmiksi, kun lopputulosta tarkastellaan HierarchyViewerilla. Teimme käyttöliittymästä vain monimutkaisemman ilman hyvää syytä. Mutta miten voisimme päästä eroon tästä FrameLayout:stä? Loppujen lopuksi XML-dokumentit vaativat juuritunnisteen ja XML-asettelun tunnisteet edustavat aina näkymäinstansseja.

Tässä kohtaa <merge />-tunniste on kätevä. Kun LayoutInflater kohtaa tämän tagin, se ohittaa sen ja lisää <merge />-lapset <merge />-vanhempaan. Hämmentynyt? Kirjoitetaan edellinen XML-asettelumme uudelleen korvaamalla FrameLayout <merge />:llä:

<merge xmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /></merge>

Tässä uudessa versiossa sekä TextView että ImageView lisätään suoraan ylimmän tasonFrameLayout:een. Lopputulos on visuaalisesti sama, mutta näkymähierarkia on yksinkertaisempi:

Optimoitu näkymähierarkia yhdistämistunnisteen avulla

Näköjään <merge /> käyttäminen toimii tässä tapauksessa, koska aktiviteetin sisältönäkymän vanhempana on aina FrameLayout. Et voisi soveltaa tätä temppua, jos asettelusi käyttäisi esimerkiksi LinearLayouttunnistetta juuritunnisteena. <merge /> voi kuitenkin olla hyödyllinen muissa tilanteissa. Se toimii esimerkiksi täydellisesti yhdistettynä <include />-tagiin. Voit myös käyttää <merge/>-tagia, kun luot mukautetun yhdistetyn näkymän. Katsotaanpa, miten voimme käyttää tätä tagia luodaksemme uuden näkymän nimeltä OkCancelBar, joka yksinkertaisesti näyttää kaksi painiketta muokattavilla merkinnöillä. Voit myös ladata tämän esimerkin täydellisen lähdekoodin. Tässä on XML, jota käytetään tämän mukautetun näkymän näyttämiseen kuvan päällä:

<merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <com.example.android.merge.OkCancelBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:paddingTop="8dip" android:gravity="center_horizontal" android:background="#AA000000" okCancelBar:okLabel="Save" okCancelBar:cancelLabel="Don't save" /></merge>

Tämä uusi asettelu tuottaa laitteessa seuraavan tuloksen:

Kustomoidun näkymän luominen yhdistämistunnisteella

OkCancelBar:n lähdekoodi on hyvin yksinkertainen, koska kaksipainiketta on määritelty ulkoisessa XML-tiedostossa, joka on ladattu LayoutInflate:n avulla. Kuten seuraavasta pätkästä näkyy, XMLlayout R.layout.okcancelbar on paisutettu siten, että OkCancelBar on sen vanhempi:

public class OkCancelBar extends LinearLayout { public OkCancelBar(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); setGravity(Gravity.CENTER); setWeightSum(1.0f); LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0); String text = array.getString(R.styleable.OkCancelBar_okLabel); if (text == null) text = "Ok"; ((Button) findViewById(R.id.okcancelbar_ok)).setText(text); text = array.getString(R.styleable.OkCancelBar_cancelLabel); if (text == null) text = "Cancel"; ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text); array.recycle(); }}

Kaksi painiketta on määritelty seuraavassa XML-asettelussa. Kuten näet, käytämme <merge />-tunnistetta lisätäksemme kaksi painiketta suoraanOkCancelBar:een. Kukin painike sisällytetään samasta ulkoisesta XMLlayout-tiedostosta, jotta niitä olisi helpompi ylläpitää; me yksinkertaisesti ohitamme niiden id:

<merge xmlns:android="http://schemas.android.com/apk/res/android"> <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_ok" /> <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_cancel" /></merge>

Olemme luoneet joustavan ja helposti ylläpidettävän mukautetun näkymän, joka tuottaa tehokkaan näkymähierarkian:

Tuloksena syntyvä hierarkia on yksinkertainen ja tehokas

Tagi <merge /> on erittäin hyödyllinen, ja se voi saada aikaan ihmeitä koodissasi. Sillä on kuitenkin pari rajoitusta:

  • <merge /> voidaan käyttää vain XML-asettelun juuritagina
  • Kun paisutat asettelua, joka alkaa <merge />:llä, sinun on määriteltävä vanhempi ViewGroup ja asetettava attachToRoot true:ksi true:ksi (ks. dokumentaatio inflate(int, android.view.ViewGroup, boolean)-metodista)

Leave a Reply