如何通过仅膨胀一次将相同的视图多次添加到父级

Posted

技术标签:

【中文标题】如何通过仅膨胀一次将相同的视图多次添加到父级【英文标题】:How to add same view to parent multiple times by inflating it only once 【发布时间】:2011-09-20 11:02:17 【问题描述】:

我有一个垂直方向的 LinearLayout 作为父级,我想以编程方式多次向该父级添加一些视图。现在,每次在添加到父级之前,每次获取对每个 UI 元素的新引用时,我都会给子级充气。这似乎不是很有效,有没有更好的方法来做到这一点。

我正在使用的当前代码如下,如果我在 for 循环之前只充气一次,我会收到运行时错误“他指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()。”

        LayoutInflater inflator = LayoutInflater.from(getBaseContext());
        LinearLayout parentPanel = findViewById(R.id.parent_pannel);

        ArrayList<String> myList = getData();
        for(String data : myList) 
            // inflate child
            View item = inflator.inflate(R.layout.list_item, null);
            // initialize review UI
            TextView dataText = (TextView) item.findViewById(R.id.data);
            // set data
            dataText.setText(data);
            // add child
            parentPanel.addView(item);
        

【问题讨论】:

我同意,如果有一种简单的方法可以“克隆”视图,那就太好了,但我还没有找到它。一遍又一遍地膨胀。但是,我不得不说,从您的代码 sn-p 来看,在我看来您想要使用 ListView 恐怕这是设计使然。一个视图不能有多个父视图,也不能多次向父视图添加相同的视图。如果不是这样,为 ViewGroup(和类似场景)编写无错误代码将非常困难。 @dmon 我没有设计我的布局来使用 ListView,因为它会使代码更复杂,因为我希望每件事都被布置。我想为了提高效率,我必须将所有内容移至 ListView。 我指出这一点的原因是ListView 出于同样的原因回收视图。由于您一次只能看到 N 个视图,它只会夸大那些必要的视图,然后重用它们。如果您看到自己添加了相当多的视图,则需要考虑一些事情。 我原以为多次膨胀相同的 xml 布局实际上会创建单独的对象但具有相同的结构。为什么这不可能?顺便说一句,ListView 并不总是一种选择:假设您在 ScrollView 中拥有所有内容 - 您不能在 ScrollView 中拥有 ListView。在这种情况下,从 xml 膨胀布局会很好。 【参考方案1】:

您不能,即使您尝试从旧的 view 对象创建 new view,该对象也将通过引用而不是值传递,因此您将得到一个 Exception 作为 childAlreadyHasParent,因此,唯一的方法是将 view 放入 for loop 与您希望它膨胀的次数,然后这个循环必须从一开始就包含创建过程,而不仅仅是充气线。

【讨论】:

【参考方案2】:

多次充气不能以单次充气的方式进行。希望这有效

LayoutInflater inflator = (LayoutInflater).getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    LinearLayout parentPanel = findViewById(R.id.parent_pannel);

    ArrayList<String> myList = getData();
    for(String data : myList) 
        // inflate child
        View item = inflator.inflate(R.layout.list_item, null);
        // initialize review UI
        TextView dataText = (TextView) item.findViewById(R.id.data);
        // set data
        dataText.setText(data);
        // add child
        parentPanel.addView(item);
    

这会起作用,至少对我有用

【讨论】:

View v = inflater.inflate(R.layout.list_item, parent, false) 也适用于我,然后调用 addView(v)。看起来 inflate(...) 可能有一个优化,如果它已经存在,则不附加。 如果我必须在回收站视图行中添加与上面相同的动态视图,你能给我一些建议吗【参考方案3】:

您是否真的检查过 inflate 是否缓慢?据我所知,膨胀视图非常快(几乎与手动创建视图一样快)。

您可能会感到惊讶,但实际上 inflate 根本不解析 XML。用于布局的 XML 在编译时被解析和预处理 - 它们以二进制形式存储,这使得视图膨胀非常有效(这就是为什么你不能从运行时生成的 XML 中膨胀视图)。

【讨论】:

android.googlesource.com/platform/frameworks/base/+/refs/heads/… 第 424 行 我不同意,在我的活动或片段创建过程中,XML 膨胀总是需要最长的时间,这就是为什么我尽量保持布局结构尽可能简单的原因。跨度> 我的观点是,如果您有多层嵌套布局,那么无论是手工完成还是通过膨胀完成都会很慢。所以我同意你应该保持布局尽可能简单(最好在最新的 Google I/O 16 之后,我们很快就会转向更简单/嵌套更少的约束布局)。我唯一的一点是不涉及 XML 解析,所以解析不是问题。 @JarekPotiuk 感谢您的澄清!【参考方案4】:

我不确定您的视图是什么,但您是否通过扩展 XML 手动创建它:

   ArrayList<String> myList = getData();
    for(String data : myList) 

        LinearLayout layout = new LinearLayout(this);
        layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,             LayoutParams.WRAP_CONTENT));
        TextView textView = new TextView(this);
        textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        textView.setText(data);

        layout.addChild(textView);         

        parentPanel.addView(layout);
    

但是,是的,您显然正在尝试使用 Simple ListView 和 API 为您完成的事情

【讨论】:

以上是关于如何通过仅膨胀一次将相同的视图多次添加到父级的主要内容,如果未能解决你的问题,请参考以下文章

将标签和侦听器添加到多次膨胀的 XML 的视图中

如何一次将多个整数传递给一个向量?

在 Swift 中剪辑到父视图的子视图

如何使用 JQuery 一次将多个图像添加到 DOM?

当客户端仅提交一次表单时,Django 多次执行视图功能

如何一次将一个项目添加(推送)到一个数组(循环遍历数组)