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
声明为根元素。 这导致膨胀的LinearLayout
是MyCompoundComponent
一个孩子,它本身已经是一个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。