使用 ViewHolder 的 Android 列表视图
Posted
技术标签:
【中文标题】使用 ViewHolder 的 Android 列表视图【英文标题】:Android listview using ViewHolder 【发布时间】:2014-09-11 23:06:10 【问题描述】:我有问题。单击后,我试图更改列表视图中的图标。它可以正常工作,尽管不仅修改了单击的图标,还修改了未显示的图标。例如,如果我单击列表视图第一项中的图标,第五个图标也会更改。对于以下所有项目(列表视图的每五个项目)重复此行为。 这是我的 getView 方法:
public class AlphabeticalAdapter extends ArrayAdapter<String>
int layoutResourceId;
private final Context context;
private List<String> data;
private ProgressDialog mProgressDialog;
private ImageView downloadImageButton;
public AlphabeticalAdapter(Context context, int resource, List<String> data)
super(context, resource, data);
this.layoutResourceId = resource;
this.context = context;
this.data = data;
public View getView(int position, View convertView, ViewGroup parent)
// View rowView = convertView;
final ViewHolder viewHolder;
if (convertView == null)
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.catalogslist_single_row, parent, false);
viewHolder = new ViewHolder();
viewHolder.catlogTitle=(TextView)convertView.findViewById(R.id.txtTitle);
viewHolder.icon=(ImageView)convertView.findViewById(R.id.imageView2);
viewHolder.downloadImageButton=(ImageView)convertView.findViewById(R.id.downloadImageButton);
//downloadImageButton = (ImageView)rowView.findViewById(R.id.downloadImageButton);
viewHolder.position = position;
viewHolder.downloadImageButton.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
System.out.println("DOWNLOAD PRESSED");
viewHolder.downloadImageButton = (ImageView)v.findViewById(R.id.downloadImageButton);
viewHolder.downloadImageButton.setImageResource(R.drawable.icon_ok);
viewHolder.downloadImageButton.setTag("downloaded");
//rowView.setTag("downloaded");
);
convertView.setTag(viewHolder);
else
viewHolder= (ViewHolder)convertView.getTag();
viewHolder.catlogTitle.setText(data.get(position));
viewHolder.catlogTitle.setTypeface(regularDin);
viewHolder.icon.setImageResource(R.drawable.cata);
if(viewHolder.downloadImageButton.getTag() == "downloaded")
downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton);
downloadImageButton.setImageResource(R.drawable.icon_ok);
else
downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton);
downloadImageButton.setImageResource(R.drawable.icon_download);
viewHolder.position = position;
return convertView;
//close getView
...
这是我的 ViewHolder 类:
static class ViewHolder
ImageView downloadImageButton;
TextView catlogTitle;
ImageView icon;
int position;
【问题讨论】:
【参考方案1】:在下面更改您的代码。我想你错过了。
public class AlphabeticalAdapter extends ArrayAdapter<String>
int layoutResourceId;
private final Context context;
private List<String> data;
private List<String> tags;
private ProgressDialog mProgressDialog;
private ImageView downloadImageButton;
public AlphabeticalAdapter(Context context, int resource, List<String> data)
super(context, resource, data);
this.layoutResourceId = resource;
this.context = context;
this.data = data;
tags = new ArrayList<String>();
int size = data.size();
for (int i = 0; i < size; i++)
tags.add("tag");
static class ViewHolder
ImageView downloadImageButton;
TextView catlogTitle;
ImageView icon;
int position;
public View getView(final int position, View convertView, ViewGroup parent)
// View rowView = convertView;
final ViewHolder viewHolder;
if (convertView == null)
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// convertView = inflater.inflate(R.layout.catalogslist_single_row,
// parent, false);
viewHolder = new ViewHolder();
viewHolder.position = position;
viewHolder.downloadImageButton
.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
System.out.println("DOWNLOAD PRESSED");
viewHolder.downloadImageButton.setTag("downloaded");
tags.add(position, "downloaded");
);
convertView.setTag(viewHolder);
else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.catlogTitle.setText(data.get(position));
viewHolder.catlogTitle.setTypeface(regularDin);
viewHolder.icon.setImageResource(R.drawable.cata);
if (tags.get(position) == "downloaded")
downloadImageButton.setImageResource(R.drawable.icon_ok);
else
downloadImageButton.setImageResource(R.drawable.icon_download);
viewHolder.position = position;
return convertView;
// close getView
【讨论】:
@Mark 我编辑了我的代码,看到这个并告诉你它的帮助 这是错误的。阅读我的答案以了解原因。 ViewHolder 对象的数量不等于行数。否则 ViewHolder 模式的含义是什么? @kupsef 是的,你是对的。其他不同的列表之一添加了它的工作 @kupsef 你能贴一个例子吗? @Mark 我更新了我认为的代码。您还可以使用数组列表来 hashmap 或 TreeSet 选择位置。【参考方案2】:ListView
中同时可见的行数与 convertViews
一样多(系统会重复使用它)。所以你实际上有 5 个convertView
,因此你有 5 个ImageView
用于图标。问题是您使用那些 ImageView 的标签来存储“下载”信息。那是 5 个状态,这就是为什么您在列表中滚动时会看到每五行下载一次。
我想现在你知道它不起作用了。您需要存储每个项目的下载状态,因此您必须将底层的List<String>
更改为List<ListItem>
,其中ListItem
可以存储实际行的下载状态。
之后,您所要做的就是更新convertView
的ImageView
(在getView()
中)以显示正确的图标。
【讨论】:
【参考方案3】:像这样更改您的代码。在 try 块之前使用 convertView 添加空检查。
final MenuItem menuItem = getItem(position);
View view = convertView;
final ViewHolder viewHolder;
if (convertView == null)
LayoutInflater inflater;
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.menu_item, parent, false);
viewHolder = new ViewHolder();
// viewHolder.half = (TextView) view.findViewById(R.id.half);
viewHolder.name = (TextView) view.findViewById(R.id.name);
viewHolder.description = (TextView) view.findViewById(R.id.description);
viewHolder.price = (TextView) view.findViewById(R.id.price);
viewHolder.add = (Button) view.findViewById(R.id.add);
viewHolder.selectedView = view.findViewById(R.id.selectedView);
viewHolder.remove = (Button) view.findViewById(R.id.remove);
viewHolder.total = (TextView) view.findViewById(R.id.itemTotal);
viewHolder.quantity = (TextView) view.findViewById(R.id.quantity);
view.setTag(viewHolder);
else
viewHolder= (ViewHolder)convertView.getTag();
【讨论】:
【参考方案4】:你可以试试这个
public class CustomArrayAdapter extends ArrayAdapter
// declare your custom list with type;
private List<YourModelClass> allData = new ArrayList<YourModelClass>();
public CustomArrayAdapter(@NonNull Context context, List<YourModelClass> allData)
super(context, R.layout.your_layout, allData); // add your_layout.xml
this.allData = allData;
class ViewHolder
TextView name, phone; // declare your your_layout.xml view type
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent)
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewHolder holder = new ViewHolder();
if (convertView == null)
convertView = inflater.inflate(R.layout.your_layout, parent, false); // inflate your_layout.xml
//initialize your your_layout.xml view
holder.name = convertView.findViewById(R.id.tv_item_name);
holder.phone = convertView.findViewById(R.id.tv_item_phone);
convertView.setTag(holder);
else
holder = (ViewHolder) convertView.getTag();
//set value into your_layout.xml
holder.name.setText(allData.get(position).getName());
holder.phone.setText(allData.get(position).getNumber());
return convertView;
【讨论】:
【参考方案5】:public class androidListViewActivity extends ListActivity
private ListView listView;
private String names[] =
"HV CAPACITOR",
"LV CAPACITORCSS",
;
private String desc[] =
"The Powerful Hypter Text Markup Language 5",
"Cascading Style Sheets",
;
private Integer imageid[] =
R.drawable.hv_capacitor,
R.drawable.lv_capacitor,
;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
// setContentView(R.layout.capacitor_layout);
// storing string resources into Array
String[] product_name = getResources().getStringArray(R.array.product_name);
// Binding Array to ListAdapter
this.setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, product_name));
ListView lv = getListView();
// listening to single list item on click
lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
// selected item
String product = ((TextView) view).getText().toString();
// Launching new Activity on selecting single List Item
Intent i = new Intent(getApplicationContext(), SingleListItem.class);
// sending data to new activity
i.putExtra("product", product);
startActivity(i);
);
CapacitorList capacitorList = new CapacitorList(this, names, desc, imageid);
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(capacitorList);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
// Launching new Activity on selecting single List Item
Intent i = new Intent(getApplicationContext(), CapacitorList.class);
// sending data to new activity
// startActivity(i);
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l)
Toast.makeText(getApplicationContext(), "You Clicked " + names[i], Toast.LENGTH_SHORT).show();
);
@Override
public boolean onCreateOptionsMenu (Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
@Override
public boolean onOptionsItemSelected (MenuItem item)
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
return true;
return super.onOptionsItemSelected(item);
【讨论】:
以上是关于使用 ViewHolder 的 Android 列表视图的主要内容,如果未能解决你的问题,请参考以下文章
android 怎么在外面拿recyclerview 中viewholder的控件
android RecyclerView获得单个Item的ViewHolder