首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将图像视图与列表视图中的某些文本结合起来

如何将图像视图与列表视图中的某些文本结合起来
EN

Stack Overflow用户
提问于 2014-06-26 15:03:25
回答 2查看 1.6K关注 0票数 2

到目前为止,我一直使用一个简单的ArrayAdapterListView中显示一些项目。现在,我还想在ListView中的文本旁边显示图像。我有一个名为AsyncTaskDownloadImageTask来下载图像。下载工作非常好,但我不知道如何在ListView中显示图像,也不知道如何使用DownloadImageTaskListView中下载图像。

这是我用来将图像下载到一个DownloadImageTask中的ImageView

代码语言:javascript
运行
复制
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bmImage;

    public DownloadImageTask(ImageView bmImage) {
        this.bmImage = bmImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mIcon11 = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mIcon11;
    }

    protected void onPostExecute(Bitmap result) {
        bmImage.setImageBitmap(result);
    }
}

我还定义了一个ImageViewListView一起下载图像到布局中。

代码语言:javascript
运行
复制
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#000000">

    <ImageView 
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

我这样称呼DownloadImageTask

代码语言:javascript
运行
复制
new DownloadImageTask((ImageView) findViewById(R.id.image1)).execute(url);

如何使用DownloadImageTask下载图像并在ListView中与文本一起显示它们?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-26 15:47:33

要实现您想做的事情,您必须创建一个自定义Adapter。要下载图片,我建议您使用像Picasso这样的库。在下载图片时,毕加索会处理好几乎所有的事情,而且使用起来也不容易,您只需调用它就可以将图像下载到ImageView中。

代码语言:javascript
运行
复制
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

它已经缓存了图像,并且可以以多种方式转换图像。毕加索是一个非常强大但易于使用的图书馆。

1)实现自定义Adapter

首先,我们需要为ListView中的每一行创建一个布局,因为您希望显示包含TextViewImageView所需的图像和文本。

代码语言:javascript
运行
复制
<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:

代码语言:javascript
运行
复制
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。我们需要参考TextViewImageView,但也需要毕加索的Context。我还喜欢将与此行关联的布局定义为该行中的公共常量。

代码语言:javascript
运行
复制
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()中。如有需要,我会评论重要部分:

代码语言:javascript
运行
复制
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)如何使用它

为了使用上面的代码,我们首先需要创建视图模型,这些模型保存我们想要显示的数据:

代码语言:javascript
运行
复制
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中。

代码语言:javascript
运行
复制
List<ExampleViewModel> viewModels = new ArrayList<ExampleViewModel>();
viewModels.add(firstRow);
viewModels.add(secondRow);
viewModels.add(thirdRow);

在此之后,我们需要创建ExampleAdapter的一个实例,并在构造函数中传递视图模型的List。最后,我们只需要将Adapter设置为ListView

代码语言:javascript
运行
复制
ExampleAdapter adapter = new ExampleAdapter(context, viewModels);
listView.setAdapter(adapter);

您以后可以使用ListViewviewmodels()方法修改ExampleAdapter中显示的项!您只需要记住在修改视图模型之后始终在Adapter上调用Adapter

代码语言:javascript
运行
复制
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(); 

我希望我能帮助你,如果你有任何进一步的问题,请随便问!

票数 4
EN

Stack Overflow用户

发布于 2014-06-26 15:09:00

您可以使用外部库,如毕加索或环球图像加载器,他们会给你很多选择。因为它们管理缓存,所以您可以从urls或其他任何地方加载图像,并在几个地方显示它们。

你可以试试:

我不确定,但也许您可以在列表适配器的getView()方法中使用您的getView()方法:

代码语言:javascript
运行
复制
  new DownloadImageTask((ImageView) findViewById(R.id.image1)){
      @Override
      protected void onPostExecute(Bitmap bm) {
           //set imageview src with your bitmap }}.execute(url);
        }
    }.execute(archivo,"investigacion");
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24433983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档