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

发布于 2024-08-05 23:52:52 字数 1542 浏览 6 评论 0原文

我目前正在开发的 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 吗?

The Android app I'm currently developing has a main activity that has grown quite large. This is mainly because it contains a TabWidget with 3 tabs. Each tab has quite a few components. The activity has to control of all those components at once. So I think you can imagine that this Activity has like 20 fields (a field for almost every component). Also it contains a lot of logic (click listeners, logic to fill lists, etc).

What I normally do in component based frameworks is to split everything up into custom components. Each custom component would then have a clear responsibility. It would contain it's own set of components and all other logic related to that component.

I tried to figure out how this can be done, and I found something in the Android documentation what they like to call a "Compound Control". (See http://developer.android.com/guide/topics/ui/custom-components.html#compound and scroll to the "Compound Controls" section) I would like to create such a component based on an XML file defining the view structure.

In the documentation it says:

Note that just like with an Activity,
you can use either the declarative
(XML-based) approach to creating the
contained components, or you can nest
them programmatically from your code.

Well, that's good news! The XML-based approach is exactly what I want! But it doesn't say how to do it, except that it is "like with an Activity"... But what I do in an Activity is call setContentView(...) to inflate the views from XML. That method is not available if you for example subclass LinearLayout.

So I tried to inflate the XML manually like this:

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);
    }
}

This works, except for the fact that the XML I'm loading has LinearLayout declared as the root element. This results in the inflated LinearLayout being a child of MyCompoundComponent which itself already is a LinearLayout!! So now we have a redundant LinearLayout in between MyCompoundComponent and the views it actually needs.

Can somebody please provide me with a better way to approach this, avoiding having a redundant LinearLayout instantiated?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独留℉清风醉 2024-08-12 23:52:52

使用merge标签作为您的XML根

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

查看这篇文章。

Use merge tag as your XML root

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

Check this article.

月亮是我掰弯的 2024-08-12 23:52:52

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

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

然后让您的类从您想要使用的任何布局派生。请注意,如果您使用此方法,则您不会在此处使用布局膨胀器。

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);
}

免责声明:我可能完全是胡说八道。

I think the way you're supposed to do it, is use your class name as the XML root element:

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

And then have your class derived from whichever layout you want to use. Note that if you are using this method you don't use the layout inflater here.

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);
    }
}

And then you can use your view in XML layouts as normal. If you want to make the view programmatically you have to inflate it yourself:

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

Unfortunately this doesn't let you do v = new MyView(context) because there doesn't seem to be a way around the nested layouts problem, so this isn't really a full solution. You could add a method like this to MyView to make it a bit nicer:

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

Disclaimer: I may be talking complete bollocks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文