Android自定义适配器:仅在滚动时填充的列表项

时间:2012-10-11 17:11:56

标签: android android-listview android-adapter

我遇到问题,我的自定义ArrayAdapter(下面的代码)正确填充了我的列表。根据我的理解,我的适配器仅在实例化时填充textviewResourceId,因为我正在使用构造函数Adapter(context, rowLayout, textViewResourceId, ArrayList<Items>),但只有当不可见的行变为可见时才调用getView方法。

这导致了一个问题,因为当我的列表首次显示时,只显示我文章的标题,我必须一直向下滚动列表,然后向上滚动,以便每行中的所有视图都能正确填充(因为该任务是在getView中完成的。)

有人能指出我正确的方向吗?我怎么能重构这个,以便每个可见行中的所有视图立即填充?

自定义适配器的代码:

import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ArticleArrayAdapter extends ArrayAdapter<Article> {

    private final Context context;
    private final ArrayList<Article> articles;
    @SuppressWarnings("unused")
    private final int rowLayout;

    public ArticleArrayAdapter(Context context, int rowLayout, int textViewResourceId, ArrayList<Article> articles) {
        super(context, rowLayout, textViewResourceId, articles);
        this.rowLayout=rowLayout;
        this.context = context;
        this.articles = articles;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View row = convertView;
        if (row == null) {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(R.layout.affichageitem, null);
        }
        else {
            TextView viewTitre = (TextView)row.findViewById(R.id.titre);
            TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
            TextView viewDate = (TextView)row.findViewById(R.id.date);
            ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
            viewTitre.setText(articles.get(position).getTitle());
            viewAuteur.setText(articles.get(position).getCreator());
            viewDate.setText(articles.get(position).getDate());
            Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
            viewLogo.setImageDrawable(drawLogo);
        }
        return super.getView(position, convertView, parent);
    }
}

编辑版:

public class ArticleArrayAdapter extends ArrayAdapter<Article> {

    private final Context context;
    @SuppressWarnings("unused")
    private final int rowLayout;

    public ArticleArrayAdapter(Context context, int rowLayout,int textViewResourceId) {
        super(context, rowLayout, textViewResourceId);
        this.rowLayout=rowLayout;
        this.context = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View row = convertView;
        if (row == null) {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(R.layout.affichageitem, null);
        }
        else {
            TextView viewTitre = (TextView)row.findViewById(R.id.titre);
            TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
            TextView viewDate = (TextView)row.findViewById(R.id.date);
            ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
            viewTitre.setText(getItem(position).getTitle());
            viewAuteur.setText(getItem(position).getCreator());
            viewDate.setText(getItem(position).getDate());
            Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
            viewLogo.setImageDrawable(drawLogo);
        }
        return super.getView(position, convertView, parent); // <<- ONLY TITLES
        //return row; <<- EMPTY
    }
}

的RowLayout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/category_logo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:contentDescription="@string/logo_desc"
        android:padding="20dp" />

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical"
        android:paddingLeft="5dp" >

        <TextView
            android:id="@+id/titre"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="18dp"
            android:textStyle="bold" />

        <LinearLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity=""
            android:orientation="horizontal" >

            <TextView
            android:id="@+id/auteur"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:textSize="12dp" />
            <TextView
            android:id="@+id/espace"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/espace"
            android:adjustViewBounds="true"
            android:textSize="12dp" />
            <TextView
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:textSize="12dp" />
        </LinearLayout>

    </LinearLayout>

</LinearLayout>

5 个答案:

答案 0 :(得分:4)

问题是您没有填充新视图。会发生什么是Android可能会保留固定数量的视图,这些视图将用于列表视图。这些视图被回收,这就是为什么在所有视图变得可见之前不可能“填充”它们的原因。这一行

if (view == null) {
    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    row = inflater.inflate(R.layout.affichageitem, null);
}

检查视图是否正在被回收。 null表示不是,所以如果你得到null,你需要给新视图充气。你的代码很好。但是,您需要填充视图,看它是否是新增的视图。所以你不应该有else语句,只需要

View row = convertView;
if (row == null) {
    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    row = inflater.inflate(R.layout.affichageitem, null);
}
TextView viewTitre = (TextView)row.findViewById(R.id.titre);
TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
TextView viewDate = (TextView)row.findViewById(R.id.date);
ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
viewTitre.setText(getItem(position).getTitle());
viewAuteur.setText(getItem(position).getCreator());
viewDate.setText(getItem(position).getDate());
Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
viewLogo.setImageDrawable(drawLogo);

return row;

当你完全向下滚动时它起作用的原因是,在你回来的路上getView正在接收回收的views并且它直接跳到你拥有的else子句中。

答案 1 :(得分:2)

您正在使用自己的收藏集ArrayList<Article>

请注意,每个ArrayAdaper<foo>都已内置数据集合,您可以按add(foo)addAll(List<foo>)添加,并按clear()方法清除。

此外,ListView可以观察此数据,并在此数据发生更改时进行刷新。或者在适配器上调用notifyDataSetChanged()时显式。

这里的问题是你在构造函数中接受数据,存储在另一个局部变量中,并且没有调用notifyDataSetChanged()。你不能从构造函数中调用它,因为Object仍在构建中。

所以,不要接受构造函数中的数据。在getView()内使用getItem(position)获取Article项。

在外部添加数据,如:

ArticleArrayAdapter adapter = new ArticleArrayAdapter(context,rowLayout,android.R.layout.simple_list_item_1);
adapter.addAll(articles);
myListView.setAdapter(adapter);

答案 2 :(得分:1)

对我来说是正确的 - 唯一的事情:没有必要调用超类。尝试返回您的组合视图:

return row;

答案 3 :(得分:0)

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View row = convertView;
    if (row==null){
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        row = inflater.inflate(R.layout.affichageitem, null);
         convertView.setTag(row);
    }else{
        TextView viewTitre = (TextView)row.findViewById(R.id.titre);
        TextView viewAuteur = (TextView)row.findViewById(R.id.auteur);
        TextView viewDate = (TextView)row.findViewById(R.id.date);
        ImageView viewLogo = (ImageView)row.findViewById(R.id.category_logo);
        viewTitre.setText(getItem(position).getTitle());
        viewAuteur.setText(getItem(position).getCreator());
        viewDate.setText(getItem(position).getDate());
        Drawable drawLogo = context.getResources().getDrawable(R.drawable.logocat);
        viewLogo.setImageDrawable(drawLogo);
    }
}

答案 4 :(得分:0)

我有类似的问题。我还发现,如果不手动滚动到列表的最后一个,则不会创建所有视图。除了可见项目之外,所有项目都为null。因此,我必须以编程方式向下滚动到列表的最后一个。

我已经从BaseAdapter类扩展了MyAdapter。

mAdapter = new MyAdapter(this, mFinalContactList);
mListView.setAdapter(mAdapter);

要创建所有列表视图,要自动滚动到最后,我使用了以下代码行。

mAdapter.notifyDataSetChanged();
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
mListView.smoothScrollToPosition(mFinalContactList.size()-1);

这可能有助于尝试自动滚动到最后一个的人。

N.B。 mListView.setSelection(position); 方法只有在我们将位置设置为最后时才能指向最后一个列表项。但是无法将列表项从forst填充到最后。

谢谢