Android图片选择器
本文是我的第二篇博客,如果有错误的地方,希望大家多多指点
本篇博客的主要内容是仿微信图片选择器,主要步骤有如下几点
- 图片加载类(单例)
- 获取手机本地图片
- 可以设置图片选择个数
第一步:核心方法:图片加载工具类 ImageLoader
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.FIFO;
/**
* 任务队列
*/
private LinkedList<Runnable> mTaskQueue;
/**
* 后台轮询线程
*/
private Thread mPoolThread;
private Handler mPoolThreadHandler;
/**
* UI线程的handler
*/
private Handler mUIHandler;
private Semaphore mSemaphorePoolThreadHandler = new Semaphore(0);
private Semaphore mSemaphoreThreadPool;
public enum Type {
FIFO, LIFO;
}
private ImageLoader(int threadCount, Type type) {
init(threadCount, type);
}
/**
* 初始化
*
* @param threadCount
* @param type
*/
private void init(int threadCount, Type type) {
mPoolThread = new Thread() {
@Override
public void run() {
Looper.prepare();
mPoolThreadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 线程池去取出一个任务进行执行
mThreadPool.execute(getTask());
try {
mSemaphoreThreadPool.acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
// 释放一个信号量
mSemaphorePoolThreadHandler.release();
Looper.loop();
}
};
mPoolThread.start();
// 获取我们应用的最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheMemory = maxMemory / 4;
mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getRowBytes() * value.getHeight();
}
};
mThreadPool = Executors.newFixedThreadPool(threadCount);
mTaskQueue = new LinkedList<Runnable>();
mType = type;
mSemaphoreThreadPool = new Semaphore(threadCount);
}
/**
* 从任务队列取出一个方法
*
* @return
*/
private Runnable getTask() {
if (mType == Type.FIFO) {
return mTaskQueue.removeFirst();
} else if (mType == Type.LIFO) {
return mTaskQueue.removeLast();
}
return null;
};
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;
}
public void LoadImage(final String path, final ImageView imageView) {
imageView.setTag(path);
if (mUIHandler == null) {
mUIHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 获取得到图片.为imageview回调设置图片
ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
Bitmap bm = holder.bitmap;
if(bm!=null){
bm = Bitmap.createScaledBitmap(bm, 200, 200, true);
}
ImageView imageView = holder.imageView;
String path = holder.path;
if (imageView.getTag().toString().equals(path)) {
imageView.setImageBitmap(bm);
}
};
};
}
// 根据path在缓存中获取bitmap
Bitmap bm = getBitmapFromLruCache(path);
if (bm != null) {
referashBitmap(path, imageView, bm);
} else {
addTasks(new Runnable() {
@Override
public void run() {
// 加载图片
// 图片的压缩
// 1获得图片需要显示的大小
ImageSize imageSize = getImageViewSize(imageView);
// 2.压缩图片
Bitmap bm = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height);
// 3.把图片加入到缓存
addBitmapToLruCache(path, bm);
referashBitmap(path, imageView, bm);
mSemaphoreThreadPool.release();
}
});
}
}
private void referashBitmap(final String path, final ImageView imageView, Bitmap bm) {
Message message = Message.obtain();
ImgBeanHolder holder = new ImgBeanHolder();
holder.bitmap = bm;
holder.path = path;
holder.imageView = imageView;
message.obj = holder;
mUIHandler.sendMessage(message);
}
/**
* 将图片加入到缓存
*
* @param path
* @param bm
*/
protected void addBitmapToLruCache(String path, Bitmap bm) {
if (getBitmapFromLruCache(path) == null) {
if (bm != null) {
mLruCache.put(path, bm);
}
}
}
/**
* 根据图片需要显示的宽高进行啊压缩
*
* @param path
* @param width
* @param height
* @return
*/
protected Bitmap decodeSampledBitmapFromPath(String path, int width, int height) {
// h获取图片的宽和高,并不把图片加载到内存
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path);
options.inSampleSize = caculateInSampleSize(options, width, height);
// 使用获取到的InSampleSize再次解析图片
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
/**
* 根据需求的宽和高及实际的宽和高计算SampleSize
*
* @param options
* @param width
* @param height
* @return
*/
private int caculateInSampleSize(Options options, int reqWidth, int reqHeight) {
int width = options.outWidth;
int height = options.outWidth;
int inSampleSize = 1;
if (width > reqWidth || height > reqHeight) {
int widthRadio = Math.round(width * 1.0f / reqWidth);
int hegihtRadio = Math.round(height * 1.0f / reqHeight);
inSampleSize = Math.max(widthRadio, hegihtRadio);
}
return inSampleSize;
}
/**
* 根据ImageView返回图片的大小
*
* @param imageView
*/
@SuppressLint("NewApi")
protected ImageSize getImageViewSize(ImageView imageView) {
ImageSize imageSize = new ImageSize();
DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();
LayoutParams lp = imageView.getLayoutParams();
int width = imageView.getWidth();// (lp.width ==
// LayoutParams.WRAP_CONTENT ? 0 :
// imageView.getWidth());
if (width <= 0) {
width = lp.width;// 获取imageview在layout中声明的宽度
}
if (width <= 0) {
width = imageView.getMaxWidth();
}
if (width <= 0) {
width = displayMetrics.widthPixels;
}
int height = imageView.getHeight();
if (height <= 0) {
height = lp.height;// 获取imageview在layout中声明的高度
}
if (height <= 0) {
height = imageView.getMaxHeight();
}
if (height <= 0) {
height = displayMetrics.heightPixels;
}
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
private synchronized void addTasks(Runnable runnable) {
mTaskQueue.add(runnable);
// if(mPoolThreadHandler==null)
try {
if (mPoolThreadHandler == null) {
mSemaphorePoolThreadHandler.acquire();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
mPoolThreadHandler.sendEmptyMessage(0x110);
}
/**
*
* @param path
* @return
*/
private Bitmap getBitmapFromLruCache(String path) {
return null;
}
private class ImageSize {
int width;
int height;
}
private class ImgBeanHolder {
Bitmap bitmap;
ImageView imageView;
String path;
}
}
第二步:主界面设计
主界面布局
<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"
android:background="@drawable/set_bg"
tools:context="${relativePackage}.${activityClass}" >
<RelativeLayout
android:id="@+id/top"
android:layout_width="match_parent"
android:layout_height="50dip"
android:background="#0079cd" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/return_icon" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="图片"
android:textColor="#FFFFFF"
android:textSize="19sp" />
<TextView
android:id="@+id/select_image"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="10dp"
android:background="@drawable/finish_btn"
android:gravity="center"
android:text="完成(0/3)"
android:textColor="#FFFFFF"
android:textSize="16sp" />
</RelativeLayout>
<GridView
android:id="@+id/id_gridView"
android:layout_marginTop="3dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/top"
android:cacheColorHint="@android:color/transparent"
android:horizontalSpacing="3dip"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="3dp" >
</GridView>
<RelativeLayout
android:id="@+id/id_bottom_ly"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#88000000"
android:clickable="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:text="所有图片"
android:textColor="#e5e5e5"
android:textSize="15sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="5dip"
android:layout_toRightOf="@+id/id_dir_name"
android:src="@drawable/more_select" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="5dip"
android:layout_toLeftOf="@+id/id_dir_num"
android:src="@drawable/split_line" />
<TextView
android:id="@+id/id_dir_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingRight="10dp"
android:text="预览"
android:textSize="15sp"
android:textColor="@android:color/white" />
</RelativeLayout>
</RelativeLayout>
定义列表
- Markdown Extra 定义列表语法:
- 项目1
- 项目2
- 定义 A
- 定义 B
- 项目3
- 定义 C
-
定义 D
定义D内容
代码块
代码块语法遵循标准markdown代码,例如:
@requires_authorization
def somefunc(param1='', param2=0):
'''A docstring'''
if param1 > param2: # interesting
print 'Greater'
return (param2 - param1 + 1) or None
class SomeClass:
pass
>>> message = '''interpreter
... prompt'''
脚注
生成一个脚注1.
目录
用 [TOC]
来生成目录:
数学公式
使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.
- 行内公式,数学公式为:
Γ(n)=(n−1)!∀n∈N 。 - 块级公式:
更多LaTex语法请参考 这儿.
UML 图:
可以渲染序列图:
或者流程图:
离线写博客
即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。
用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。
博客发表后,本地缓存将被删除。
用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。
注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱。
浏览器兼容
- 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
- IE9以下不支持
- IE9,10,11存在以下问题
- 不支持离线功能
- IE9不支持文件导入导出
- IE10不支持拖拽文件导入
- 这里是 脚注 的 内容. ↩
作者:waa_0618 发表于2016/9/14 17:15:48 原文链接
阅读:110 评论:0 查看评论