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

Java Android-编写自定义(复合)组件,java,android,custom-component,Java,Android,Custom Component,我目前正在开发的Android应用程序有一个主要的活动,这个活动已经变得相当大了。这主要是因为它包含一个带有3个选项卡的TabWidget。每个选项卡都有相当多的组件。活动必须同时控制所有这些组件。所以我想你可以想象这个活动有20个字段(几乎每个组件都有一个字段)。它还包含很多逻辑(单击侦听器、逻辑填充列表等) 在基于组件的框架中,我通常做的是将所有内容拆分为自定义组件。每个定制组件都有明确的责任。它将包含它自己的一组组件以及与该组件相关的所有其他逻辑 我试图弄清楚如何做到这一点,我在Andro

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

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

我试图弄清楚如何做到这一点,我在Android文档中找到了他们喜欢称之为“复合控件”的东西。(请参阅并滚动到“复合控件”部分)我想基于定义视图结构的XML文件创建这样一个组件

文件中说:

请注意,与活动一样, 您可以使用声明性 (基于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
的子组件,而MyCompoundComponent本身已经是
LinearLayout
!!因此,现在我们在
MyCompoundComponent
和它实际需要的视图之间有一个冗余的线性布局


有谁能为我提供一种更好的方法来解决这个问题,避免重复的
LinearLayout
实例化?

使用merge标记作为XML根

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


我认为应该这样做,即使用类名作为XML根元素:

<com.example.views.MyView xmlns:....
       android:orientation="vertical" etc.>
    <TextView android:id="@+id/text" ... />
</com.example.views.MyView>
然后,您可以像平常一样在XML布局中使用视图。如果要以编程方式创建视图,则必须自己充气:

MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false);
不幸的是,这不允许您执行
v=newmyview(context)
,因为似乎没有办法解决嵌套布局问题,所以这并不是一个完整的解决方案。您可以将这样的方法添加到
MyView
中,使其更好一些:

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

免责声明:我可能在胡说八道。

非常感谢!这正是我想要的。令人惊讶的是,这么长的问题竟然能有这么短的答案。杰出的把这个合并布局放在景观中怎么样?@timmm-hahahaha我早在可视化编辑器出现之前就提出了这个问题:)我喜欢从中学习的问题。谢谢。我最近写了一篇博客:谢谢!我认为这个答案也是正确的:)但三年前,当我问这个问题时,“合并”也起了作用!然后有人来尝试在某个布局中使用您的自定义视图,其中只有
,而您的
setData
onfinishflate
调用开始抛出NPE,您不知道为什么。这里的诀窍是使用您的自定义视图,然后在构造函数中,膨胀使用合并标记作为根的布局。现在,您可以在XML中使用它,或者只需更新它。涵盖所有基础,这正是问题/公认答案的共同作用。但是,您不能再直接参考布局。它现在由自定义控件“拥有”,并且只能由构造函数中的自定义控件使用。但是如果你正在使用这种方法,你为什么还要在其他地方使用它呢?你不会的。
public static MyView create(Context context)
{
    return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false);
}