Android – 编写一个自定义(复合)组件

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

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

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

在文档中说:

请注意,就像使用Activity一样,您可以使用基于声明(基于XML)的方法来创build包含的组件,也可以通过代码将它们嵌套在程序中。

那好,这是个好消息! 基于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声明为根元素。 这导致膨胀的LinearLayoutMyCompoundComponent一个孩子,它本身已经是一个LinearLayout ! 所以现在我们在MyCompoundComponent和它实际需要的视图之间有一个冗余的LinearLayout。

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

使用合并标签作为您的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> 

然后让你的class级从你想要使用的任何布局派生出来。 请注意,如果您正在使用此方法, 则不要在此处使用布局充气器。

 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)因为似乎没有解决嵌套布局问题的方法,所以这不是一个完整的解决scheme。 你可以添加一个像MyView这样的方法,使其更好一些:

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

免责声明:我可能会说完整的bollocks。