3

在我的项目中,我有很多重复相同模式的屏幕——它基本上是一个视图容器,由带有标题、图像和特定背景的线性布局组成。为了避免多次复制和粘贴相同的序列,我想我可以创建一个复合视图,扩展 LinearLayout 并在那里定义所有“样式”,然后在我的布局中使用该组件。我遵循了howto和examples并让我的复合视图起作用。但是,我见过的所有示例都使用如下结果视图:

<com.myproject.compound.myview
    ...some attrs...
/>

即没有通过 XML 添加子级。我需要像这样使用它:

<com.myproject.compound.myview
    ...some attrs...>
    <TextView 
        ..../>
    ...other views...

</com.myproject.compound.myview>

由于我正在扩展 LinearLayout,因此我希望“myview”标签也能像 LinearLayout 一样工作,但由于某些原因,我放在里面的项目不会被绘制。我需要特别做些什么来绘制内部视图吗?

我扩展的 LinearLayout 非常简单,我没有重写任何方法,只是在构造函数中调用 super 并像这样膨胀布局:

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_compound_view, this, true);

更新:我想我会添加一个 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" 
android:background="@drawable/bg"
android:padding="12dp">
<TextView 
    android:id="@+id/section_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="#FF0000AA"        />
<ImageView
    android:layout_width="match_parent"
    android:layout_height="2dp"
        android:src="@drawable/line"        />
</LinearLayout>
4

2 回答 2

10

实际上找到了一个更优雅的解决方案。只需要在复合视图中使用合并标签而不是 LinearLayout。一切归结为:

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    <TextView 
        android:id="@+id/section_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="HEADING"
        android:textColor="#FF0000AA"        />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:src="@drawable/line"        />
</merge>

public class CompoundLayout extends LinearLayout{
    public CompoundLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        LayoutInflater inflater = (LayoutInflater) context
           .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.compound_layout, this, true);
    }
}

主要布局:

<com.testbench.CompoundLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FFFFDDEE"
    android:orientation="vertical">
    <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Inner text"
            android:layout_gravity="center_horizontal"/>        
</com.testbench.CompoundLayout>
于 2013-03-20T05:04:04.287 回答
6

在阅读了 Android 源代码和示例之后,我想我明白了这一点。基本上就我而言,它是复合视图和自定义布局的混合体。“复合视图”部分负责布局和绘制指定“容器”的 XML 内容。但是该容器内的物品稍后会膨胀,并且在我的实现中它们没有被布置。一种方法是遵循自定义布局路径 - 我必须实现 onLayout() 和 onMeasure() 才能正确计算我的孩子(我在研究期间做了,它奏效了)。但是因为我真的不需要任何与 LinearLayout 不同的东西,而且我不想复制/粘贴它的代码(那些方法在那里很大),我只是决定重写方法 onFinishInflate() 并添加我的“容器视图“ 那里。

public class CompoundLayout extends LinearLayout{
View mView;
public CompoundLayout(Context context, AttributeSet attrs) {
    super(context, attrs);

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mView = inflater.inflate(R.layout.compound_layout, this, false);
}

@Override
public void onFinishInflate(){
    super.onFinishInflate();
    addView(mView, 0);
}
}

然后在 Activity 的主布局中,我只需像使用 LinearLayout 一样使用我的自定义布局。它呈现相同的内容,但始终将那些 TextView 和 ImageView 放在顶部。

于 2013-03-19T07:17:18.603 回答