Universal-Image-Loader解析(三)——用ListView和ViewPager加载网络中的图片
现在我们终于可以通过这个框架来实现ListView中加载图片了,至于ViewPager还是别的,原理其实都是一样的
一、ListView
1.布局文件
list_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ImageView android:id="@+id/item_imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/ic_launcher" /> </LinearLayout>
图片来源类:
package com.kale.universalimageloadertest; public class PicArrays { public static String[] getPicArray() { String[] arrs = new String[]{ "http://static4.photo.sina.com.cn/middle/69670edbx9475f3f01283&690", "http://s8.sinaimg.cn/middle/6f78405exa6e437719ea7&690", "http://s3.sinaimg.cn/middle/6f78405ex9f4d66911f22&690", "http://s8.sinaimg.cn/middle/6f78405exa6e436d8f357&690", "http://s4.sinaimg.cn/middle/6f78405exa6e43621ecb3&690", "http://s10.sinaimg.cn/middle/6f78405exa0f4f335c589&690", "http://s16.sinaimg.cn/middle/6f78405ex9f4d7b2eff0f&690", "http://s7.sinaimg.cn/middle/6f78405exa6e2fa1d4ab6&690", "http://s8.sinaimg.cn/middle/6f78405exa6e2fa4b19c7&690", "http://s6.sinaimg.cn/middle/69670edbx94da12276525&690", "http://s2.sinaimg.cn/middle/69670edbx94da117f7c41&690", "http://s3.sinaimg.cn/bmiddle/6f78405exa503c5d0a462&690", "http://s6.sinaimg.cn/middle/6f78405exa72b24119765&690", "http://s11.sinaimg.cn/middle/6f78405ex9f4d5245988a&690", "http://s10.sinaimg.cn/middle/6f78405ex9f4d7b107f29&690", "http://img0.tech2ipo.com/upload/img/article/2013/03/1364556945327.png", "http://s7.sinaimg.cn/middle/6f78405eta77a260b8d96&690", "http://s3.sinaimg.cn/middle/6f78405eta77a29344d92&690", "http://s10.sinaimg.cn/middle/6f78405exa0f4f250e469&690", "http://s3.sinaimg.cn/middle/6f78405eta77a21932632&690", "http://s13.sinaimg.cn/middle/6f78405eta77a2c9a0d2c&690", "http://s9.sinaimg.cn/middle/6f78405eta77a47b89188&690", "http://s16.sinaimg.cn/middle/6f78405exa0f4f11fb58f&690", "http://img2.imgtn.bdimg.com/it/u=2449553173,1966285445&fm=23&gp=0.jpg", "http://h.hiphotos.baidu.com/baike/w%3D150/sign=406f3d00251f95caa6f596b3f9167fc5/d50735fae6cd7b89493402fd0f2442a7d9330e77.jpg" }; return arrs; } public static void main(String[] args) { System.out.println("图片总数:"+getPicArray().length); } }
写一个listview的适配器
这里在载入图片的时候放入了一个动画的效果。可见这个框架的扩展性是相当强的!!!
final private DisplayImageOptions options = getSimpleOptions(); final private ImageLoader imageLoader = ImageLoader.getInstance();
/** * * 自定义列表项适配器 * */ class ItemAdapter extends BaseAdapter { //图片第一次加载的监听器 private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener(); private String[] picArrs; public ItemAdapter() { // TODO 自动生成的构造函数存根 picArrs = PicArrays.getPicArray(); } private class ViewHolder { public ImageView image; } @Override public int getCount() { return picArrs.length; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { View view = convertView; final ViewHolder holder; //通过convertView来判断是否已经加载过了,如果没有就加载 if (convertView == null) { view = getLayoutInflater().inflate(R.layout.list_item, parent, false); holder = new ViewHolder(); holder.image = (ImageView) view.findViewById(R.id.item_imageView); view.setTag(holder);// 给View添加一个格外的数据 } else { holder = (ViewHolder) view.getTag(); // 把数据取出来 } /** * 显示图片 * 参数1:图片url * 参数2:显示图片的控件 * 参数3:显示图片的设置 * 参数4:监听器 */ imageLoader.displayImage(picArrs[position], holder.image, options,animateFirstListener); return view; } } /** * 图片加载第一次显示监听器 * @author Administrator * */ private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener { static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>()); @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { if (loadedImage != null) { ImageView imageView = (ImageView) view; // 是否第一次显示 boolean firstDisplay = !displayedImages.contains(imageUri); if (firstDisplay) { // 图片淡入效果 FadeInBitmapDisplayer.animate(imageView, 200); displayedImages.add(imageUri); } } } }
全部的Activity代码:
package com.kale.universalimageloadertest; import java.util.Collections; import java.util.LinkedList; import java.util.List; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; public class UILListActivity extends Activity{ final private DisplayImageOptions options = getSimpleOptions(); final private ImageLoader imageLoader = ImageLoader.getInstance(); @Override protected void onCreate(Bundle savedInstanceState) { // TODO 自动生成的方法存根 super.onCreate(savedInstanceState); setContentView(R.layout.list_layout); ListView listView = (ListView)findViewById(R.id.listView); /* * 3个参数-> * 1:图片加载对象ImageLoader, * 2:控制是否在滑动过程中暂停加载图片,如果需要暂停传true就行了 * 3:控制猛的滑动界面的时候图片是否加载 * */ listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, false, true)); listView.setAdapter(new ItemAdapter()); } /** * 设置常用的设置项 * @return */ private DisplayImageOptions getSimpleOptions() { DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.loading) //设置图片在下载期间显示的图片 .showImageForEmptyUri(R.drawable.ic_launcher)//设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.error) //设置图片加载/解码过程中错误时候显示的图片 .cacheInMemory(true)//设置下载的图片是否缓存在内存中 .cacheOnDisk(true)//设置下载的图片是否缓存在SD卡中 .imageScaleType(ImageScaleType.IN_SAMPLE_INT)//设置图片以如何的编码方式显示 .considerExifParams(true) .bitmapConfig(Bitmap.Config.RGB_565)//设置图片的解码类型 .build();//构建完成 return options; } /** * * 自定义列表项适配器 * */ class ItemAdapter extends BaseAdapter { //图片第一次加载的监听器 private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener(); private String[] picArrs; public ItemAdapter() { // TODO 自动生成的构造函数存根 picArrs = PicArrays.getPicArray(); } private class ViewHolder { public ImageView image; } @Override public int getCount() { return picArrs.length; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { View view = convertView; final ViewHolder holder; //通过convertView来判断是否已经加载过了,如果没有就加载 if (convertView == null) { view = getLayoutInflater().inflate(R.layout.list_item, parent, false); holder = new ViewHolder(); holder.image = (ImageView) view.findViewById(R.id.item_imageView); view.setTag(holder);// 给View添加一个格外的数据 } else { holder = (ViewHolder) view.getTag(); // 把数据取出来 } /** * 显示图片 * 参数1:图片url * 参数2:显示图片的控件 * 参数3:显示图片的设置 * 参数4:监听器 */ imageLoader.displayImage(picArrs[position], holder.image, options,animateFirstListener); return view; } } /** * 图片加载第一次显示监听器 * @author Administrator * */ private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener { static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>()); @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { if (loadedImage != null) { ImageView imageView = (ImageView) view; // 是否第一次显示 boolean firstDisplay = !displayedImages.contains(imageUri); if (firstDisplay) { // 图片淡入效果 FadeInBitmapDisplayer.animate(imageView, 200); displayedImages.add(imageUri); } } } } }
通过ViewHolder和convertView配合使用,可以提高效率。这点也是我们应该学习的
二、ViewPager
viewPager_layout.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" />
viewpager_item.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="1dip"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:adjustViewBounds="true" android:contentDescription="@string/hello_world" /> <ProgressBar android:id="@+id/loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> </FrameLayout>
UILViewPagerActivity.java
package com.kale.universalimageloadertest; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; public class UILViewPagerActivity extends Activity { ViewPager pager; DisplayImageOptions options; ImageLoader imageLoader; private static final String STATE_POSITION = "STATE_POSITION"; @Override protected void onCreate(Bundle savedInstanceState) { // TODO 自动生成的方法存根 super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_layout); // 当前显示View的位置 */ int pagerPosition = 0; // 如果之前有保存用户数据 if (savedInstanceState != null) { pagerPosition = savedInstanceState.getInt(STATE_POSITION); } options = getSimpleOptions(); imageLoader = ImageLoader.getInstance(); pager = (ViewPager) findViewById(R.id.viewPager); pager.setAdapter(new ImagePagerAdapter(PicArrays.getPicArray())); pager.setCurrentItem(pagerPosition); } @Override public void onSaveInstanceState(Bundle outState) { // outState.putInt(STATE_POSITION, pager.getCurrentItem()); } /** * 设置常用的设置项 * * @return */ private DisplayImageOptions getSimpleOptions() { DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.loading) // 设置图片在下载期间显示的图片 .showImageForEmptyUri(R.drawable.ic_launcher)// 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.error) // 设置图片加载/解码过程中错误时候显示的图片 .cacheInMemory(true)// 设置下载的图片是否缓存在内存中 .cacheOnDisk(true)// 设置下载的图片是否缓存在SD卡中 .imageScaleType(ImageScaleType.IN_SAMPLE_INT)// 设置图片以如何的编码方式显示 .considerExifParams(true).bitmapConfig(Bitmap.Config.RGB_565)// 设置图片的解码类型 .build();// 构建完成 return options; } private class ImagePagerAdapter extends PagerAdapter { private String[] images; private LayoutInflater inflater; ImagePagerAdapter(String[] images) { this.images = images; inflater = getLayoutInflater(); } @Override public int getCount() { return images.length; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager) container).removeView((View) object); } @Override public Object instantiateItem(ViewGroup view, int position) { View viewLayout = inflater.inflate(R.layout.viewpager_item, view, false); ImageView imageView = (ImageView) viewLayout .findViewById(R.id.image); final ProgressBar spinner = (ProgressBar) viewLayout .findViewById(R.id.loading); imageLoader.displayImage(images[position], imageView, options, new SimpleImageLoadingListener() { @Override public void onLoadingStarted(String imageUri, View view) { spinner.setVisibility(View.VISIBLE); } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { String message = null; switch (failReason.getType()) { // 获取图片失败类型 case IO_ERROR: // 文件I/O错误 message = "Input/Output error"; break; case DECODING_ERROR: // 解码错误 message = "Image can't be decoded"; break; case NETWORK_DENIED: // 网络延迟 message = "Downloads are denied"; break; case OUT_OF_MEMORY: // 内存不足 message = "Out Of Memory error"; break; case UNKNOWN: // 原因不明 message = "Unknown error"; break; } Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); spinner.setVisibility(View.GONE); } @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { spinner.setVisibility(View.GONE); // 不显示圆形进度条 } }); ((ViewPager) view).addView(viewLayout, 0); // 将图片增加到ViewPager return viewLayout; } @Override public void finishUpdate(View container) { } } }
这里ViewPager的实现是通过动态加载的方式来做的,结合了进度条。很具有实用性!以前我们用ViewPager的时候是传入一个List<View>对象,在getView()中返回list.getindex(position)的方式来得到view对象。这里不传入view,直接在getView()中产生一个view,然后给view中加载图片。这种方式好处是节约了内存,要显示的时候才判断加载哪个对象;而坏处是没实现预加载,所以要配合进度条。在今后的改进中应该是预加载当前viewpager左右的图片,这样可以流畅的显示图片了~
源码下载:http://download.csdn.net/detail/shark0017/8055421
参考自:
http://blog.csdn.net/wwj_748/article/details/10079311
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?