一、引入

  1. Android在7.0中修改了文件权限,所以从Android7.0开始要使用FileProvider来处理uri,从网上找了好多文章,解决了在7.0下拍照及相册选图的问题,但是参照网上的解决方案前切图片一直搞不定,最终使用了UCrop进行剪切图片并返回文件地址,便于与服务器交互。

  2. 本文主要介绍在Android7.0上进行拍照,相册选图以及相应的图片剪切,当然也会向下兼容,同时我也在Android4.3的手机上进行了测试,在文章最后我会附上源码,会有我自认为详细的注释哈哈。

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

二、拍照及相册

  1. FileProvider

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

  1. 在manifest中配置
  1. <application
  2. ... ...
  3. <provider
  4. android:name="android.support.v4.content.FileProvider"
  5. android:authorities="com.sdwfqin.sample.fileprovider"
  6. android:exported="false"
  7. android:grantUriPermissions="true">
  8. <meta-data
  9. android:name="android.support.FILE_PROVIDER_PATHS"
  10. android:resource="@xml/file_paths_public"/>
  11. </provider>
  12. </application>
  1. 在 res 目录下新建文件夹 xml 然后创建资源文件 file_paths_public(名字随意,但是要和manifest中的名字匹配)
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <paths>
  3. <!--照片-->
  4. <external-path
  5. name="my_images"
  6. path="Pictures"/>
  7. <!--下载-->
  8. <paths>
  9. <external-path
  10. name="download"
  11. path=""/>
  12. </paths>
  13. </paths>
  1. 调用相机拍照
  1. // 全局变量
  2. public static final int RESULT_CODE_1 = 201;
  3. // 7.0 以上的uri
  4. private Uri mProviderUri;
  5. // 7.0 以下的uri
  6. private Uri mUri;
  7. // 图片路径
  8. private String mFilepath = SDCardUtils.getSDCardPath() + "AndroidSamples";
  9. -----------
  10. /**
  11. * 拍照
  12. */
  13. private void camera() {
  14. File file = new File(mFilepath, System.currentTimeMillis() + ".jpg");
  15. if (!file.getParentFile().exists()) {
  16. file.getParentFile().mkdirs();
  17. }
  18. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  19. // Android7.0以上URI
  20. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  21. //通过FileProvider创建一个content类型的Uri
  22. mProviderUri = FileProvider.getUriForFile(this, "com.sdwfqin.sample.fileprovider", file);
  23. intent.putExtra(MediaStore.EXTRA_OUTPUT, mProviderUri);
  24. //添加这一句表示对目标应用临时授权该Uri所代表的文件
  25. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  26. } else {
  27. mUri = Uri.fromFile(file);
  28. intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
  29. }
  30. try {
  31. startActivityForResult(intent, RESULT_CODE_1);
  32. } catch (ActivityNotFoundException anf) {
  33. ToastUtils.showShort("摄像头未准备好!");
  34. }
  35. }
  1. 相册选图
  1. // 全局变量
  2. public static final int RESULT_CODE_2 = 202;
  3. ----------
  4. private void selectImg() {
  5. Intent pickIntent = new Intent(Intent.ACTION_PICK,
  6. MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
  7. pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
  8. startActivityForResult(pickIntent, RESULT_CODE_2);
  9. }
  1. onActivityResult

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

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

三、图片剪裁(重点)

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

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

  1. 依赖
  1. compile 'com.github.yalantis:ucrop:2.2.1'
  1. 在AndroidManifest中添加Activity
  1. <activity
  2. android:name="com.yalantis.ucrop.UCropActivity"
  3. android:screenOrientation="portrait"
  4. android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
  1. 剪切图片
  1. public void cropRawPhoto(Uri uri) {
  2. // 修改配置参数(我这里只是列出了部分配置,并不是全部)
  3. UCrop.Options options = new UCrop.Options();
  4. // 修改标题栏颜色
  5. options.setToolbarColor(getResources().getColor(R.color.colorPrimary));
  6. // 修改状态栏颜色
  7. options.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
  8. // 隐藏底部工具
  9. options.setHideBottomControls(true);
  10. // 图片格式
  11. options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
  12. // 设置图片压缩质量
  13. options.setCompressionQuality(100);
  14. // 是否让用户调整范围(默认false),如果开启,可能会造成剪切的图片的长宽比不是设定的
  15. // 如果不开启,用户不能拖动选框,只能缩放图片
  16. options.setFreeStyleCropEnabled(true);
  17. // 设置源uri及目标uri
  18. UCrop.of(uri, Uri.fromFile(new File(mFilepath, System.currentTimeMillis() + ".jpg")))
  19. // 长宽比
  20. .withAspectRatio(1, 1)
  21. // 图片大小
  22. .withMaxResultSize(200, 200)
  23. // 配置参数
  24. .withOptions(options)
  25. .start(this);
  26. }
  1. 剪切完图片的回掉
  1. if (resultCode == UCrop.RESULT_ERROR){
  2. mCameraTv.setText(UCrop.getError(data) + "");
  3. showMsg("图片剪裁失败");
  4. return;
  5. }
  6. if (resultCode == RESULT_OK) {
  7. switch (requestCode) {
  8. case UCrop.REQUEST_CROP:
  9. // 成功(返回的是文件地址)
  10. Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data));
  11. mCameraTv.setText(UCrop.getOutput(data) + "");
  12. // 使用Glide显示图片
  13. Glide.with(this)
  14. .load(UCrop.getOutput(data))
  15. .crossFade()
  16. .into(mCameraImg);
  17. break;
  18. }
  19. }
  1. 完整的onActivityResult,包含拍照的回掉
  1. @Override
  2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  3. super.onActivityResult(requestCode, resultCode, data);
  4. if (resultCode == UCrop.RESULT_ERROR){
  5. mCameraTv.setText(UCrop.getError(data) + "");
  6. showMsg("图片剪裁失败");
  7. return;
  8. }
  9. if (resultCode == RESULT_OK) {
  10. switch (requestCode) {
  11. case RESULT_CODE_1:
  12. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  13. cropRawPhoto(mProviderUri);
  14. } else {
  15. cropRawPhoto(mUri);
  16. }
  17. break;
  18. case RESULT_CODE_2:
  19. Log.i(TAG, "onActivityResult: " + data.getData());
  20. cropRawPhoto(data.getData());
  21. break;
  22. case UCrop.REQUEST_CROP:
  23. Log.i(TAG, "onActivityResult: " + UCrop.getOutput(data));
  24. mCameraTv.setText(UCrop.getOutput(data) + "");
  25. Glide.with(this)
  26. .load(UCrop.getOutput(data))
  27. .crossFade()
  28. .into(mCameraImg);
  29. break;
  30. }
  31. }
  32. }

四、源码

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