上一篇笔记Andorid学习笔记:实现图片选择器功能(上)讲了这次学习的图片选择器实现基本目的及方法,今天就把学习的代码贴上来,方便下次使用,我是懒人一个,呵呵!
主界面,布局就一个GridView就不贴了:
public class MainActivity extends Activity {
/* 图片展示GridView* */
private GridView mgGridView;
/* 文件名及数量TextView* */
private TextView nameTv, numberTv;
/* 点击选择文件Popupwindow* */
private RelativeLayout mSelectRela;
/* 数据加载时的进度条* */
private ProgressDialog mLoadingDialog;
/* popupWindow* */
private MyPopupWindow mPopupWindow;
private int mMaxCount;
private File mCurrentDir;
private List<String> mImgs = new ArrayList<String>();
private final static int HAND_NUMBER = 1;
private List<ImageFolder> beans = new ArrayList<ImageFolder>();
private GridViewAdapter adapter;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == HAND_NUMBER) {
mLoadingDialog.dismiss();
/* 设置数据* */
setDataToViews();
initPopupWindows();
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initListeners();
initDatas();
}
/**
* 设置弹出popupwindow
* @description:
* @date 2015-9-18 下午2:28:38
*/
protected void initPopupWindows() {
mPopupWindow = new MyPopupWindow(this, beans);
mPopupWindow.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
changeLight(1.0f);
}
});
mPopupWindow.setOnItemClick(new OnItemClickImpl() {
@Override
public void onItemClick(ImageFolder bean) {
mCurrentDir = new File(bean.getDir());
mImgs = Arrays.asList(mCurrentDir.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png")) return true;
return false;
}
}));
adapter = new GridViewAdapter(MainActivity.this, mImgs, mCurrentDir.getAbsolutePath());
numberTv.setText(mImgs.size() + "");
nameTv.setText(bean.getName());
mgGridView.setAdapter(adapter);
}
});
}
/**
* 改变屏幕亮度
* @description:
* @date 2015-9-18 下午2:36:08
*/
protected void changeLight(float alpha) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = alpha;
getWindow().setAttributes(lp);
}
protected void setDataToViews() {
if (mCurrentDir == null) {
Toast.makeText(MainActivity.this, "文件不存在", Toast.LENGTH_SHORT).show();
return;
}
mImgs = Arrays.asList(mCurrentDir.list());
adapter = new GridViewAdapter(this, mImgs, mCurrentDir.getAbsolutePath());
numberTv.setText(adapter.getCount() + "");
nameTv.setText(mCurrentDir.getName());
mgGridView.setAdapter(adapter);
}
/**
* 初始化控件
* @description:
* @date 2015-9-14 下午1:53:31
*/
private void initViews() {
mgGridView = (GridView) findViewById(R.id.pic_gv);
nameTv = (TextView) findViewById(R.id.file_name);
numberTv = (TextView) findViewById(R.id.file_number);
mSelectRela = (RelativeLayout) findViewById(R.id.select_rela);
}
/**
* 监听处理
* @description:
* @date 2015-9-14 下午1:53:45
*/
private void initListeners() {
mSelectRela.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mSelectRela.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mPopupWindow != null) {
mPopupWindow.setAnimationStyle(R.style.pop_style);//设置动画
mPopupWindow.showAsDropDown(mSelectRela, 0, 0);
changeLight(0.3f);
}
}
});
}
});
}
/**
* 设置数据
* @description:
* @date 2015-9-14 下午1:53:53
*/
private void initDatas() {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {// 判断手机内存卡是否可使用
Toast.makeText(MainActivity.this, "当前手机SD卡不能使用", Toast.LENGTH_SHORT).show();
return;
}
mLoadingDialog = ProgressDialog.show(MainActivity.this, null, "数据加载中...");
new Thread() {// 耗时操作,新开线程
@Override
public void run() {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(uri, null, MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?", 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();
ImageFolder bean = null;
if (mDirPaths.contains(dirPath)) {
continue;
}
else {
mDirPaths.add(dirPath);
bean = new ImageFolder();
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(".jpeg") || filename.endsWith(".png")) return true;
return false;
}
}).length;
bean.setCount(picSize);
beans.add(bean);
if (picSize > mMaxCount) {
mMaxCount = picSize;
mCurrentDir = parentFile;
}
cursor.close();
/* 扫描图片完成,发送handler信息* */
mHandler.sendEmptyMessage(HAND_NUMBER);
}
}
}.start();
}
}
GridView的适配器:
public class GridViewAdapter extends BaseAdapter {
private Context context;
private List<String> mDatas;
private String dirPath;
private LayoutInflater inflater;
private List<String> seltctList;
public GridViewAdapter(Context context, List<String> mDatas, String dirPath) {
this.context = context;
this.mDatas = mDatas;
this.dirPath = dirPath;
inflater = LayoutInflater.from(context);
seltctList = new ArrayList<String>();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item_gridview, null);
holder.itemIv = (ImageView) convertView.findViewById(R.id.item_iv);
holder.itemIbt = (ImageButton) convertView.findViewById(R.id.item_ibt);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.itemIv.setImageResource(R.drawable.item_default);
holder.itemIbt.setImageResource(R.drawable.unselect_bg);
ImageLoader.getInstance().loadImage(dirPath + "/" + mDatas.get(position), holder.itemIv);
final String filePath = dirPath + "/" + mDatas.get(position);
holder.itemIv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (seltctList.contains(filePath)) {
seltctList.remove(filePath);
holder.itemIv.setColorFilter(null);
holder.itemIbt.setImageResource(R.drawable.elect_bg);
}
else {
seltctList.add(filePath);
holder.itemIbt.setImageResource(R.drawable.unselect_bg);
}
}
});
return convertView;
}
class ViewHolder {
ImageView itemIv;
ImageButton itemIbt;
}
}
点击弹出的PopupWindow自定义类,涉及到的布局就只一个ListView:
public class MyPopupWindow extends PopupWindow {
private int mWidth;
private int mHeight;
private ListView popupLv;
private List<ImageFolder> mDatas;
private Context context;
private View mMainView;
private OnItemClickImpl onItemListener;
public void setOnItemClick(OnItemClickImpl onItemListener) {
this.onItemListener = onItemListener;
}
public MyPopupWindow(Context context, List<ImageFolder> mDatas) {
this.context = context;
this.mDatas = mDatas;
intWidthAndHeight();
mMainView = LayoutInflater.from(context).inflate(R.layout.pic_popupwindow, null);
setContentView(mMainView);
setHeight(mHeight);
setWidth(mWidth);
setFocusable(true);
setTouchable(true);
setOutsideTouchable(true);
setBackgroundDrawable(new BitmapDrawable());
setTouchInterceptor(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
}
return false;
}
});
initViewsAndEvents();
}
/**
* 初始化PopupWindow中的控件
* @description:
* @date 2015-9-18 下午1:45:58
*/
private void initViewsAndEvents() {
popupLv = (ListView) mMainView.findViewById(R.id.popupwindow_lv);
popupLv.setAdapter(new PopupAdapter(context, mDatas));
popupLv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
if (onItemListener != null) {
onItemListener.onItemClick(mDatas.get(arg2));
}
}
});
}
/**
* 设置PopupWindow的高度
* @description:
* @date 2015-9-18 下午1:34:27
*/
private void intWidthAndHeight() {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);// 获取系统服务中的WindowManager
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
mWidth = metrics.widthPixels;
mHeight = (int) (metrics.heightPixels * 0.7);// 设置高度为屏幕高度的70%
}
private class PopupAdapter extends ArrayAdapter<ImageFolder> {
private LayoutInflater mLayoutInflater;
public PopupAdapter(Context context, List<ImageFolder> objects) {
super(context, 0, objects);
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.item_popupwindow, null);
holder.itemPic = (ImageView) convertView.findViewById(R.id.item_pop_image);
holder.nameTv = (TextView) convertView.findViewById(R.id.item_pop_file_name);
holder.numberTv = (TextView) convertView.findViewById(R.id.item_pop_image);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.itemPic.setImageResource(R.drawable.item_default);
ImageFolder bean = getItem(position);
if (bean != null) {
ImageLoader.getInstance().loadImage(bean.getFirstImgPath(), holder.itemPic);
holder.nameTv.setText(bean.getName());
holder.numberTv.setText(bean.getCount() + "");
}
return convertView;
}
private class ViewHolder {
ImageView itemPic;// 显示的图片
TextView nameTv;// 图库名称
TextView numberTv;// 图库文件数量
}
}
public interface OnItemClickImpl {
void onItemClick(ImageFolder bean);
}
关键的图片处理类:
public class ImageLoader {
private static ImageLoader mImageLoader;
/* 枚举定义加载方式(先进先出还是后进先出)* */
public enum LoadType {
FIFO, LIFO;
}
/* 图片缓存对象* */
private LruCache<String, Bitmap> mLruCache;
/* 线程池* */
private ExecutorService mExecutorService;
/* 线程数量* */
private static final int DEFAULT_THREAD_NUM = 1;
/* 任务队列* */
private LinkedList<Runnable> mTaskQueue;
/* 后台执行线程* */
private Thread mThread;
/* 线程通知handler* */
private Handler mThreadHandler;
/* UI更新handler* */
private Handler mUIHandler;
/* 队列的方式* */
private LoadType mLoadType = LoadType.LIFO;
private Semaphore mThreadSemaphore = new Semaphore(0);
private Semaphore mSemaphorePool;
private ImageLoader(int threadNum, LoadType type) {
init(threadNum, type);
}
/**
* 单例模式
* @description:
* @date 2015-9-8 下午7:10:32
*/
public static ImageLoader getInstance() {
if (mImageLoader == null) {
synchronized (ImageLoader.class) {
if (mImageLoader == null) {
mImageLoader = new ImageLoader(DEFAULT_THREAD_NUM, LoadType.LIFO);
}
}
}
return mImageLoader;
}
/**
* 初始化变量
* @description:
* @date 2015-9-8 下午8:05:45
*/
private void init(int threadNum, LoadType type) {
/* 后台操作线程 * */
mThread = new Thread() {
@Override
public void run() {
Looper.prepare();
mThreadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
/* 取线程池中一线程并执行* */
mExecutorService.execute(getRunTask());
try {
// 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
mSemaphorePool.acquire();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mThreadSemaphore.release();// 释放一个许可,将其返回给信号量。
Looper.loop();
}
};
mThread.start();
int max = (int) Runtime.getRuntime().maxMemory();// 获取应用可用最大内存
int cacheSize = max / 8;// 设置缓存大小为最大内存的八分之一
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
mExecutorService = Executors.newFixedThreadPool(threadNum);// 可重用固定线程数的线程池
mTaskQueue = new LinkedList<Runnable>();
mLoadType = type;
mSemaphorePool = new Semaphore(threadNum);
}
/**
* 根据选择的队列方式从任务队列中取出一个Runable
* @description:
* @date 2015-9-8 下午10:11:19
*/
private Runnable getRunTask() {
if (mLoadType == LoadType.FIFO) {
return mTaskQueue.removeFirst();
}
else if (mLoadType == LoadType.LIFO) { return mTaskQueue.removeLast(); }
return mThread;
}
/**
* 根据图片path为ImageView设置图片
* @description:
* @date 2015-9-8 下午8:09:21
*/
public void loadImage(final String path, final ImageView imageView) {
/* 设置个tag标签,防止图片错位* */
imageView.setTag(path);
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
/* 获取得到的图片,为imageView回调设置图片* */
ImageBean bean = (ImageBean) msg.obj;
Bitmap bm = bean.bean_bitmap;
String path = bean.bean_path;
ImageView imageView = bean.bean_imageview;
/* 判断tag中路径 与path是否一致,以防图片错位* */
if (imageView.getTag().toString().equals(path)) {
imageView.setImageBitmap(bm);
}
}
};
}
/* 从缓存中取得图片* */
Bitmap bitmap = getBitmapFromCache(path);
if (null != bitmap) {
sendBitmapMessage(path, imageView, bitmap);
}
else {
/* 加载图片,需要对图片进行压缩* */
addImageTask(new Runnable() {
@Override
public void run() {
/* step1:获取图片需要显示的大小 * */
ImgSize size = getImgSize(imageView);
/* step2:压缩图片 * */
Bitmap bmp = decodeBitmapFromPath(path, size.width, size.height);
/* step3:把图片添加入缓存中* */
addBitmapToCache(path, bmp);
sendBitmapMessage(path, imageView, bmp);
mSemaphorePool.release();
}
});
}
}
private void sendBitmapMessage(final String path, final ImageView imageView, Bitmap bitmap) {
Message msg = Message.obtain();
ImageBean bean = new ImageBean();
bean.bean_bitmap = bitmap;
bean.bean_imageview = imageView;
bean.bean_path = path;
msg.obj = bean;
mUIHandler.sendMessage(msg);
}
/**
* 将图片加入到缓存LruCache中
* @description:
* @date 2015-9-9 上午12:44:29
*/
protected void addBitmapToCache(String path, Bitmap bmp) {
if (getBitmapFromCache(path) == null) {
if (bmp != null) {
mLruCache.put(path, bmp);
}
}
}
/**
* 压缩图片
* @description:
* @date 2015-9-8 下午10:29:38
*/
protected Bitmap decodeBitmapFromPath(String path, int width, int height) {
/* 用于获取图片的宽和高* */
BitmapFactory.Options options = new BitmapFactory.Options();
/* 设置并不把图片加载到内存中* */
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calSampleSize(options, width, height);
/* 使用获取到的inSampleSize再次解析 图片* */
options.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile(path, options);
return bm;
}
/**
* 根据需求的宽高及图片实际宽高计算出inSampleSize
* @description:
* @date 2015-9-9 上午12:35:21
*/
private int calSampleSize(Options options, int reqWidth, int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int sampleSize = 1;
if (width > reqWidth || height > reqHeight) {
int widthSize = Math.round(width * 1.0f / reqWidth);
int heightSize = Math.round(height * 1.0f / reqHeight);
sampleSize = Math.max(widthSize, heightSize);
}
return sampleSize;
}
/**
* 获取图片的宽高
* @description:
* @return
* @date 2015-9-8 下午10:17:30
*/
private ImgSize getImgSize(ImageView imageView) {
ImgSize size = new ImgSize();
LayoutParams lp = imageView.getLayoutParams();
/* 获取ImageView的实际宽度* */
int width = imageView.getWidth();
if (width <= 0) {
width = lp.width;// 获取ImageView在Layout中申明的宽度
}
if (width <= 0) {
// width = imageView.getMaxWidth();// 检查imageView的最大宽度
width = getViewFieldValue(imageView, "mMaxWidth");
}
if (width <= 0) {
width = imageView.getContext().getResources().getDisplayMetrics().widthPixels;// 设置为屏幕宽度
}
int height = imageView.getHeight();
if (height <= 0) {
height = lp.height;// 获取ImageView在Layout中申明的宽度
}
if (height <= 0) {
// height = imageView.getMaxHeight();// 检查imageView的最大宽度
height = getViewFieldValue(imageView, "mMaxHeight");
// 检查imageView的最大宽度
}
if (height <= 0) {
height = imageView.getContext().getResources().getDisplayMetrics().heightPixels;// 设置为屏幕宽度
}
size.height = height;
size.width = width;
return size;
}
/**
* 反射获取图片的大小
* @description:
* @date 2015-9-18 下午3:50:30
*/
private static int getViewFieldValue(Object obj, String fieldName) {
int value = 0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = field.getInt(obj);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
value = fieldValue;
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return value;
}
private synchronized void addImageTask(Runnable runnable) {
mTaskQueue.add(runnable);
try {
if (mThreadSemaphore == null) {
mThreadSemaphore.acquire();
}
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mThreadHandler.sendEmptyMessage(0);
}
private Bitmap getBitmapFromCache(String key) {
return mLruCache.get(key);
}
/***
* 图片实体bean
* @description:
* @date 2015-9-8 下午9:57:01
*/
class ImageBean {
Bitmap bean_bitmap;// 图片
ImageView bean_imageview;// imageView
String bean_path;// 路径
}
class ImgSize {
int width;
int height;
}
}
最后贴下布局及实体bean:
主页面中GridView的item布局:
<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"
>
<ImageView
android:id="@+id/item_iv"
android:layout_width="match_parent"
android:layout_height="100dp"
android:scaleType="centerCrop"
/>
<ImageButton
android:id="@+id/item_ibt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:background="@null"
android:src="@drawable/unselect_bg"
/>
</RelativeLayout>
PopupWindow中ListView的item布局:
<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="wrap_content" >
<ImageView
android:id="@+id/item_pop_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:padding="10dp"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_centerInParent="true"
android:layout_toRightOf="@id/item_pop_image"
android:orientation="vertical" >
<TextView
android:id="@+id/item_pop_file_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="所有图片"
android:textColor="#333333"
android:textSize="12sp" />
<TextView
android:id="@+id/item_pop_file_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="所有图片"
android:textColor="#333333"
android:textSize="10sp" />
</LinearLayout>
</RelativeLayout>
涉及到的实体类bean:
public class ImageFolder {
private String name;//名称
private String dir;//路径
private String firstImgPath;//首图路径
private int count;//数量
public String getName() {
return name;
}
public int getCount() {
return count;
}
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
int lastIndex = this.dir.lastIndexOf("/");
this.name = this.dir.substring(lastIndex);
}
public String getFirstImgPath() {
return firstImgPath;
}
public void setFirstImgPath(String firstImgPath) {
this.firstImgPath = firstImgPath;
}
public void setCount(int count) {
this.count = count;
}
}