Как создать многоразовые xml-оболочки для файлов Android Layout - PullRequest
9 голосов
/ 15 июня 2011

У меня есть несколько файлов макетов, которые в основном одинаковы, за исключением одного раздела. Есть ли способ, чтобы я мог иметь общий XML все в одном месте; вместо копирования / вставки и необходимости обновления группы файлов, когда я хочу сделать 1 изменение?

Я знаю, что могу включать XML из других файлов XML, но общий код не является внутренним контролем; это внешняя обертка; так что включить не работает. По сути, у меня есть несколько файлов, которые выглядят так:

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

По сути, я хочу сделать то, что ASP.Net делает с мастер-страницами. Есть ли вариант для этого?

Ответы [ 4 ]

6 голосов
/ 28 мая 2013

Решение было довольно простым.

Вам необходимо расширить класс " Activity " в функции onCreate() SetContentView для вашего базового XML-макета, а также переопределить setContentView в базовом классе Activity

Например:

1.Создать base_layout.xml с кодом ниже

<?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. Создать 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);
    }
}

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

Единственное, что я заметил до сих пор, это то, что при запросе индикатора выполнения (requestWindowFeature (Window.FEATURE_INDETERMINATE_PROGRESS)) это необходимо сделать перед вызовом super.onCreate. Я думаю, это потому, что до вызова этой функции еще ничего нельзя нарисовать.

Это отлично сработало для меня, и, надеюсь, вы найдете это полезным в вашем собственном кодировании.

1 голос
/ 15 июня 2011

Возможно, вы могли бы использовать один основной XML-файл макета, а затем динамически добавлять / удалять другие виджеты с помощью кода по мере необходимости.

1 голос
/ 23 ноября 2011

Я пытался сделать именно это - я хотел, чтобы представление имело кнопку слева и кнопку справа, но в середине мог иметь произвольный контент (в зависимости от того, кто его включал). В основном это настраиваемая группа представлений, которая может иметь дочернее представление в макете XML и оборачивать эти дочерние представления другим макетом XML. Вот как я это сделал:

top_bar.xml: это представляет общий макет, чтобы обернуть вещи. Обратите внимание на LinearLayout (может быть любой макет) с идентификатором «addChildrenHere» - на него ссылаются позже.

<?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: основной макет. Это включает в себя пользовательскую группу просмотра (WrappedLayout) с несколькими детьми. Обратите внимание, как он объявляет настраиваемое пространство имен XML и устанавливает два настраиваемых атрибута в теге WrappedLayout (они говорят, какой макет обернуть дочерние элементы и где в этом макете должны быть размещены дочерние элементы этого узла).

<?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: это относится к res / values. Это определяет пользовательские атрибуты XML, используемые в XML выше.

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

Наконец, WrappedLayout.java: это обрабатывает чтение пользовательских атрибутов и делает небольшую хакерскую попытку заставить addView () фактически добавить представления в другом месте.

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

}

Это работает, насколько я могу судить. Он не очень хорошо работает с редактором макетов Eclipse (я не совсем уверен, в чем проблема), но вы можете хорошо просматривать макет. Изменение дочерних элементов WrappedLayout, по-видимому, требует редактирования XML вручную.

0 голосов
/ 15 июня 2011
...