Android - 编写自定义(复合)组件

时间:2009-09-25 09:35:35

标签: java android custom-component

我正在开发的Android应用程序的主要活动已经变得非常大。这主要是因为它包含带有3个选项卡的TabWidget。每个选项卡都有很多组件。活动必须立即控制所有这些组件。所以我认为你可以想象这个Activity有20个字段(几乎每个组件都有一个字段)。它还包含许多逻辑(单击侦听器,填充列表的逻辑等)。

我通常在基于组件的框架中执行的操作是将所有内容拆分为自定义组件。然后,每个自定义组件都有明确的责任。它将包含它自己的一组组件以及与该组件相关的所有其他逻辑。

我试图弄清楚如何做到这一点,我在Android文档中找到了他们喜欢称之为“复合控制”的东西。 (参见http://developer.android.com/guide/topics/ui/custom-components.html#compound并滚动到“化合物控制”部分)我想基于定义视图结构的XML文件创建这样的组件。

在文档中说:

  

请注意,就像使用Activity一样   你可以使用声明性的   (基于XML)创建的方法   包含组件,或者您可以嵌套   它们以编程方式从您的代码中开始。

嗯,这是个好消息!基于XML的方法正是我想要的!但它并没有说明如何做到这一点,除了它“像一个活动”...但我在一个活动中做的是调用setContentView(...)来从XML扩展视图。如果你是例如子类LinearLayout,则该方法不可用。

所以我尝试像这样手动扩充XML:

public class MyCompoundComponent extends LinearLayout {

    public MyCompoundComponent(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_layout, this);
    }
}

这是有效的,除了我加载的XML已将LinearLayout声明为根元素的事实。这导致虚增LinearLayout成为MyCompoundComponent的孩子,其本身已经是LinearLayout!所以现在我们在MyCompoundComponent和它实际需要的视图之间有一个冗余的LinearLayout。

有人可以为我提供一个更好的方法来解决这个问题,避免实例化多余的LinearLayout吗?

2 个答案:

答案 0 :(得分:99)

使用合并标记作为XML根目录

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Your Layout -->
</merge>

Check this article.

答案 1 :(得分:0)

我认为你应该这样做的方法是使用你的类名作为XML根元素:

<com.example.views.MyView xmlns:....
       android:orientation="vertical" etc.>
    <TextView android:id="@+id/text" ... />
</com.example.views.MyView>

然后让您的类派生自您想要使用的任何布局。请注意,如果您使用此方法,则在此处使用布局inflater。

public class MyView extends LinearLayout
{
    public ConversationListItem(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public ConversationListItem(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }


    public void setData(String text)
    {
        mTextView.setText(text);
    }

    private TextView mTextView;

    @Override
    protected void onFinishInflate()
    {
        super.onFinishInflate();

        mTextView = (TextView)findViewById(R.id.text);
    }
}

然后您可以正常使用XML布局中的视图。如果你想以编程方式制作视图,你必须自己给它充气:

MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false);

不幸的是,这不允许你v = new MyView(context),因为似乎没有办法解决嵌套布局问题,所以这不是一个完整的解决方案。您可以将这样的方法添加到MyView以使其更好一些:

public static MyView create(Context context)
{
    return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false);
}

免责声明:我可能正在谈论完整的僵局。