0%

Android7.0拍照以及使用uCrop裁剪

一、引入

  1. Android在7.0中修改了文件权限,所以从Android7.0开始要使用FileProvider来处理uri,从网上找了好多文章,解决了在7.0下拍照及相册选图的问题,但是参照网上的解决方案前切图片一直搞不定,最终使用了UCrop进行剪切图片并返回文件地址,便于与服务器交互。
  2. 本文主要介绍在Android7.0上进行拍照,相册选图以及相应的图片剪切,当然也会向下兼容,同时我也在Android4.3的手机上进行了测试,在文章最后我会附上源码,会有我自认为详细的注释哈哈。

二、拍照及相册

  1. FileProvider

    想必FileProvider大家都很熟悉了,但是想了一下感觉还是写一下比较好。

    1. 在manifest中配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <application

      ... ...

      <provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="com.sdwfqin.sample.fileprovider"
      android:exported="false"
      android:grantUriPermissions="true">
      <meta-data
      android:name="android.support.FILE_PROVIDER_PATHS"
      android:resource="@xml/file_paths_public"/>
      </provider>
      </application>
    2. 在 res 目录下新建文件夹 xml 然后创建资源文件 file_paths_public(名字随意,但是要和manifest中的名字匹配)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <?xml version="1.0" encoding="utf-8"?>
      <paths>
      <!--照片-->
      <external-path
      name="my_images"
      path="Pictures"/>
      <!--下载-->
      <paths>
      <external-path
      name="download"
      path=""/>
      </paths>
      </paths>
  2. 调用相机拍照

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // 全局变量
    public static final int RESULT_CODE_1 = 201;
    // 7.0 以上的uri
    private Uri mProviderUri;
    // 7.0 以下的uri
    private Uri mUri;
    // 图片路径
    private String mFilepath = SDCardUtils.getSDCardPath() + "AndroidSamples";
    -----------
    /**
    * 拍照
    */
    private void camera() {
    File file = new File(mFilepath, System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists()) {
    file.getParentFile().mkdirs();
    }
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Android7.0以上URI
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    //通过FileProvider创建一个content类型的Uri
    mProviderUri = FileProvider.getUriForFile(this, "com.sdwfqin.sample.fileprovider", file);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, mProviderUri);
    //添加这一句表示对目标应用临时授权该Uri所代表的文件
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    } else {
    mUri = Uri.fromFile(file);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
    }
    try {
    startActivityForResult(intent, RESULT_CODE_1);
    } catch (ActivityNotFoundException anf) {
    ToastUtils.showShort("摄像头未准备好!");
    }
    }
  3. 相册选图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 全局变量
    public static final int RESULT_CODE_2 = 202;
    ----------
    private void selectImg() {
    Intent pickIntent = new Intent(Intent.ACTION_PICK,
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
    startActivityForResult(pickIntent, RESULT_CODE_2);
    }
  4. onActivityResult

    需要注意的是拍照没有返回数据,用之前的uri就可以,从相册查找图片会返回uri

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    case RESULT_CODE_1:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    // 调用裁剪方法
    cropRawPhoto(mProviderUri);
    } else {
    cropRawPhoto(mUri);
    }
    break;
    case RESULT_CODE_2:
    Log.i(TAG, "onActivityResult: " + data.getData());
    cropRawPhoto(data.getData());
    break;

三、图片剪裁(重点)

  1. 因为用原生的一直是各种报错,所以我这里用的是UCrop,大家可能都见过官方的展示图,界面可能在有些需求下显得过于复杂,但是真正使用起来感觉有很多都是可以修改的哈哈哈!推荐大家看一下官方的例子。项目地址:https://github.com/Yalantis/uCrop

  2. 简单说一下引入方法但是并不能保证是最新的

    1. 依赖

      1
      compile 'com.github.yalantis:ucrop:2.2.1'
    2. 在AndroidManifest中添加Activity

      1
      2
      3
      4
      <activity
      android:name="com.yalantis.ucrop.UCropActivity"
      android:screenOrientation="portrait"
      android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
  3. 剪切图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public void cropRawPhoto(Uri uri) {

    // 修改配置参数(我这里只是列出了部分配置,并不是全部)
    UCrop.Options options = new UCrop.Options();
    // 修改标题栏颜色
    options.setToolbarColor(getResources().getColor(R.color.colorPrimary));
    // 修改状态栏颜色
    options.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
    // 隐藏底部工具
    options.setHideBottomControls(true);
    // 图片格式
    options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
    // 设置图片压缩质量
    options.setCompressionQuality(100);
    // 是否让用户调整范围(默认false),如果开启,可能会造成剪切的图片的长宽比不是设定的
    // 如果不开启,用户不能拖动选框,只能缩放图片
    options.setFreeStyleCropEnabled(true);

    // 设置源uri及目标uri
    UCrop.of(uri, Uri.fromFile(new File(mFilepath, System.currentTimeMillis() + ".jpg")))
    // 长宽比
    .withAspectRatio(1, 1)
    // 图片大小
    .withMaxResultSize(200, 200)
    // 配置参数
    .withOptions(options)
    .start(this);
    }
  4. 剪切完图片的回掉

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    if (resultCode == UCrop.RESULT_ERROR){
    mCameraTv.setText(UCrop.getError(data) + "");
    showMsg("图片剪裁失败");
    return;
    }
    if (resultCode == RESULT_OK) {
    switch (requestCode) {
    case UCrop.REQUEST_CROP:
    // 成功(返回的是文件地址)
    Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data));
    mCameraTv.setText(UCrop.getOutput(data) + "");
    // 使用Glide显示图片
    Glide.with(this)
    .load(UCrop.getOutput(data))
    .crossFade()
    .into(mCameraImg);
    break;
    }
    }
  5. 完整的onActivityResult,包含拍照的回掉

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == UCrop.RESULT_ERROR){
    mCameraTv.setText(UCrop.getError(data) + "");
    showMsg("图片剪裁失败");
    return;
    }
    if (resultCode == RESULT_OK) {
    switch (requestCode) {
    case RESULT_CODE_1:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    cropRawPhoto(mProviderUri);
    } else {
    cropRawPhoto(mUri);
    }
    break;
    case RESULT_CODE_2:
    Log.i(TAG, "onActivityResult: " + data.getData());
    cropRawPhoto(data.getData());
    break;
    case UCrop.REQUEST_CROP:
    Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data));
    mCameraTv.setText(UCrop.getOutput(data) + "");
    Glide.with(this)
    .load(UCrop.getOutput(data))
    .crossFade()
    .into(mCameraImg);
    break;
    }
    }
    }

四、源码

源码地址:https://github.com/sdwfqin/AndroidSamples