简体   繁体   English

以编程方式将TextView添加到Listview自定义行

[英]Add TextView programatically to Listview custom row

I want to add one TextView programatically to a Linearlayout declared in the XML file that defines a custom row which is applied to all listview rows. 我想以编程方式将一个TextView添加到XML文件中声明的Linearlayout中,该文件定义了应用于所有listview行的自定义行。 In order to do this I have the following code: 为此,我有以下代码:

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

However the TextView appears more than one time in every row. 但是,TextView在每一行中出现多次。 What am I doing wrong? 我究竟做错了什么? Thanks 谢谢

What I really want to do is add a Textview in certain conditions and some ImageViews otherwise so I can't declare it in the XML file. 我真正想做的是在某些条件下添加一个Textview,否则添加一些ImageView,因此我无法在XML文件中声明它。

You should use multiple layouts to do this properly, since adding and removing Views in a row's layout can be expensive and slow. 您应该使用多个布局来正确执行此操作,因为在行的布局中添加和删除视图可能既昂贵又缓慢。 You can create the different layouts in XML or Java, but in your adapter you must override getViewTypeCount() and getItemViewType() to tell the Adapter to expect more than one layout and which layout to use for each row. 您可以使用XML或Java创建不同的布局,但是在适配器中,您必须重写getViewTypeCount()getItemViewType()才能告诉适配器期望不止一个布局以及用于每一行的布局。

It's quite easy, I wrote an example of this in: Reusing views in Android Listview with 2 different layouts 这很简单,我在以下示例中编写了一个示例: 在Android Listview中重用具有2种不同布局的视图


Original 原版的

However the TextView appears more than one time in every row. 但是,TextView在每一行中出现多次。 What am I doing wrong? 我究竟做错了什么?

You have failed to account for the way ListView's recycle their rows. 您无法说明ListView回收其行的方式。 This is explained in great detail in Google I/O presentations like Turbo-Charge Your UI . Google I / O演示文稿(如Turbo-Charge Your UI)中对此进行了详细说明。

Perhaps you should simply add the extra TextView to your row's XML layout or use multiple layouts. 也许您应该只将多余的TextView添加到行的XML布局中,或使用多个布局。 It's hard to give you definitive advice since you haven't explained why you want to add the TextView. 很难给您明确的建议,因为您还没有解释为什么要添加TextView。


This adds only one TextView to each row: 这将仅向每个行添加一个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;
}

getView is called everytime you the OS wants to render the view. 每当操作系统要呈现视图时,都会调用getView。 This means that every time the listview asks for the contents of the row, you are adding a new view. 这意味着,每次listview询问该行的内容时,您都将添加一个新视图。

If you switch to only adding the view when the convertView is not null, you'll achieve what you want. 如果您在convertView不为null时切换到仅添加视图,则将实现所需的功能。

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

By the way, you could remove the need for adding the textview dynamically by adding the textview to R.layout.row 顺便说一句,您可以通过将文本视图添加到R.layout.row来消除动态添加文本视图的需要。

You seem to add the TextView unconditionally, right? 您似乎无条件地添加了TextView,对吗?

Question is, how can you identify the single row where it must be added. 问题是,如何确定必须在其中添加一行的一行。 Maybe by means of the position parameter? 也许借助于position参数? Only you know. 只有你知道。

I notice that you are adding a TextView regardless of whether convertView is null or not. 我注意到您正在添加TextView而不管convertView是否为null。 That may explain the fact that any one row might have multiple TextView widgets in it. 这可以解释一个事实,即任何一行中可能都有多个TextView小部件。

But, I do agree with the previous answers - there might be a much better method of accomplishing what you need. 但是,我确实同意前面的答案-可能有一种更好的方法来完成您所需要的。

My guess is that when the view is recycled, it already has the TextView added to it, and so when you go to add another one you're not checking to see if there is one already added from a previous view. 我的猜测是,当视图被回收时,它已经添加了TextView,因此当您添加另一个视图时,您不会检查是否从上一个视图添加了一个。 Something like this should help: 这样的事情应该有所帮助:

//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...");

Here is a sample code for you. 这是给您的示例代码。 First of all, you have to decide in which format you send your data to the adapter. 首先,您必须确定将数据发送到适配器的格式。 In my code, I sent it as an arraylist. 在我的代码中,我将其作为数组列表发送。

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

Only after you have a specific data order(like the 'list') you can iterate the data row by row in the listview. 只有具有特定的数据顺序(如“列表”)后,您才能在列表视图中逐行迭代数据。

@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;

  }
}

And finally, you can call the custom adapter like this; 最后,您可以像这样调用自定义适配器;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM