【问题标题】:Add TextView programatically to Listview custom row以编程方式将 TextView 添加到 Listview 自定义行
【发布时间】:2013-03-05 15:38:57
【问题描述】:

我想以编程方式将一个 TextView 添加到 XML 文件中声明的 Linearlayout,该文件定义了应用于所有列表视图行的自定义行。 为了做到这一点,我有以下代码:

<LinearLayout
    android:id="@+id/zv"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/title"
    android:layout_marginBottom="1dip"
    android:layout_marginLeft="5dip"
    android:layout_marginRight="5dip"
    android:orientation="vertical"
    android:padding="1dip" >
</LinearLayout>

class ListViewAdapter extends BaseAdapter {

(...)
public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;
        if (convertView == null)
            vi = inflater.inflate(R.layout.row, null);

        TextView tv_nz = new TextView(activity.getApplicationContext());

        LinearLayout zv = (LinearLayout)vi.findViewById(R.id.zv);

        tv_nz.setText("testing...");
        zv.addView(tv_nz);
(...)

return vi;
}

但是,TextView 在每一行中出现不止一次。 我究竟做错了什么?谢谢

【问题讨论】:

    标签: android android-listview android-linearlayout textview baseadapter


    【解决方案1】:

    我真正想做的是在某些条件下添加一个 Textview 和一些 ImageViews 否则我不能在 XML 文件中声明它。

    您应该使用多个布局来正确执行此操作,因为在一行布局中添加和删除视图可能既昂贵又缓慢。您可以在 XML 或 Java 中创建不同的布局,但在您的适配器中必须覆盖 getViewTypeCount()getItemViewType() 以告诉适配器期望多个布局以及每一行使用哪种布局.

    这很简单,我写了一个例子:Reusing views in Android Listview with 2 different layouts


    原创

    但是,TextView 在每一行中出现不止一次。我做错了什么?

    您未能考虑 ListView 回收其行的方式。这在像 Turbo-Charge Your UI 这样的 Google I/O 演示文稿中有详细解释。

    也许您应该简单地将额外的 TextView 添加到行的 XML 布局或使用多个布局。由于您没有解释为什么要添加 TextView,因此很难给您明确的建议。


    这只会为每一行添加一个 TextView:

    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            // Code here only affects new rows
            convertView = inflater.inflate(R.layout.row, null);
    
            TextView tv_nz = new TextView(activity.getApplicationContext());
            tv_nz.setText("testing...");
            convertView.addView(tv_nz);
        }
        else {
            // Code here affects only recycled rows
        }
    
        // Code here affects every row when the ListView is scrolled
        return convertView;
    }
    

    【讨论】:

    • 您可以将android:visibility="gone" 用于TextView,然后在代码中更改可见性。
    • 确实,在 XML 中添加 TextView 并更改 getView() 内部的可见性可能是一个很好的解决方案,具体取决于 notGeek 希望行的行为方式。
    • @Sam 非常感谢您的回答,但问题是我需要动态地将 ImageViews 添加到布局中,因为图像的数量因行而异:)
    • @notGeek 如果 ImageViews 总是在一个小的数字范围内(比如 1-5),那么您仍然可以设置多个布局以获得最快的代码。或者您可以简单地检查您需要多少 ImageView 以及已经存在多少 (getChildCount()),然后添加或删除适当数量的 View。 (如果您可能有几十个 ImageView,请考虑使用 ExpandableListView。)
    【解决方案2】:

    每次操作系统想要渲染视图时都会调用getView。这意味着每次列表视图询问行的内容时,您都在添加一个新视图。

    如果你切换到只在convertView不为空的时候添加视图,你会达到你想要的。

    public View getView(int position, View convertView, ViewGroup parent) {
        TextView tv_nz;
    
        // If the row does not exist, lets create it.
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.row, null); 
    
            // Add the text view to the new view
            tv_nz = new TextView(activity.getApplicationContext());
            tv_nz.setId(R.id.tv_nz);
    
            convertView.addView(tv_nz);
        } else {
            // The row already exists, lets find the TextView
            tv_nz = (TextView) findViewById(R.id.tv_nz);
        }
    
        if (tv_nz != null) {
            tv_nz.setText("testing...");
        }
    
        return convertView;
    }
    

    顺便说一句,您可以通过将 textview 添加到 R.layout.row 来消除动态添加 textview 的需要

    【讨论】:

      【解决方案3】:

      您似乎是无条件添加 TextView 对吧?

      问题是,如何识别必须添加的单行。也许通过position 参数?只有你知道。

      【讨论】:

      • 这是代码的简化版本。我真正想做的是在某些条件下添加一个 Textview 和一些 ImageViews 否则我不能在 XML 文件中声明它。谢谢
      • @notGeek 我在 XML 文件中声明它并使用 android:visibility。但是同样,除非您发布带有可能错误的整个代码,否则您将让我们所有人都在疯狂地猜测,正如我们已经清楚地看到的那样。 ;)
      • @notGeek 由于您希望行具有不同的布局,因此您必须覆盖两种特定方法,我更新了我的答案。
      【解决方案4】:

      我注意到无论convertView 是否为空,您都在添加TextView。这可以解释这样一个事实,即任何一行中可能有多个 TextView 小部件。

      但是,我确实同意前面的答案 - 可能有更好的方法来完成您的需要。

      【讨论】:

        【解决方案5】:

        我的猜测是,当视图被回收时,它已经添加了 TextView,因此当您添加另一个视图时,您不会检查是否已经从前一个视图中添加了一个。这样的事情应该会有所帮助:

        //after your view inflation
        LinearLayout zv = (LinearLayout)vi.findViewById(R.id.zv);
        TextView tv_nz;
        if(zv.getChildCount() == 0) {
            tv_nz = new TextView(activity.getApplicationContext());
            zv.addView(tv_nz);
        } else
            tv_nz = (TextView) zv.getChildAt(0);
        tv_nz.setText("testing...");
        

        【讨论】:

          【解决方案6】:

          这是给您的示例代码。首先,您必须决定以哪种格式将数据发送到适配器。在我的代码中,我将它作为数组列表发送。

          public class CustomArrayAdapter extends ArrayAdapter<String>
          {
              ArrayList<String> list;
              Context mContext; // ADD THIS to keep a context
          
          public CustomArrayAdapter(Context context, int textViewResourceId,
                  ArrayList<String> objects)
          {
              super(context, textViewResourceId, objects);
              this.mContext = context;
              // Pass the elements in the list
              list = objects;
          }
          

          只有在您拥有特定的数据顺序(如“列表”)后,您才能在列表视图中逐行迭代数据。

          @Override
          public View getView(int position, View convertView, ViewGroup parent)
          {
              View row = convertView;
          
              if (row == null)
              {
          
                  // get reference to the activity
                  LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
          
                  // Inflate the custom text which will replace the default text view
                  //list_item is a simple lineer layout which contain textView1 in it. 
                  row = inflater.inflate(R.layout.list_item, parent, false);
              }
          
              // Create custom text view to customize
          
              TextView tv = (TextView) row.findViewById(R.id.textView1);
          
              // TextView can be customized here or in the xml file
              tv.setText(list.get(position));
          
              return row;
          
            }
          }
          

          最后,您可以像这样调用自定义适配器;

           CustomArrayAdapter adapter = new CustomArrayAdapter(getActivity(),
                      R.id.textView1,values);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-07
            相关资源
            最近更新 更多