9 Stimmen

Wie man wiederverwendbare xml-Wrapper für Android-Layout-Dateien erstellt

Ich habe mehrere Layoutdateien, die bis auf einen Abschnitt weitgehend identisch sind. Gibt es eine Möglichkeit, die gemeinsame XML-Datei an einem Ort zu haben, anstatt sie zu kopieren und einzufügen und eine Reihe von Dateien aktualisieren zu müssen, wenn ich eine Änderung vornehmen möchte?

Ich weiß, dass ich XML aus anderen XML-Dateien einbinden kann, aber der gemeinsame Code ist kein internes Steuerelement, sondern der äußere Wrapper, also funktioniert include nicht. Im Grunde habe ich eine Reihe von Dateien, die alle wie folgt aussehen:

<LinearLayout
    android:id="@+id/row"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">

    <ImageView android:layout_height="26dp"
           android:id="@+id/checkImage"
           android:layout_width="26dp"
           android:layout_alignParentTop="true"
           android:scaleType="fitCenter"/>

    <!-- Different types of views go here depending on which layout file it is -->

    <ImageButton android:layout_height="fill_parent"
             android:id="@+id/playButton"
             android:layout_width="42dp"
             android:src="@drawable/play_button"
             android:scaleType="center"

             android:background="#00000000"/>

</LinearLayout>

Im Grunde möchte ich das tun, was ASP.Net mit Master Pages macht. Gibt es dafür eine Möglichkeit?

6voto

Ahmad Ronagh Punkte 760

Die Lösung war ziemlich einfach.

Sie müssen die " Tätigkeit " Klasse, in onCreate() Funktion SetContentView in Ihr Basis-Xml-Layout einfügen und setContentView in der Basis-Activity-Klasse außer Kraft setzen

Zum Beispiel:

1.Erstellen base_layout.xml mit folgendem Code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
           <ImageView 
               android:id="@+id/image_view_01"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:maxHeight="50dp" />
   </LinearLayout>

   <LinearLayout 
       android:id="@+id/base_layout"
       android:layout_width="match_parent"
       android:layout_height="match_parent" >
   </LinearLayout>
</LinearLayout>    
  1. erstellen. BaseActivity.java

    public class BaseActivity extends Activity { ImageView image; LinearLayout baseLayout;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); 
        super.setContentView(R.layout.base_layout);    
    
        this.image = (ImageView) this.findViewById(R.id.image_view_01);
        this.baseLayout = (LinearLayout) this.findViewById(R.id.base_layout);
    
        this.image.setImageResource(R.drawable.header);
    }
    
    @Override
    public void setContentView(int id) {
        LayoutInflater inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(id, this.baseLayout);
    }

    }

y SomeActivity.java

public class SomeActivity extends BaseActivity {

    @Override    
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.some_layout);

       //rest of code
    }
}

Das Einzige, was mir bisher aufgefallen ist, ist, dass beim Anfordern eines Fortschrittsbalkens (requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) dies vor dem Aufruf von super.onCreate erfolgen muss. Ich denke, das liegt daran, dass vor dem Aufruf dieser Funktion noch nichts gezeichnet werden kann.

Das hat bei mir sehr gut funktioniert, und ich hoffe, dass Sie dies bei Ihrer eigenen Codierung nützlich finden werden.

1voto

marchica Punkte 2246

Vielleicht könnten Sie eine Haupt-Layout-XML-Datei verwenden und dann andere Widgets dynamisch durch Code nach Bedarf hinzufügen/entfernen.

1voto

Karu Punkte 4379

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.

0voto

Squonk Punkte 48341

Haben Sie sich angesehen Anwendung von Stilen und Themen ?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X