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

Android ListView with Custom Adapter shows only last item

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

这是列表视图的布局

<?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>

这是列表视图行的布局

<?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"
    }
]

最后,输出仅显示页面底部列表视图中 JSON 的最后一个对象

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

任何帮助将不胜感激。

用此代码替换:

 <?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="match_parent"
            android:layout_height="wrap_content"
            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>

您已将列表视图高度保持为 fill_parent。这可能会给您带来问题。将高度更改为 wrap_content

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

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

在那个特定的 inflate() 重载中,第二个参数是 ViewGroup,膨胀的 View 添加到 inflation 之后。您的 getView() 方法第一次运行时,activity.findViewById(R.id.doc_list_row) 将 return null,因为层次结构中尚不存在 doc_list_row View,所以膨胀的 View 将像正常情况一样添加到 ListView 中,在 return 之后。然而,下一次 getView() 运行时,第一个列表项中有一个 doc_list_row View,因此第二个项目的 View 以及之后膨胀的任何项,得到添加到第一个项目中,在其垂直 LinearLayout.

中堆叠在其原始子项 Views 下面

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

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

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

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

您的列表视图行项目有问题 xml 而不是父布局高度 fill_parent 让它们 wrap_content 像这样

<?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: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>