要实现您想做的事情,您必须创建一个自定义Adapter。要下载图像,我建议您使用 Picasso 之类的库。 Picasso 在下载图片时会处理几乎所有的事情,而且它真的不能更容易使用它,你只需要调用它来将图片下载到ImageView:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
它已经缓存了图像,还可以通过多种方式转换图像。 Picasso 是一个非常强大且易于使用的库。
1) 实现自定义Adapter
首先我们需要为ListView 中的每一行创建一个布局,在您的情况下,因为您要显示图像和文本,它需要包含TextView 和ImageView:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageView"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textAlignment="gravity"
android:gravity="center"/>
</RelativeLayout>
现在我们需要创建一个容器类——称为视图模型——来保存属于ListView 每一行的数据。在您的情况下,此视图模型包含您要显示的文本和图像的 url:
private class ExampleViewModel {
private String text;
private String imageUrl;
private ExampleViewModel(String text, String imageUrl) {
this.text = text;
this.imageUrl = imageUrl;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
ListViews 使用视图回收。我们可以通过使用一种称为“视图持有者”的模式来加快ListView 的性能。基本上,我们在每一行内保存对Views 的引用并将其附加到行本身。这样我们只需调用一次昂贵的findViewById()。这个视图持有者类——我喜欢称它们为行——还包含一个名为bind() 的方法,用于将视图模型中的数据绑定到每行中的Views。我们需要对 TextView 和 ImageView 的引用,但我们还需要为 Picasso 提供 Context。我还喜欢将与该行关联的布局定义为该行中的公共常量。
private class ExampleRow {
// This is a reference to the layout we defined above
public static final int LAYOUT = R.layout.list_item;
private final Context context;
private final TextView textView;
private final ImageView imageView;
private ExampleRow(Context context, View convertView) {
this.context = context;
this.imageView = (ImageView) convertView.findViewById(R.id.imageView);
this.textView = (TextView) convertview.findViewById(R.id.textView);
}
public void bind(ExampleViewModel exampleViewModel) {
this.textView.setText(exampleViewModel.getText());
Picasso.with(this.context).load(exampleViewModel.getImageUrl()).into(this.imageView);
}
}
最后我们需要一个自定义的Adapter 来完成这项工作,这真的没什么特别的。唯一有趣的部分是getView()。如有必要,我会评论重要部分:
public class ExampleAdapter extends BaseAdapter {
private final List<ExampleViewModel> viewModels;
private final Context context;
private final LayoutInflater inflater;
public ExampleAdapter(Context context) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.viewModels = new ArrayList<ExampleViewModel>();
}
public ExampleAdapter(Context context, List<ExampleViewModel> viewModels) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.viewModels = viewModels;
}
public List<ExampleViewModel> viewmodels() {
return this.viewModels;
}
@Override
public int getCount() {
return this.viewModels.size();
}
@Override
public ExampleViewModel getItem(int position) {
return this.viewModels.get(position);
}
@Override
public long getItemId(int position) {
// We only need to implement this if we have multiple rows with a different layout. All your rows use the same layout so we can just return 0.
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// We get the view model for this position
final ExampleViewModel viewModel = getItem(position);
ExampleRow row;
// If the convertView is null we need to create it
if(convertView == null) {
convertView = this.inflater.inflate(ExampleRow.LAYOUT, parent, false);
// In that case we also need to create a new row and attach it to the newly created View
row = new ExampleRow(this.context, convertView);
convertView.setTag(row);
}
// After that we get the row associated with this View and bind the view model to it
row = (ExampleRow) convertView.getTag();
row.bind(viewModel);
return convertView;
}
}
这就是您所需要的一切。这几乎是Adapter 的最佳实践实现。它使用视图持有者模式来获得额外的性能,并与ListView 的视图回收完美配合。它快速、简洁且容易,并且几乎不会为开发人员犯下的错误留下空间,否则会减慢ListView 的速度。您可以完美区分要显示的数据(全部在 ExampleViewModel 中)和显示方式(在 ExampleRow 中)。适配器本身也不知道 - 应该是这样!
2) 使用方法
要使用上面的代码,我们首先需要创建视图模型来保存我们想要显示的数据:
ExampleViewModel firstRow = new ExampleViewModel("First Row". "http://http://upload.wikimedia.org/wikipedia/commons/6/6f/Freiburger_Alpen.JPG");
ExampleViewModel secondRow = new ExampleViewModel("Second Row". "http://blog.caranddriver.com/wp-content/uploads/2013/05/lamborghini_egoista_three_quarter_front_view.jpg");
ExampleViewModel thirdRow = new ExampleViewModel("Third Row". "http://4.bp.blogspot.com/-vXnf7GjcXmg/UfJZE9rWc2I/AAAAAAAAGRc/x2CIlHM9IAA/s1600/aphoto49721.jpg");
我们需要将所有这些行添加到List:
List<ExampleViewModel> viewModels = new ArrayList<ExampleViewModel>();
viewModels.add(firstRow);
viewModels.add(secondRow);
viewModels.add(thirdRow);
然后我们需要创建ExampleAdapter 的实例并在构造函数中传递视图模型的List。最后我们只需要将Adapter设置为ListView:
ExampleAdapter adapter = new ExampleAdapter(context, viewModels);
listView.setAdapter(adapter);
您可以稍后使用ExampleAdapter 的viewmodels() 方法修改ListView 中显示的项目!您只需要记住在修改视图模型后始终在Adapter 上调用notifyDataSetChanged():
adapter.viewmodels().remove(0); // Remove first view model
adapter.viewmodels().add(someNewViewModel); // Add some new view model
// Always remember to call this method after modifying the viewmodels.
// This will apply the changes to the ListView.
// If you forget to call this you will get an exception
adapter.notifyDataSetChanged();
希望我能帮到你,如果你有任何其他问题,请随时提出!