Android学习笔记:实现图片选择器功能(下)

     上一篇笔记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;
}
}

你可能感兴趣的:(Android开发,图片,图像处理)