1、概述
图片选择器也是在APP开发中常见的一个功能,检索手机本地的所有图片以GridView的形式显示在界面上,看起来一个简单的功能,但是要想要尽量避免内存溢出,还想要UI操作尽可能的流畅图片加载尽可能的快速,也不是简单的一个setImageBitmap就可以的。
2、运行效果
效果图:
测试手机里存储了近万张漫画图片,每个文件夹也有上千张图片,可以看到加载速度和运行流畅程度还是可以的。
3、代码结构
代码的主要思路先实现了一个异步加载图片的ImageLoader类,通过这个类进行图片的加载。其他界面部分的代码就比较简单,通过ContentResolver获取图片文件路径按文件夹区分,通过ImageLoader将图片加载到GridView中,默认最多图片文件夹,点击下方的layout布局弹出一个popwindow,选择其他文件夹,更新界面。
ImageLoader结构图:
4、具体代码
ImageLoader.java
package com.example.sy.a20170604.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LruCache;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* Created by SY on 2017/6/4.
*/
public class ImageLoader {
private static ImageLoader mInstance;
//图片缓存
private LruCache<String, Bitmap> mLruCache;
//线程池
private ExecutorService mThreadPool;
private static final int DEFAULT_THREAD_COUNT = 1;
//队列调度方式
private Type mType = Type.LIFO;
//任务队列
private LinkedList<Runnable> mTaskQueue;
//后台轮询线程
private Thread mPoolThread;
private Handler mPoolTheadHandler;
//UI线程Handler
private Handler mUIHandler;
//mPoolTheadHandler初始化的信号量
private Semaphore mSemaphorePoolTheadHandler = new Semaphore(0);
//同时可并行执行线程的信号量
private Semaphore mSemaphoreThreadPool;
//队列调度方式枚举
public enum Type {
FIFO, LIFO;
}
private ImageLoader(int threadCount, Type type) {
init(threadCount, type);
}
private void init(int threadCount, Type type) {
//后台轮询线程
mPoolThread = new Thread() {
@Override
public void run() {
Looper.prepare();
mPoolTheadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//线程池去取出一个任务执行
mThreadPool.execute(getTask());
try {
mSemaphoreThreadPool.acquire();
} catch (InterruptedException e) {
Log.e("ImageLoader",e.getMessage());
}
}
};
//初始化完成,释放一个信号量
mSemaphorePoolTheadHandler.release();
Looper.loop();
}
};
mPoolThread.start();
int maxMemory = (int) Runtime.getRuntime().maxMemory();//应用最大可用内存
int cacheMeory = maxMemory / 4;
mLruCache = new LruCache<String, Bitmap>(cacheMeory) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
//创建线程池
mThreadPool = Executors.newFixedThreadPool(threadCount);
mTaskQueue = new LinkedList<Runnable>();
mType = type;
mSemaphoreThreadPool = new Semaphore(threadCount);
}
//从任务队列取出一个任务
private Runnable getTask() {
if (mType == Type.FIFO) {
return mTaskQueue.removeFirst();
} else if (mType == Type.LIFO) {
return mTaskQueue.removeLast();
}
return null;
}
/**
* 设置图片
*
* @param path
* @param imageView
*/
public void loadImage(final String path, final ImageView imageView) {
imageView.setTag(path);
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//获得图片,为imageview回调设置图片
ImageBeanHolder holder = (ImageBeanHolder) msg.obj;
Bitmap bm = holder.bitmap;
ImageView imageView = holder.imageView;
String path = holder.path;
//将path与gettag进行比较,防止图片错乱
if (imageView.getTag().toString().equalsIgnoreCase(path)) {
imageView.setImageBitmap(bm);
}
}
};
}
Bitmap bm = getBipmapFromLruCache(path);
if (bm != null) {
refresashBitmap(path, imageView, bm);
} else {
addTasks(new Runnable() {
@Override
public void run() {
//加载图片
//1、获得图片需要现实的大小
ImageSize imageSize = getImageViewSize(imageView);
//2、压缩图片
Bitmap bitmap = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height);
//3、图片计入缓存
addBitmapToCache(path, bitmap);
refresashBitmap(path, imageView, bitmap);
mSemaphoreThreadPool.release();
}
});
}
}
public void refresashBitmap(String path, ImageView imageView, Bitmap bm) {
Message message = Message.obtain();
ImageBeanHolder holder = new ImageBeanHolder();
holder.bitmap = bm;
holder.imageView = imageView;
holder.path = path;
message.obj = holder;
mUIHandler.sendMessage(message);
}
/**
* 图片加入缓存
*
* @param path
* @param bm
*/
private void addBitmapToCache(String path, Bitmap bm) {
if (getBipmapFromLruCache(path) == null) {
if (bm != null) {
mLruCache.put(path, bm);
}
}
}
/**
* 压缩图片
*
* @param path
* @param width
* @param height
* @return
*/
private Bitmap decodeSampledBitmapFromPath(String path, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//图片不加载入内存
BitmapFactory.decodeFile(path, options);
options.inSampleSize = caculateInSampleSize(options, width, height);
//使用inSampleSize再次解析图片
options.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile(path, options);
return bm;
}
/**
* 根据传入的宽高和实际宽高计算inSampleSize
*
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
private int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (width > reqWidth || height > reqHeight) {
int widthRadio = Math.round(width * 1.0f / reqWidth);
int heightRadio = Math.round(height * 1.0f / reqHeight);
inSampleSize = Math.max(widthRadio, heightRadio);
}
return inSampleSize;
}
/**
* 根据imageview获取适当的压缩的图片宽高
*
* @param imageView
* @return
*/
protected ImageSize getImageViewSize(ImageView imageView) {
ImageSize size = new ImageSize();
DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
int width = imageView.getWidth();//获取imageview实际宽度
if (width <= 0) {
width = layoutParams.width;//获取image在layout里设置的宽度
}
if (width <= 0) {
// width = imageView.getMaxWidth();//检查最大值 此方法API16以上
width = getImageViewFieldValue(imageView,"mMaxWidth");
}
if (width <= 0) {
width = displayMetrics.widthPixels;//屏幕宽度
}
int height = imageView.getHeight();
if (height <= 0) {
height = layoutParams.height;
}
if (height <= 0) {
// height = imageView.getMaxHeight();
height = getImageViewFieldValue(imageView,"mMaxHeight");
}
if (height <= 0) {
height = displayMetrics.heightPixels;
}
size.width = width;
size.height = height;
return size;
}
/**
* 通过反射获取imageview的某个属性值
*
* @param object
* @param fieldName
* @return
*/
private static int getImageViewFieldValue(Object object, String fieldName) {
int value = 0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);//设置为允许访问
int fieldValue = field.getInt(object);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
value = fieldValue;
}
} catch (Exception e) {
Log.e("ImageLoader",e.getMessage());
}
return value;
}
private synchronized void addTasks(Runnable runnable) {
mTaskQueue.add(runnable);
try {
if (mPoolTheadHandler == null)
//保证mPoolTheadHandler已经初始化,如果为null请求一个信号量,默认为0,故停止等待mPoolTheadHandler初始化
mSemaphorePoolTheadHandler.acquire();
} catch (InterruptedException e) {
Log.e("ImageLoader",e.getMessage());
}
mPoolTheadHandler.sendEmptyMessage(0x110);
}
/**
* 根据path在缓存中获取图片
*
* @param path
* @return
*/
private Bitmap getBipmapFromLruCache(String path) {
return mLruCache.get(path);
}
private class ImageBeanHolder {
Bitmap bitmap;
ImageView imageView;
String path;
}
private class ImageSize {
int width;
int height;
}
public static ImageLoader getInstance() {
if (mInstance == null) {
synchronized (ImageLoader.class) {
if (mInstance == null) {
mInstance = new ImageLoader(DEFAULT_THREAD_COUNT, Type.LIFO);
}
}
}
return mInstance;
}
public static ImageLoader getInstance(int threadCount, Type type) {
if (mInstance == null) {
synchronized (ImageLoader.class) {
if (mInstance == null) {
mInstance = new ImageLoader(threadCount, type);
}
}
}
return mInstance;
}
}
使用单例模式,给出获得单例对象的方法getInstance();首先构造函数中执行init()初始化方法,初始化后台轮询线程,初始化后台轮询线程Handler和线程池和任务队列。接着看loadImage()方法,传入图片路径和一个imageview,通过getBipmapFromLruCache()方法在LruCache里根据路径url寻找图片,如果找到执行refresashBitmap()方法,设置图片到imageview。如果在LruCache里没有该图片,则新建一个Runnable任务 Task通过addTask()方法将任务加入到TaskQueue里,并通过mPoolTheadHandler发送消息通知后台轮询线程,后台轮询线程收到消息后从TaskQueue里取出任务放入从线程池中取出的子线程里执行。Task任务Runnable的run方法里执行具体的加载图片方法。通过getImageViewSize()方法获得图片适合大小,根据传进来的图片url路径用decodeSampledBitmapFromPath()压缩并且BitmapFactory.decodeFile()得到图片的Bitmap对象,接着将图片放入LruCache缓存,最后调用refresashBitmap()方法设置图片到imageview。除此之外,代码中使用了信号量类Semaphore,来保证在addTask()方法中发送消息时mPoolTheadHandler已经初始化,若未初始化则线程无法获取到信号量线程暂停,直到后台轮询线程初始化完成mPoolTheadHandler释放信号量。同样在后台轮询线程在任务队列中拿去任务时同样需要使用信号量控制同时并行执行的线程数量,来实现任务队列TaskQueue的队列不同调度方式。
MainActivity.java
package com.example.sy.a20170604;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.annotation.Size;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.GridView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.sy.a20170604.adapter.ImageListAdapter;
import com.example.sy.a20170604.bean.FolderBean;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private GridView mGridView;
private RelativeLayout mBottomLy;
private TextView mDirName;
private TextView mDirCount;
private List<String> mImages ;
private File mCurrentDir;
private int mMaxCount;
private ImageListAdapter adapter;
private ProgressDialog progressDialog;
private List<FolderBean> folderBeans = new ArrayList<FolderBean>();
private ListImageDirPopupWindow popupWindow;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x110) {
progressDialog.dismiss();
data2View();
initDirPopupWindow();
}
}
};
private void initDirPopupWindow() {
popupWindow = new ListImageDirPopupWindow(this, folderBeans);
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
lightOn();
}
});
popupWindow.setOnDirSelectedListener(new ListImageDirPopupWindow.OnDirSelectedListener() {
@Override
public void onSelected(FolderBean folderBean) {
//更新adapter
mCurrentDir = new File(folderBean.getDir());
mImages = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
@Override
public boolean accept(File file, String filename) {
if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
filename.endsWith(".jepg")){
return true;
}
return false;
}
}));
adapter = new ImageListAdapter(MainActivity.this, mImages, mCurrentDir.getAbsolutePath());
mGridView.setAdapter(adapter);
Log.e("Size",mImages.size() + "");
mDirCount.setText(mImages.size() + "");
mDirName.setText(mCurrentDir.getName());
popupWindow.dismiss();
}
});
}
private void data2View() {
if (mCurrentDir == null) {
Toast.makeText(this, "未扫描到任何图片", Toast.LENGTH_SHORT).show();
return;
}
mImages = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
@Override
public boolean accept(File file, String filename) {
if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
filename.endsWith(".jepg")){
return true;
}
return false;
}
}));
setGridViewAdapter();
}
private void lightOn() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 1.0f;
getWindow().setAttributes(lp);
}
private void lightOff() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 0.3f;
getWindow().setAttributes(lp);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDatas();
initEvent();
}
private void initEvent() {
mBottomLy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.setAnimationStyle(R.style.dir_popupwindow_anim);
popupWindow.showAsDropDown(mBottomLy, 0, 0);
lightOff();
}
});
}
/**
* 利用ContentProvider扫描手机中的所有图片
*/
private void initDatas() {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
Toast.makeText(getApplicationContext(), "当前存储卡不可用!", Toast.LENGTH_SHORT).show();
return;
}
progressDialog = ProgressDialog.show(this, null, "正在加载...");
new Thread() {
@Override
public void run() {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver contentResolver = MainActivity.this.getContentResolver();
String select = MediaStore.Images.Media.MIME_TYPE + " = ? or " + MediaStore.Images.Media.MIME_TYPE + " = ?";
Cursor cursor = contentResolver.query(uri, null, select, new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_MODIFIED);
Set<String> mDirPaths = new HashSet<String>();
while (cursor.moveToNext()) {
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
File parentFile = new File(path).getParentFile();
if (parentFile == null) {
continue;
}
String dirPath = parentFile.getAbsolutePath();
FolderBean bean = null;
if (mDirPaths.contains(dirPath)) {
continue;
} else {
mDirPaths.add(dirPath);
bean = new FolderBean();
bean.setDir(dirPath);
bean.setFirstImgPath(path);
}
if (parentFile.list() == null) {
continue;
}
int picSize = parentFile.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if (filename.endsWith(".jpg") || filename.endsWith(".png") ||
filename.endsWith(".jepg")){
return true;
}
return false;
}
}).length;
bean.setCount(picSize);
folderBeans.add(bean);
if (picSize > mMaxCount) {
mMaxCount = picSize;
mCurrentDir = parentFile;
}
}
cursor.close();
//通知 扫描图片完成
mHandler.sendEmptyMessage(0x110);
}
}.start();
}
private void initView() {
mGridView = (GridView) findViewById(R.id.id_gridview);
mBottomLy = (RelativeLayout) findViewById(R.id.id_bottom_rl);
mDirName = (TextView) findViewById(R.id.id_dir_name);
mDirCount = (TextView) findViewById(R.id.id_dir_count);
}
private void setGridViewAdapter() {
adapter = new ImageListAdapter(this, mImages, mCurrentDir.getAbsolutePath());
mGridView.setAdapter(adapter);
mDirCount.setText(mMaxCount + "");
mDirName.setText(mCurrentDir.getName());
}
}
在onCreate()方法里initView()方法初始化界面控件;initDatas()方法里new子线程在里面通过使用ContentResolver获取图片文件信息,将图片文件夹信息封装到一个FolderBean里,获取图片信息结束后通过Handler发送消息,通知主线程执行data2View()方法加载图片显示到界面的GridView里,并且初始化更换文件夹的popwindow;最后initEvent()方法里设置了点击下方的layout弹出popwindow的事件。
FolderBean.java
package com.example.sy.a20170604.bean;
/**
* Created by SY on 2017/6/4.
*/
public class FolderBean {
private String dir;//文件夹路径
private String firstImgPath;
private int count;
private String name;//文件夹名称
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
int lastIndexof = this.dir.lastIndexOf("/");
this.name = this.dir.substring(lastIndexof);
}
public String getFirstImgPath() {
return firstImgPath;
}
public void setFirstImgPath(String firstImgPath) {
this.firstImgPath = firstImgPath;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ImageListAdapter.java
package com.example.sy.a20170604.adapter;
import android.content.Context;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import com.example.sy.a20170604.R;
import com.example.sy.a20170604.utils.ImageLoader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ImageListAdapter extends BaseAdapter {
private static Set<String> mSelectImgs = new HashSet<String>();
private List<String> mDatas;
private String dirPath;
private LayoutInflater inflater;
private int mScreenWidth;
public ImageListAdapter(Context context, List<String> mDatas, String dirPath) {
this.mDatas = mDatas;
this.dirPath = dirPath;
this.inflater = LayoutInflater.from(context);
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;//获取屏幕宽度
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public Object getItem(int position) {
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder ;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_gridview, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.id_item_img);
viewHolder.imageButton = (ImageButton) convertView.findViewById(R.id.id_item_select);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
//重置状态
viewHolder.imageView.setImageResource(R.mipmap.icon_default_img);
viewHolder.imageView.setColorFilter(null);
viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_off_grid);
viewHolder.imageView.setMaxWidth(mScreenWidth / 3);//ImageLoader 进行图片压缩的时候可能会用到 减少内存使用
ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(dirPath + "/" + mDatas.get(position),
viewHolder.imageView);
final String filePath = dirPath + "/" + mDatas.get(position);
viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mSelectImgs.contains(filePath)) {
mSelectImgs.remove(filePath);
viewHolder.imageView.setColorFilter(null);
viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_off_grid);
}else {
mSelectImgs.add(filePath);
viewHolder.imageView.setColorFilter(Color.parseColor("#77000000"));
viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_on_grid);
}
}
});
if (mSelectImgs.contains(filePath)) {
viewHolder.imageView.setColorFilter(Color.parseColor("#77000000"));
viewHolder.imageButton.setImageResource(R.mipmap.icon_file_check_on_grid);
}
return convertView;
}
private class ViewHolder {
ImageView imageView;
ImageButton imageButton;
}
}
ListImageDirPopupWindow.java
package com.example.sy.a20170604;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.example.sy.a20170604.bean.FolderBean;
import com.example.sy.a20170604.utils.ImageLoader;
import java.util.List;
/**
* Created by SY on 2017/6/4.
*/
public class ListImageDirPopupWindow extends PopupWindow {
private int width;
private int height;
private View mConvertView;
private ListView mListView;
private List<FolderBean> mDatas;
public interface OnDirSelectedListener {
void onSelected(FolderBean folderBean);
}
private OnDirSelectedListener listener;
public void setOnDirSelectedListener(OnDirSelectedListener listener) {
this.listener = listener;
}
public ListImageDirPopupWindow(Context context, List<FolderBean> mDatas) {
super(context);
this.mDatas = mDatas;
calWidthAndHeight(context);
mConvertView = LayoutInflater.from(context).inflate(R.layout.popup_main, null);
setContentView(mConvertView);
setWidth(width);
setHeight(height);
setFocusable(true);
setTouchable(true);
setOutsideTouchable(true);
setBackgroundDrawable(new BitmapDrawable());
setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
}
return false;
}
});
initViews(context);
initEvent();
}
private void initViews(Context context) {
mListView = (ListView) mConvertView.findViewById(R.id.id_dir_list);
mListView.setAdapter(new ListDirAdapter(context, mDatas));
}
private void initEvent() {
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(listener!=null) {
listener.onSelected(mDatas.get(position));
}
}
});
}
/**
* 计算高度和宽度
* 宽度和屏幕一样
* 高度是75%的屏幕
* @param context
*/
private void calWidthAndHeight(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
width = displayMetrics.widthPixels;
height = (int) (displayMetrics.heightPixels * 0.75 );
}
private class ListDirAdapter extends ArrayAdapter<FolderBean> {
private LayoutInflater inflater;
public ListDirAdapter(Context context, List<FolderBean> objects) {
super(context, 0, objects);
inflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder =null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.item_popup, parent, false);
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.id_dir_item_image);
viewHolder.nameTv = (TextView) convertView.findViewById(R.id.id_dir_item_name);
viewHolder.countTv = (TextView) convertView.findViewById(R.id.id_dir_item_count);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
FolderBean bean = getItem(position);
viewHolder.imageView.setImageResource(R.mipmap.icon_default_img);
ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(bean.getFirstImgPath(), viewHolder.imageView);
viewHolder.nameTv.setText(bean.getName());
viewHolder.countTv.setText(bean.getCount() + "");
return convertView;
}
private class ViewHolder {
ImageView imageView;
TextView nameTv;
TextView countTv;
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<GridView
android:id="@+id/id_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3"
android:stretchMode="columnWidth"
android:cacheColorHint="@android:color/transparent"
android:listSelector="@android:color/transparent"
android:horizontalSpacing="3dp"
android:verticalSpacing="3dp">
</GridView>
<RelativeLayout
android:id="@+id/id_bottom_rl"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#ee000000"
android:clipChildren="true">
<TextView
android:id="@+id/id_dir_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:paddingLeft="10dp"
android:textColor="@android:color/white"
android:text="所有图片"/>
<TextView
android:id="@+id/id_dir_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingRight="10dp"
android:textColor="@android:color/white"
android:text="0"/>
</RelativeLayout>
</RelativeLayout>
item_popup.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:id="@+id/id_dir_item_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentLeft="true"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingBottom="17dp"
android:paddingTop="9dp"
android:scaleType="fitXY"
android:src="@mipmap/icon_default_img"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/id_dir_item_image"
android:orientation="vertical">
<TextView
android:id="@+id/id_dir_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="文件夹"/>
<TextView
android:id="@+id/id_dir_item_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="10sp"
android:textColor="#444"
android:text="1112"/>
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:src="@mipmap/icon_file_check_off_grid"/>
</RelativeLayout>
5、参考资料
Android 超高仿微信图片选择器 图片该这么加载 - Hongyang - 博客频道 - CSDN.NET
http://blog.csdn.net/lmj623565791/article/details/39943731
Android-仿微信图片选择器-慕课网
http://www.imooc.com/learn/489