相信很多朋友在开发安卓App时都会有这样需求,图片选择或拍照选择,需求实现很简单,如下:
- 图片选择:调用系统图库进行选择
- 拍照选择:调用系统相机进行拍照
看了上面的实现后发现很容易啊,都有现成的调用;但我们错了,对于产品的BT需求,我们远远无法这么简单的满足,比如:图片多选上传了?额,这个时候我们调用系统的图库就蒙B了,因为系统图库并不支持多选;那怎么办了?不急,请慢慢往下看,这就是这篇Blog的意义所在,定义一个自己的图片选择器
本项目已经开发完毕了,下面是相应的地址
GitHub:https://github.com/JaySong/PhotoPicker
Gradle引用:’com.jay.ui:photopicker:last-version’;目前版本:1.0.0
此工程实现的功能:
- 图片的单选或多选<可自定最大选择数量>
- 可根据不同图片文件夹进行筛选
- 图片的预览
- 相机拍照选择
总结:微信选择图片的功能基本都有,可满足大部分需求,UI界面采用MD风格设计
需要解决的技术问题
- 得到手机中所有的图片并显示在列表
- 实现列表的单选或多选
1.得到手机中所有的图片并显示在列表
实现:采用LoaderManager.LoaderCallbacks时行图片的查询,下面见核心代码
PS:当前需要实现加载的类可实现此接口或自己自定义一个类实现此接口
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { @SuppressWarnings("UnnecessaryLocalVariable") CursorLoader cursorLoader = new CursorLoader( this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME}, "mime_type=? or mime_type=?" + (isShowGif ? "or mime_type=?" : ""), isShowGif ? new String[]{"image/jpeg", "image/png", "image/gif"} : new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_ADDED + " DESC" ); return cursorLoader; }
getLoaderManager().initLoader(int,Bundle, LoaderManager.LoaderCallbacks);
通过此方法进行初始化,如果要兼容到11以下的系统,调用
getSupportLoaderManager()..initLoader(int,Bundle, LoaderManager.LoaderCallbacks);onCreateLoader()方法是接口中必须实现的方法;
new CursorLoader(Context context, Uri uri, //查询的Uri String[] projection, //列名 String selection,//查询条件 String[] selectionArgs, //查询条件中的参数 String sortOrder)//排序规则
onLoadFinished(Loader loader, Cursor data)方法会在查询完成后回调,其中data就是我们想要的结果就在此对象中
if (data.moveToFirst()) { do { String photoDir = data.getString(data.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME)); String photoUri = data.getString(data.getColumnIndex(MediaStore.Images.Media.DATA)); } while (data.moveToNext()); } //photoDir:当前图片所在的目录名 //photoUri:当前图片的路径
2.实现列表的单选或多选
列表的显示是使用控件RecyclerView实现展示,图片选中控件是使用CheckBox来进行图片的选择标识,具体请查看源码PhotoPickerActivity.PhotoListAdapter适配器类
拍照并显示至列表
实现方式:同样调用系统相机
//用户要拍照 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePhotoFile = createImageFile(); // Continue only if the File was successfully created if (takePhotoFile != null) { takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(takePhotoFile)); startActivityForResult(takePictureIntent, TAKE_PHOTO); } else { showSnackBar(getString(R.string.open_camera_fail)); } //其中createImageFile()返回一个文件File,即拍照后保存的路径
拍照成功需要更新列表,这个时候我们做一个操作即可,那就是提醒系统更新媒体库
public void notifyMediaUpdate(File file) { Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri contentUri = Uri.fromFile(file); mediaScanIntent.setData(contentUri); sendBroadcast(mediaScanIntent); } //这样操作后,我们前面实现的加载器会自动去加载新的数据,参数file就是我们之前拍照前保存的保存路径
下面上一张演示图