convertViews 是否在 ListView 中被重用?
Are convertViews being reused in a ListView?
我正在使用此代码来布局我的 ListView
,使用基于某些数据的不同布局:
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder;
MyInfo myInfo = getItem(i);
String label = myInfo.getLabel();
if (convertView == null) {
if (!"".equals(label)) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.info_grey, null);
Log.d(SapphireApplication.TAG, "GREY, label=" + label);
} else {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.info_plain, null);
Log.d(SapphireApplication.TAG, "PLAIN, label=" + label);
}
viewHolder = new ViewHolder();
viewHolder.tvLabel = convertView.findViewById(R.id.tvLabel);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.tvLabel.setText(label);
return convertView;
}
但是,Log.d
从未对列表中的某些项目完成。这是否意味着 Android 重新使用现有的 convertView
,导致它(在本例中)使用错误的布局?
是的。它们正在被重新使用。这就是您只看到少数项目的消息日志的原因。
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
// convertView is null. It means the ListView does not have a view to give to you
// This way, you need to create a new one.
// You will enter here until the ListView has enough Views to fill
// the screen.
// So, just inflate the view and set the View holder here.
// Don't customize your view here (set text, contenet etc)
// So, any log message here will be printed only when the ListView becomes visible (and when you scroll to next item)
// After that, views will be re-used so convertView will no longer be null
} else {
// ListView gave a convertView to you. It means that you are receiving a View
// that was created in the past and it is be re-used now.
// At this moment, convertView still has the content of the old item it was
// representing.
// This view was created in the statement above and after user scrolled the ListView
// it becomes hidden and ready to be re-used.
// Don't customize the view here.. just get the ViewHolder from the View
}
// Here you customize the View. Set content, text, color, background etc
// The ViewHolder is just a helpful class to help you to access
// all View inside the convertView without needing to perform the
// findViewById again.
return convertView;
}
然而,在这个基本示例中,所有 convertViews
都是相似的。它们是从相同的布局中充气的。
这适用于每行只有一个视图类型的情况。所有项目都相似但内容不同。
如果差异很小,这仍然有效。例如,您可以膨胀相同的布局并根据位置控制其某些 Views
的可见性(位置 1 有图像而位置 2 没有)。
但是,在某些情况下,您确实需要为每行填充不同的布局。
例如,"grey" 布局与 "plain" 布局有很大不同。在这种情况下,您需要更新您
代码如下:
private static final int GREY = 1;
private static final int PLAIN = 2;
private static final int TOTAL_VIEW_TYPES = 2; // Grey and Plain
@Override
public int getViewTypeCount() {
// Tell the list view that you have two types of Views (Grey and plain)
return TOTAL_VIEW_TYPES;
}
@Override
public int getItemViewType(int position) {
// You must inform view type for given position
String label = myInfo.getLabel();
if (!"".equals(label)) {
return GREY;
} else {
return PLAIN;
}
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
// If view is null, you must create the view. But you need to create the
// correct view for given position
if(getItemViewType(position) == GREY) {
// Inflate grey;
} else {
// inflate plain
}
} else {
// convertView is not null. It is being reused.
// Android will give you the proper view here. If you are expecting
// a plain type, that's what you will get. Android won't re-use
// plain layout where you are expecting to have the grey layout.
// It will re-use the proper view for each position (following to the getItemViewType()).
// ListView is very robust.
}
// Update the view here.. Just remember that here you may have two different
// types of view.. grey or plain.
return convertView;
}
这些概念最酷的地方在于它们对使用此视图<->适配器关系的任何视图都有效。
RecyclerView
、ListView
、Spinner
、PagerView
等
我正在使用此代码来布局我的 ListView
,使用基于某些数据的不同布局:
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder;
MyInfo myInfo = getItem(i);
String label = myInfo.getLabel();
if (convertView == null) {
if (!"".equals(label)) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.info_grey, null);
Log.d(SapphireApplication.TAG, "GREY, label=" + label);
} else {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.info_plain, null);
Log.d(SapphireApplication.TAG, "PLAIN, label=" + label);
}
viewHolder = new ViewHolder();
viewHolder.tvLabel = convertView.findViewById(R.id.tvLabel);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.tvLabel.setText(label);
return convertView;
}
但是,Log.d
从未对列表中的某些项目完成。这是否意味着 Android 重新使用现有的 convertView
,导致它(在本例中)使用错误的布局?
是的。它们正在被重新使用。这就是您只看到少数项目的消息日志的原因。
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
// convertView is null. It means the ListView does not have a view to give to you
// This way, you need to create a new one.
// You will enter here until the ListView has enough Views to fill
// the screen.
// So, just inflate the view and set the View holder here.
// Don't customize your view here (set text, contenet etc)
// So, any log message here will be printed only when the ListView becomes visible (and when you scroll to next item)
// After that, views will be re-used so convertView will no longer be null
} else {
// ListView gave a convertView to you. It means that you are receiving a View
// that was created in the past and it is be re-used now.
// At this moment, convertView still has the content of the old item it was
// representing.
// This view was created in the statement above and after user scrolled the ListView
// it becomes hidden and ready to be re-used.
// Don't customize the view here.. just get the ViewHolder from the View
}
// Here you customize the View. Set content, text, color, background etc
// The ViewHolder is just a helpful class to help you to access
// all View inside the convertView without needing to perform the
// findViewById again.
return convertView;
}
然而,在这个基本示例中,所有 convertViews
都是相似的。它们是从相同的布局中充气的。
这适用于每行只有一个视图类型的情况。所有项目都相似但内容不同。
如果差异很小,这仍然有效。例如,您可以膨胀相同的布局并根据位置控制其某些 Views
的可见性(位置 1 有图像而位置 2 没有)。
但是,在某些情况下,您确实需要为每行填充不同的布局。 例如,"grey" 布局与 "plain" 布局有很大不同。在这种情况下,您需要更新您 代码如下:
private static final int GREY = 1;
private static final int PLAIN = 2;
private static final int TOTAL_VIEW_TYPES = 2; // Grey and Plain
@Override
public int getViewTypeCount() {
// Tell the list view that you have two types of Views (Grey and plain)
return TOTAL_VIEW_TYPES;
}
@Override
public int getItemViewType(int position) {
// You must inform view type for given position
String label = myInfo.getLabel();
if (!"".equals(label)) {
return GREY;
} else {
return PLAIN;
}
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
// If view is null, you must create the view. But you need to create the
// correct view for given position
if(getItemViewType(position) == GREY) {
// Inflate grey;
} else {
// inflate plain
}
} else {
// convertView is not null. It is being reused.
// Android will give you the proper view here. If you are expecting
// a plain type, that's what you will get. Android won't re-use
// plain layout where you are expecting to have the grey layout.
// It will re-use the proper view for each position (following to the getItemViewType()).
// ListView is very robust.
}
// Update the view here.. Just remember that here you may have two different
// types of view.. grey or plain.
return convertView;
}
这些概念最酷的地方在于它们对使用此视图<->适配器关系的任何视图都有效。
RecyclerView
、ListView
、Spinner
、PagerView
等