Layout trucs: Layouts samenvoegen
De artikelen lieten u zien hoe u de <include />
tag in XML layouts kunt gebruiken, om uw lay-out code te hergebruiken en te delen. Dit artikel legt de <merge />
-tag uit en hoe deze de <include />
-tag aanvult.
De <merge />
-tag is in het leven geroepen om Android lay-outs te optimaliseren door het aantal niveaus in weergavebomen te verminderen. Het is eenvoudiger om het probleem dat deze tag oplost te begrijpen door naar een voorbeeld te kijken. De volgende XML layout declareert een layout die een afbeelding toont met de titel erbovenop. De structuur is vrij eenvoudig; een FrameLayout
wordt gebruikt om een TextView
bovenop een ImageView
te stapelen:
<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>
Deze layout rendert mooi en er lijkt niets mis mee:
Het wordt interessanter als je het resultaat met HierarchyViewer bekijkt. Als u goed naar de resulterende boom kijkt, zult u zien dat deFrameLayout
die in ons XML-bestand is gedefinieerd (hieronder in blauw gemarkeerd) het enige kind is van een andere FrameLayout
:
Omdat onze FrameLayout
dezelfde afmetingen heeft als zijn ouder, dankzij het gebruik van de fill_parent
-restricties, en geen achtergrond, extra opvulling of een zwaartekracht definieert, is hij volkomen nutteloos. We hebben alleen de UI complexer gemaakt zonder goede reden. Maar hoe kunnen we van deze FrameLayout
afkomen? Tenslotte hebben XML documenten een root tag nodig en tags in XML layouts vertegenwoordigen altijd view instances.
Daar komt de <merge />
tag van pas. Als deLayoutInflater
deze tag tegenkomt, slaat hij hem over en voegt de <merge />
-kinderen toe aan de <merge />
-ouder. In de war? Laten we onze vorige XML layout herschrijven door deFrameLayout
te vervangen door <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>
Met deze nieuwe versie worden zowel de TextView
als deImageView
direct toegevoegd aan de top-levelFrameLayout
. Het resultaat zal visueel hetzelfde zijn, maar de viewhiërarchie is eenvoudiger:
Het is duidelijk dat het gebruik van <merge />
in dit geval werkt, omdat de ouder van een inhoudsweergave van een activiteit altijd een FrameLayout
is. U zou deze truc niet kunnen toepassen als uw layout bijvoorbeeld een LinearLayout
als root-tag zou gebruiken. De <merge />
kan echter ook in andere situaties nuttig zijn. Hij werkt bijvoorbeeld perfect in combinatie met de tag<include />
. U kunt <merge/>
ook gebruiken wanneer u een aangepaste samengestelde view maakt. Laten we eens kijken hoe we deze tag kunnen gebruiken om een nieuwe view te maken met de naam OkCancelBar
die eenvoudigweg twee knoppen laat zien met aanpasbare labels. Je kunt ook de complete broncode van dit voorbeeld downloaden. Dit is de XML die wordt gebruikt om deze aangepaste weergave bovenop een afbeelding weer te geven:
<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>
Deze nieuwe opmaak levert het volgende resultaat op een apparaat:
De broncode van OkCancelBar
is heel eenvoudig omdat de twee knoppen zijn gedefinieerd in een extern XML-bestand, dat wordt geladen met eenLayoutInflate
. Zoals u in het volgende fragment kunt zien, wordt de XML-layout R.layout.okcancelbar
opgeblazen met deOkCancelBar
als ouder:
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(); }}
De twee knoppen zijn gedefinieerd in de volgende XML-layout. Zoals u kunt zien, gebruiken we de <merge />
tag om de twee knoppen direct aan deOkCancelBar
toe te voegen. Elke knop is opgenomen in hetzelfde externe XMLlayout-bestand om ze gemakkelijker te kunnen onderhouden; we overschrijven gewoon hun 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>
We hebben een flexibele en gemakkelijk te onderhouden aangepaste view gemaakt die een efficiënte view-hiërarchie genereert:
De <merge />
tag is uiterst nuttig en kan wonderen doen in uw code. Hij heeft echter te lijden onder een paar beperkingen:
-
<merge />
kan alleen worden gebruikt als de root-tag van een XML-lay-out - Wanneer u een lay-out opblaast die begint met een
<merge />
, moet u een parentViewGroup
opgeven en moet uattachToRoot
instellen optrue
(zie de documentatie voor de methodeinflate(int, android.view.ViewGroup, boolean)
)
Leave a Reply