Trucuri de machetare: Fuzionarea machetelor

Articolele v-au arătat cum să folosiți tag-ul <include /> în machetele XML, pentru a reutiliza și partaja codul de machetare. Acest articol explică tag-ul <merge /> și modul în care acesta completează tag-ul <include />.

Tag-ul <merge /> a fost creat cu scopul de aoptimiza machetele Android prin reducerea numărului de niveluri în arborii de vizualizare. Estemai ușor de înțeles problema pe care o rezolvă această etichetă analizând un exemplu. Următorul aspect XML declară un aspect care afișează o imagine cu titlul acesteia deasupra. Structura este destul de simplă; un FrameLayout este folosit pentru a suprapune un TextView peste un ImageView:

<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>

Acest layout se redă frumos și nu pare să aibă nimic în neregulă:

Un FrameLayout este folosit pentru a suprapune un titlu peste o imagine

Lucrurile devin mai interesante atunci când inspectați rezultatul cu HierarchyViewer. Dacă vă uitați cu atenție la arborele rezultat, veți observa că FrameLayout definit în fișierul nostru XML (evidențiat în albastru mai jos) este singurul copil al unui alt FrameLayout:

Un layout cu un singur copil de aceleași dimensiuni poate fi eliminat

Din moment ce FrameLayout al nostru are aceeași dimensiune ca și părintele său, în virtutea folosirii constrângerilor fill_parent, și nu definește nici un fundal, nici o umplutură suplimentară sau o gravitație, el este total inutil. Nu am făcut decât să facem mai complexă interfața utilizator fără niciun motiv întemeiat. Dar cum am putea să scăpăm de acest FrameLayout? La urma urmei, documentele XML au nevoie de o etichetă rădăcină, iar etichetele din machetele XML reprezintă întotdeauna instanțe de vizualizare.

Acesta este locul unde eticheta <merge /> este utilă. Atunci cândLayoutInflater întâlnește această etichetă, o sare și adaugă copiii <merge /> la <merge />părintele <merge />. Sunteți confuz? Să rescriem layout-ul nostru XML anterior înlocuindFrameLayout cu <merge />:

<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>

Cu această nouă versiune, atât TextView cât și ImageView vor fi adăugate direct la nivelul superiorFrameLayout. Rezultatul va fi același din punct de vedere vizual, dar ierarhia vizualizărilor este mai simplă:

Hierarhia vizualizărilor optimizată prin utilizarea tag-ului de fuziune

Evident, utilizarea <merge /> funcționează în acest caz deoarece părintele vizualizării conținutului unei activități este întotdeauna un FrameLayout. Nu ați putea aplica acest truc dacă layout-ul dvs. ar folosi un LinearLayout ca etichetă rădăcină, de exemplu. Totuși, <merge /> poate fi util în alte situații. De exemplu, funcționează perfect atunci când este combinat cu tagul<include />. De asemenea, puteți utiliza <merge/> atunci când creați o vizualizare compozită personalizată. Să vedem cum putem folosi acest tag pentru a crea o nouă vizualizare numită OkCancelBar care afișează pur și simplu două butoane cu etichete personalizabile. Puteți descărca, de asemenea, codul sursă complet al acestui exemplu. Iată XML-ul folosit pentru a afișa această vizualizare personalizată deasupra unei imagini:

<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>

Acest nou aspect produce următorul rezultat pe un dispozitiv:

Crearea unei vizualizări personalizate cu ajutorul tag-ului de îmbinare

Codul sursă al lui OkCancelBar este foarte simplu deoarece cele două butoane sunt definite într-un fișier XML extern, încărcat cu ajutorul unuiLayoutInflate. După cum puteți vedea în următorul fragment, XMLlayout-ul este umflat cuOkCancelBar ca părinte:

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(); }}

Cele două butoane sunt definite în următorul layout XML. După cum puteți vedea, folosim tagul <merge /> pentru a adăuga cele două butoane direct la OkCancelBar. Fiecare buton este inclus din același fișier XMLlayout extern pentru a fi mai ușor de întreținut; pur și simplu le suprascriem id-ul:

<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>

Am creat o vizualizare personalizată flexibilă și ușor de întreținut care generează o ierarhie de vizualizare eficientă:

Hierarhia rezultată este simplă și eficientă

Eticheta <merge /> este extrem de utilă și poate face minuniîn codul dumneavoastră. Cu toate acestea, suferă de câteva limitări:

  • <merge /> poate fi folosită doar ca etichetă rădăcină a unui layout XML
  • Când umflați un layout care începe cu un <merge />, trebuie să specificați un părinte ViewGroup și trebuie să setați attachToRoot la true (consultați documentația pentru metoda inflate(int, android.view.ViewGroup, boolean))

.

Leave a Reply