带有自定义适配器的 Android ListView 仅显示最后一项

标签 android listview custom-adapter

我正在使用 ListView 显示一些来自 JSON 的数据。 JSON 有 3 个对象。我正在为 ListView 使用自定义适配器。

这是 ListView 的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/doc_signing"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <ListView android:id="@+id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:dividerHeight="1.5dp" />
    <TextView android:id="@+id/android:empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:text="@string/no_docs_to_sign"/>
</LinearLayout>

这是 ListView 行的布局

<?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="fill_parent"
    android:id="@+id/doc_list_row"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/doc_name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textSize="22sp" >
    </TextView>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/doc_id"
            android:layout_weight="0.50"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:paddingBottom="2dp"
            android:paddingLeft="5dp"
            android:paddingRight="3dp"
            android:textSize="16sp" >
        </TextView>
        <TextView
            android:id="@+id/doc_date"
            android:layout_weight="0.50"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:paddingBottom="2dp"
            android:paddingLeft="3dp"
            android:paddingRight="3dp"
            android:textSize="16sp" >
        </TextView>
    </LinearLayout>
</LinearLayout>

读取JSON和设置适配器的代码在这里

ArrayList<DocInfo> docInfo = new ArrayList<DocInfo>();
try {
    JSONArray jArray = new JSONArray(readData());
    for (int i = 0; i < jArray.length(); i++) {
        JSONObject jObject = jArray.getJSONObject(i);
        Log.i("Object" + i, jObject.toString());
        docInfo.add(new DocInfo(Long.valueOf(jObject.getString("doc_id")), jObject.getString("doc_name"), jObject.getString("doc_file_name"), jObject.getString("doc_date")));
    }
} catch (Exception e) {
}
CustomAdapter adapter = new CustomAdapter(this, R.layout.doc_list, docInfo);
setListAdapter(adapter);

自定义适配器

public class CustomAdapter extends ArrayAdapter<DocInfo> {
    private List<DocInfo> entries;
    private Activity activity;

    public CustomAdapter(Activity a, int textViewResourceId, ArrayList<DocInfo> entries) {
        super(a, textViewResourceId, entries);
        this.entries = entries;
        this.activity = a;
    }

    public static class ViewHolder{
        public TextView tv_doc_name;
        public TextView tv_doc_id;
        public TextView tv_doc_date;
    }

    @Override
    public int getCount(){
          return entries!=null ? entries.size() : 0;
    }

    @Override
    public DocInfo getItem(int index) {
        return entries.get(index);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            LayoutInflater vi = LayoutInflater.from(activity);
            convertView = vi.inflate(R.layout.doc_list, (ViewGroup) activity.findViewById(R.id.doc_list_row));
            holder = new ViewHolder();
            holder.tv_doc_name = (TextView) convertView.findViewById(R.id.doc_name);
            holder.tv_doc_id = (TextView) convertView.findViewById(R.id.doc_id);
            holder.tv_doc_date = (TextView) convertView.findViewById(R.id.doc_date);
            convertView.setTag(holder);
        }
        else
            holder=(ViewHolder) convertView.getTag();

        final DocInfo custom = entries.get(position);
        if (custom != null) {
            holder.tv_doc_name.setText(custom.get_doc_name());
            holder.tv_doc_id.setText(String.valueOf(custom.get_doc_id()));
            holder.tv_doc_date.setText(custom.get_doc_date());
        }
        Log.i("Custom" + position, custom.get_doc_name() + String.valueOf(custom.get_doc_id()) + custom.get_doc_date());
        return convertView;
    }
}

用于测试的 JSON

[
    {
        "doc_name": "Home Loan Agreement",
        "doc_file_name": "home_loan_agreement.pdf",
        "doc_id": "6781",
        "doc_date": "11-Mar-2017"
    },
    {
        "doc_name": "Personal Loan Agreement",
        "doc_file_name": "personal_loan_agreement.pdf",
        "doc_id": "2517",
        "doc_date": "19-Mar-2017"
    },
    {
        "doc_name": "Insurance Policy Proposal",
        "doc_file_name": "policy_proposal.pdf",
        "doc_id": "1291",
        "doc_date": "24-Mar-2017"
    }
]

最后,输出只显示页面底部 ListView 中JSON的最后一个对象 screen shot

调试时,我看到 JSON 已被正确读取,并且所有 3 个对象都存在于数组列表中。为 3 个对象调用了自定义适配器的 GetView 方法, View 正在形成并正确返回。尝试了很长时间不同的东西,但无法弄清楚前两项为什么没有出现在屏幕上。

任何帮助将不胜感激。

最佳答案

您错误地扩充了列表项布局。

convertView = vi.inflate(R.layout.doc_list, (ViewGroup) activity.findViewById(R.id.doc_list_row));

在那个特定的 inflate() 重载中,第二个参数是 ViewGroup,在膨胀后将膨胀的 View 添加到该 ViewGroup 中。 getView() 方法第一次运行时,activity.findViewById(R.id.doc_list_row) 将返回 null,因为 doc_list_row View 还不存在于层次结构中,因此膨胀的 View 将像往常一样被添加到 ListView 中, 返回之后。然而,下一次 getView() 运行时,第一个列表项中有一个 doc_list_row View,所以第二个项目的 View 以及之后膨胀的任何对象,都被添加到第一个项目中,在其垂直 LinearLayout 中堆叠在其原始子 View 之下。

此外,inflate() 方法返回膨胀和(可选)添加的任何结果的根 View。如果 ViewGroup 参数为 null,则没有要添加膨胀布局的内容,它返回刚刚膨胀布局的根 View。如果 ViewGroup 参数不是 null,那么 ViewGroup 将作为根返回,因为它现在是顶级父级。创建第一个列表项后,getView() 方法重复返回相同的第一个项目 View,并且 ListView 在协调布局具有自己的内部逻辑,这就是为什么您看到的一项没有与顶部对齐。

膨胀列表项的正确方法是将 ViewGroup parent 参数作为 inflate() 调用中的第二个参数传递,并且 false 作为第三个参数,表示膨胀布局不应添加到那里的 parent,因为它最终将被添加到 之后的 ListView返回

convertView = vi.inflate(R.layout.doc_list, parent, false);

您可能还想在 doc_list 布局 wrap_content 中制作根 LinearLayoutlayout_height,如果只是为了安全起见。 ListView 应该足够聪明,可以覆盖它并将其包装起来,但最好不要引入任何可能有问题的东西。

关于带有自定义适配器的 Android ListView 仅显示最后一项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43025216/

相关文章:

android - 混淆整个 React Native 应用程序,包括 JavaScript 代码

xml - 为什么Listview + Selector从xml文件崩溃

安卓 : drop down a list of items without a spinner

android - 检查 ListView 项目是否包含指定数据然后开始下一个 Activity

java - 按顺序播放帧动画。安卓

android - 如何通过 Activity 绑定(bind)从抽屉标题布局中获取 View ?

Android - 数据库文件丢失时恢复数据库清除数据库

不使用 jQuery-Mobile 的 jQuery-Mobile ListView 插件

java - 使用 customadapter 填充 ListView 的组件时获取空行

java - CustomAdapter 覆盖 ListView 中的项目 - Android