关于使用图片选择器的库的选择

2017-06-02  本文已影响1917人  zgfei
前言:

这几日一直在做图片选择器的功能,关于要求是仿微信的样式,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

  <provider             
      android:name="com.example.zgfei.photopickertest.zhihu.MyFileProvider"
      android:authorities="com.example.zgfei.photopickertest.provider"
      android:exported="false"
      android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths_public"/>
    </provider>

这里提供了一个 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 不使用拍照功能,什么问题都没有,使用,上面全是坑。毕竟人家是拿来完成人家自己的功能,我们如果要用可以学习一下。

写在最后

不知道问什么当写到一定长度的时候,浏览器会莫名崩溃,重新进入,依旧是崩溃,因此写不了。

上一篇下一篇

猜你喜欢

热点阅读