前言:
这几日一直在做图片选择器的功能,关于要求是仿微信的样式,takePhoto 直接被 pass。经过几天的查阅资料和筛选,基本确定了一下相关的几个库来使用。接下来就具体解析一下这几库的相关优缺点,当然也有少不了的坑。
因为后面写不了,所以就直接写在了介绍里面,不知道为什么编辑帖子的时候,浏览器会莫名崩溃,奈何只能简单的介绍了。
在图片选择器的选择上,如果有时间可以研究一下源码如何写的,时间充足的话可以自己写一个符合自己项目需要的库。
相关库介绍
Matisse
这是知乎开源的一个框架,查看知乎,也在使用。
PhotoPicker
这也是一个比较好用库,作者是 donglua
写在这:这个库没有实现的功能有多选浏览,浏览时选择等,有一点就是默认的布局有点不好看。因此当时我是直接使用的源码进行的修改,这样可能又会遇到 Matisse 那样的问题,不过按照步骤一般都能解决,这里就不做过多介绍了。
这里再说一下刷新本地图片保存的文件的方法,这个方法是在 PhotoPicker 的源码中找到的:
// 重点是获取图片保存的路径
private void scan(Uri uri) {
if (!uri.toString().contains("ContentProvider 提供的:authorities")) {
return;
}
String path = uri.getPath();
String[] split = path.split("/");
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);// 文件路径是默认的,要与 ContentProvider 设置的 resource 一致(public/private)
String a = file.getAbsolutePath() + File.separatorChar + split[split.length - 1];// 截取图片的名称全称(包含路径)
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);// 扫描的意图
if (TextUtils.isEmpty(file.getAbsolutePath())) {
return;
}
File f = new File(a);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
mActivity.sendBroadcast(mediaScanIntent);// 发送广播
}
ImageSelector
这个是高仿微信的一个开源库,这个目前正在维护中,谨慎使用。
维护的地址是:https://github.com/YancyYe/GalleryPick
相对来说这个库还是挺不错的,虽然有一些 bug,并且在维护,但是对这个库还是很期待的
注意:
Maitsse 返回的数据是以 Uri 的形式进行返回,因此需要自行处理。
PhotoPicker 返回的是相对路径,可以直接获取。
对比优缺点
Matisse
Matisse 是知乎开源的库,当然兼容性和稳定性还是挺可靠的,这个库的基本使用方法在项目的首页已经介绍的很详细了,这里不再重复,我们只写一些他们没有的。
在使用这个库的时候我搜索了很多的资料,基本都是照抄官网的,没有一点创新,还好有一位叫七零八落蛋的作者提供了一些有用的知识(感谢感谢)。
相关支持:查看官方文档
优点:功能强大,界面美观,稳定性高
缺点:多选和单选都是跳入同一个图片选择器页面,拍照功能没有独立出来,相关的设置属性没有开放,返回的结果以 Uri 的方式返回……
如果只是使用一些简单的功能,可以参考官方提供的 demo 即可,这里讲一下添加拍照功能。
拍照
在拍照的时候我们需要设置 capture(true) 和 captureStrategy() 方法,这样才会显示出拍照。但是这里需要提供一些配置。
1、提供一个 ContentProvider 供拍照使用,不然会崩。
这里是我添加的 ContentProvider
这里提供了一个 MyFileProvider 用来兼容 android 7.0,不然会崩。这个 MyFileProvider 只是继承自 FileProvider 即可。
android:authorities="com.example.zgfei.photopickertest.provider" 很重要,这里的 authorities 对应的值要和设置 captureStrategy() 的参数一直,不然会崩。
看一下我设置的 captureStrategy() 方法:
Matisse.from(MatisseTestActivity.this).choose(MimeType.allOf())
.countable(false)
.capture(true)
.captureStrategy(new CaptureStrategy(true, "com.example.zgfei.photopickertest.provider"))
.maxSelectable(9)//最大选择数
.theme(R.style.Matisse_Zhihu)//主题
.spanCount(4)//行数
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
.thumbnailScale(0.85f)
.imageEngine(new PicassoEngine())//选择图片加载器
.forResult(REQUEST_CODE_CHOOSE);//设置回调
这里 android:resource="@xml/file_paths_public" 提供了一个文件的路径,即拍照完成后的路径,路径一定要配置对,不然会崩。
这个地方提供一些相关的资料供学习使用:
FileProvider共享文件、缓存
FileProvider无法获取外置SD卡问题解决方案 | Failed to find configured root that contains
关于AndroidManifest.xml 添加多个 provider节点问题
在配置 ContentProvider 的时候会遇到各种各样的问题,这些和上面的相关介绍均可解决问题。
这样就可以成功拍照了,也可以获取相关的 Uri,那么这个时候另一个问题就会来。
问题描述:在我们拍完照后,页面会返回我们之前的页面,不会跳到图片选择的页面,这个也就算了,当我们再次进入图片选择页面的时候,刚才拍的照片竟然没有显示出来。崩溃,如果你可以说服你的产品这样做是合理的,那没什么可说的(碰见这样的产品就娶了吧,别管
TA 是男的还是女的)。
解决问题:找到保存图片的位置,刷新一下图片的文件,再次进入就可以显示出来了(好神奇,但是有毛用,你不可能告诉用户这样做吧)。
但是问题出来了,还是要解决的,那么我们就自己刷新吧。网上有相关的刷新相册的相关资料,自己可以 Google。当你看到它返回来的 Uri
的格式,你就知道我为什么不用网上的资料了。这里说一下我的解决方案。
刷新拍照图片保存的文件
查看源码发现图片保存的路径是:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
getExternalFilesDir(Environment.DIRECTORY_PICTURES);
源码:
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir;
if (mCaptureStrategy.isPublic) {
storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
} else {
storageDir = mContext.get().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
}
return new File(storageDir + imageFileName + ".jpg");
}
这里根据你在 file_paths_public.xml 中使用的文件路径可以知道你的 mCaptureStrategy.isPublic 还是 else,获取到路径后刷新就简单了,刷新的方法会在 PhotoPicker 的地方讲。
使用 Matisse 不使用拍照功能,什么问题都没有,使用,上面全是坑。毕竟人家是拿来完成人家自己的功能,我们如果要用可以学习一下。
写在最后
不知道问什么当写到一定长度的时候,浏览器会莫名崩溃,重新进入,依旧是崩溃,因此写不了。