Ich habe versucht, genau dies zu tun - ich wollte eine Ansicht, die eine Schaltfläche auf der linken Seite und eine Schaltfläche auf der rechten Seite hatte, aber könnte beliebige Inhalte in der Mitte haben (je nachdem, wer es enthalten war). Im Grunde genommen eine benutzerdefinierte Ansichtsgruppe, die untergeordnete Ansichten im XML-Layout haben könnte und diese untergeordneten Ansichten mit einem anderen XML-Layout umhüllen würde. Hier ist, wie ich es tat:
top_bar.xml: Dies stellt das allgemeine Layout dar, mit dem die Dinge verpackt werden. Beachten Sie das LinearLayout (kann ein beliebiges Layout sein) mit der ID "addChildrenHere" - es wird später referenziert.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topBarLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="left" />
<LinearLayout
android:id="@+id/addChildrenHere"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="right" />
</LinearLayout>
main.xml: Das Hauptlayout. Es enthält eine benutzerdefinierte Ansichtsgruppe (WrappedLayout) mit ein paar untergeordneten Elementen. Beachten Sie, wie ein benutzerdefinierter XML-Namensraum deklariert und zwei benutzerdefinierte Attribute für das WrappedLayout-Tag festgelegt werden (diese geben an, mit welchem Layout die Kinder umhüllt werden sollen und wo innerhalb dieses Layouts die Kinder dieses Knotens platziert werden sollen).
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:karl="http://schemas.android.com/apk/res/karl.test"
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<karl.test.WrappedLayout
android:id="@+id/topBarLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
karl:layoutToInflate="@layout/top_bar"
karl:childContainerID="@+id/addChildrenHere">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a child of the special wrapper."
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is another child; you can put anything here."
android:textAppearance="?android:attr/textAppearanceMedium" />
</karl.test.WrappedLayout>
</LinearLayout>
attrs.xml: Dies kommt in res/values. Hier werden die benutzerdefinierten XML-Attribute definiert, die in der obigen XML-Datei verwendet werden.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WrappedLayout">
<attr name="layoutToInflate" format="integer"/>
<attr name="childContainerID" format="integer"/>
</declare-styleable>
</resources>
Schließlich WrappedLayout.java: Hier werden die benutzerdefinierten Attribute gelesen, und es wird ein bisschen gebastelt, damit addView() die Ansichten tatsächlich an einer anderen Stelle hinzufügt.
package karl.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
public class WrappedLayout extends FrameLayout
{
///Attempts to add children to this layout will actually get forwarded through to mChildContainer.
///This would be final, but it's actually used indirectly by the constructor before it's initialised.
private ViewGroup mChildContainer;
public WrappedLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
//read the custom attributes
final int layoutToInflate;
final int childContainerID;
{
final TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.WrappedLayout);
layoutToInflate = styledAttributes.getResourceId(R.styleable.WrappedLayout_layoutToInflate, 0);
childContainerID = styledAttributes.getResourceId(R.styleable.WrappedLayout_childContainerID, 0);
styledAttributes.recycle();
}
if(layoutToInflate == 0
|| childContainerID == 0)
{
Log.e("Error", "WrappedLayout.WrappedLayout(): Error reading custom attributes from XML. layoutToInflate = " + layoutToInflate + ", childContainerID =" + childContainerID);
}
else
{
//inflate the layout and (implicitly) add it as a child view
final View inflatedLayout = View.inflate(context, layoutToInflate, this);
//grab the reference to the container to pass children through to
mChildContainer = (ViewGroup)inflatedLayout.findViewById(childContainerID);
}
}
///All the addView() overloads eventually call this method.
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params)
{
if(mChildContainer == null)
{
//still inflating - we're adding one of the views that makes up the wrapper structure
super.addView(child, index, params);
}
else
{
//finished inflating - forward the view through to the child container
mChildContainer.addView(child, index, params);
}
}
}
Das funktioniert, soweit ich das beurteilen kann. Es funktioniert nicht sehr gut mit dem Eclipse-Layout-Editor (ich bin nicht ganz sicher, was das Problem ist), aber Sie können das Layout fein anzeigen. Ändern der Kinder des WrappedLayout scheint zu erfordern, die XML manuell bearbeiten.