本文是根据鸿祥大神的博客http://blog.csdn.net/lmj623565791/article/details/39943731进化而来,在大神的基础上更进一步封装拍照,防止oom,选择图片后回调。
效果如图所示,点击加号弹出dialog,可以选择从照相机拍照也可以选择从图库选择多张图片。
为了方变使用,封装了一个父类。在父类中进行dialog的点击事件响应并接收照相机的回调和多图选择后的回调,并对外提供两个接口,一个是选择单一图片的回调,一个是选择多图的回调。代码如下
public class SelectImageActivity extends AppCompatActivity{
protected CameraAlbumDialog mCameraDialog;
private Uri mUri;
//相机回调参数,
public static final int REQ_CAMERA = 0x01;
//系统图库参数
public static final int REQ_ALBUM = 0x02;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initCameraDialog();
}
public void initCameraDialog(){
mCameraDialog = new CameraAlbumDialog(this);
mCameraDialog.getWindow().setGravity(Gravity.BOTTOM);
// 拍照
mCameraDialog.setOnCameraClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadRealImgFromCamera();
mCameraDialog.dismiss();
}
});
// 相册
mCameraDialog.setOnAlbumClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadImgFromAlbum();
mCameraDialog.dismiss();
}
});
// 取消
mCameraDialog.setOnCancleClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCameraDialog.dismiss();
}
});
}
/**
* 跳转到另一个页面进行多图操作
*/
private void loadImgFromAlbum() {
Intent openAlbumIntent = new Intent(this, OpenAlbumActivity.class);
startActivityForResult(openAlbumIntent,REQ_ALBUM);
}
/**
* 打开照相机
*/
private void loadRealImgFromCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (mUri == null) {
mUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "cameraImghead.jpg"));
}
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
startActivityForResult(cameraIntent, REQ_CAMERA);
}
/**
* 相机回调和多图回调
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQ_CAMERA && resultCode == -1) {
jiantu(mUri);
} else if (requestCode == 3 && resultCode == -1) {
if (mUri != null&&listener!=null) {
listener.getImgUrl(mUri);
}
}else if (requestCode == REQ_ALBUM&&resultCode == -1){
if (listener!=null){
listener.getImgUrl(data.getStringArrayListExtra("urls"));
}
}
}
/**
* 拍照剪裁
*/
private void jiantu(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, 3);
}
public interface imgUrlListener{
void getImgUrl(Uri url); //返回一张图片的地址
void getImgUrl(ArrayList<String> urls); //返回一组图片的地址
}
imgUrlListener listener;
public void setListener(imgUrlListener listener) {
this.listener = listener;
}
@Override
protected void onDestroy() {
super.onDestroy();
mCameraDialog = null;
}
在MainActivity里面进行进行监听图片选择后的监听回调,并在GridView里面进行显示代码如下,要注意权限,Android6.0应该在代码了主动调用获取相机授权。
mGridView = (GridView)findViewById(R.id.grid_photo); mData = new ArrayList<>(); mAdapter = new GridPhotoAdapter(this,mData); mGridView.setAdapter(mAdapter); /** * 监听项目需求最多选择6张图,不到6张就显示加号,选到6张就隐藏掉加号 */ setListener(new imgUrlListener() { @Override public void getImgUrl(Uri url) { mData.add(url.toString()); mAdapter.notifyDataSetChanged(); } @Override public void getImgUrl(ArrayList<String> urls) { for (int i = 0; i < urls.size(); i++) { if (mData.size() < 6) { mData.add(urls.get(i)); } } mAdapter.notifyDataSetChanged(); } }); /** * 当点击的位置等于图片数组的长度时,可以知道此时图片数小于6张,并且点击的是加号,显示选择图片的dialog */ mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { if (i == mData.size()) { mCameraDialog.show(); } } }); }
因为需要显示加号而且需求是最多显示6张图片,所以要在adapter里面要进行逻辑上的操作
要注意调用相机返回的url地址和调用多图选择返回的url地址不一样,相机回调产生的地址前部分含有“file///”所以判断当含有这个字符串时要进行截取。然后显示。private Context mContext; private List<String> mData; public GridPhotoAdapter(Context context, List<String> data){ mContext = context; mData = data; } @Override public int getCount() { if (mData.size()<6){ return mData.size()+1; }else{ return mData.size(); } } @Override public Object getItem(int i) { return mData.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View view, ViewGroup viewGroup) { viewHolder holder; if (view == null){ view = LayoutInflater.from(mContext).inflate(R.layout.item_photo,null); holder = new viewHolder(); holder.simpleDraweeView = (ImageView) view.findViewById(R.id.image); holder.ivAdd = (ImageView) view.findViewById(R.id.iv_add); RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) ScreenUtils.getScreenWidth(mContext)/3-20,(int)ScreenUtils.getScreenWidth(mContext)/3-20); holder.simpleDraweeView.setLayoutParams(lp); view.setTag(holder); }else{ holder = (viewHolder) view.getTag(); } if (mData.size() <= 6){ if (i < mData.size()){ holder.ivAdd.setVisibility(View.GONE); if (mData.get(i).contains("file:///")){ ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(mData.get(i).substring(7), holder.simpleDraweeView); }else{ ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(mData.get(i), holder.simpleDraweeView); } }else{ holder.ivAdd.setVisibility(View.VISIBLE); ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage("", holder.simpleDraweeView); } } return view; } class viewHolder{ ImageView simpleDraweeView; ImageView ivAdd; } public void onDestory(){ mContext = null; mData = null; }
为了防止oom,在ImageLoder里面将图片的宽高根据比例压缩后,再度压缩2倍
源码已上传地址在http://download.csdn.net/detail/u013692888/9758445/** * 计算inSampleSize,用于压缩图片 * * @param options * @param reqWidth * @param reqHeight * @return */ private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源图片的宽度 int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (width > reqWidth && height > reqHeight) { // 计算出实际宽度和目标宽度的比率 int widthRatio = Math.round((float) width / (float) reqWidth); int heightRatio = Math.round((float) width / (float) reqWidth); inSampleSize = Math.max(widthRatio*2, heightRatio*2); } return inSampleSize; }