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
.
中堆叠在其原始子项 View
s 下面
此外,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
中创建根 LinearLayout
的 layout_height
。 ListView
应该足够聪明来覆盖它并将其包装起来,但最好不要引入任何可能有问题的东西。
您的列表视图行项目有问题 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>
我正在使用 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
.
View
s 下面
此外,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
中创建根 LinearLayout
的 layout_height
。 ListView
应该足够聪明来覆盖它并将其包装起来,但最好不要引入任何可能有问题的东西。
您的列表视图行项目有问题 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>