Layout-Tricks: Merging Layouts
In den Artikeln wurde gezeigt, wie man das <include />
-Tag in XML-Layouts verwendet, um den Layout-Code wiederzuverwenden und weiterzugeben. Dieser Artikel erklärt das <merge />
-Tag und wie es das <include />
-Tag ergänzt.
Das <merge />
-Tag wurde entwickelt, um Android-Layouts zu optimieren, indem die Anzahl der Ebenen in Ansichtsbäumen reduziert wird. Es ist einfacher, das Problem, das dieses Tag löst, anhand eines Beispiels zu verstehen. Das folgende XML-Layout deklariert ein Layout, das ein Bild mit seinem Titel darüber anzeigt. Die Struktur ist recht einfach; ein FrameLayout
wird verwendet, um ein TextView
über ein ImageView
zu stapeln:
<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>
Dieses Layout wird gut gerendert und es scheint nichts falsch zu sein:
Interessanter wird es, wenn man das Ergebnis mit dem HierarchyViewer untersucht. Wenn Sie sich den resultierenden Baum genau ansehen, werden Sie feststellen, dass das in unserer XML-Datei definierte FrameLayout
(unten blau hervorgehoben) das einzige Kind eines anderen FrameLayout
ist:
Da unser FrameLayout
durch die Verwendung der fill_parent
-Einschränkungen die gleiche Dimension wie sein Elternteil hat und keinen Hintergrund, kein zusätzliches Padding oder eine Schwerkraft definiert, ist es völlig nutzlos. Wir haben die Benutzeroberfläche ohne guten Grund nur noch komplexer gemacht. Aber wie könnten wir dieses FrameLayout
loswerden? Schließlich benötigen XML-Dokumente einen Root-Tag, und Tags in XML-Layouts stellen immer Ansichtsinstanzen dar.
Da kommt der <merge />
-Tag gerade recht. Wenn LayoutInflater
auf dieses Tag trifft, überspringt es es und fügt die <merge />
-Kinder zum <merge />
-Elternteil hinzu. Verwirrt? Schreiben wir unser vorheriges XML-Layout neu, indem wir dasFrameLayout
durch <merge />
ersetzen:
<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>
Mit dieser neuen Version werden sowohl das TextView
als auch dasImageView
direkt dem übergeordnetenFrameLayout
hinzugefügt. Das Ergebnis ist optisch dasselbe, aber die Ansichtshierarchie ist einfacher:
Es ist offensichtlich, dass die Verwendung von <merge />
in diesem Fall funktioniert, da das übergeordnete Element der Inhaltsansicht einer Aktivität immer ein FrameLayout
ist. Sie könnten diesen Trick nicht anwenden, wenn Ihr Layout zum Beispiel ein LinearLayout
als Root-Tag verwenden würde. Das <merge />
kann jedoch in anderen Situationen nützlich sein. Zum Beispiel funktioniert es perfekt in Kombination mit dem Tag <include />
. Sie können auch <merge/>
verwenden, wenn Sie eine benutzerdefinierte zusammengesetzte Ansicht erstellen. Sehen wir uns an, wie wir dieses Tag verwenden können, um eine neue Ansicht namens OkCancelBar
zu erstellen, die einfach zwei Schaltflächen mit anpassbaren Beschriftungen anzeigt. Sie können auch den vollständigen Quellcode dieses Beispiels herunterladen. Hier ist der XML-Code, der verwendet wird, um diese benutzerdefinierte Ansicht über einem Bild anzuzeigen:
<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>
Dieses neue Layout führt zu folgendem Ergebnis auf einem Gerät:
Der Quellcode von OkCancelBar
ist sehr einfach, da die beiden Schaltflächen in einer externen XML-Datei definiert sind, die mit einemLayoutInflate
geladen wird. Wie im folgenden Ausschnitt zu sehen ist, wird das XML-Layout R.layout.okcancelbar
mit OkCancelBar
als übergeordnetem Element aufgeblasen:
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(); }}
Die beiden Schaltflächen sind in dem folgenden XML-Layout definiert. Wie Sie sehen können, verwenden wir den <merge />
-Tag, um die beiden Schaltflächen direkt zum OkCancelBar
hinzuzufügen. Jede Schaltfläche ist in derselben externen XML-Layout-Datei enthalten, damit sie leichter zu pflegen sind; wir überschreiben einfach ihre 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>
Wir haben eine flexible und leicht zu pflegende benutzerdefinierte Ansicht erstellt, die eine effiziente Ansichtshierarchie erzeugt:
Das <merge />
-Tag ist äußerst nützlich und kann in Ihrem Code Wunder bewirken. Es leidet jedoch unter einigen Einschränkungen:
-
<merge />
kann nur als Wurzel-Tag eines XML-Layouts verwendet werden - Wenn Sie ein Layout aufblasen, das mit einem
<merge />
beginnt, müssen Sie ein übergeordnetesViewGroup
angeben undattachToRoot
auftrue
setzen (siehe die Dokumentation der Methodeinflate(int, android.view.ViewGroup, boolean)
)
Leave a Reply