Android使用系统裁剪功能,保存裁剪图片,适配Android11

3,292 阅读2分钟

本期接到一个裁剪上传图片功能,本以为很简单,几个小时就搞定了,结果搞了两天才基本完成,时间都花费在了Android版本适配上面,话不多说,直接展示坑的位置。

1.获取相机拍照图片(适配7.0 fileProvider)

private fun openCamera() {
    TAKEPAHTO = 1
    // 启动系统相机
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    val mImageCaptureUri: Uri
    // 判断7.0android系统
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        //临时添加一个拍照权限
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        //通过FileProvider获取uri
        takePhotoSaveAdr = FileProvider.getUriForFile(this@MainActivity,
                "com.zy.androidcrop", File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "head.jpg"))
        intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoSaveAdr)
    } else {
        mImageCaptureUri = Uri.fromFile(File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "head.jpg"))
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri)
    }
    startActivityForResult(intent, PHOTO_TAKEPHOTO)
}

2.裁剪图库或相机图片并保存到手机(适配Android11分区存储)

val intent = Intent("com.android.camera.action.CROP")//com.android.camera.action.CROP,这个action是调用系统自带的图片裁切功能
intent.setDataAndType(uri, "image/*") //裁剪的图片uri和图片类型
intent.putExtra("crop", "true") //设置允许裁剪,如果不设置,就会跳过裁剪的过程,还可以设置putExtra("crop", "circle")
//设置aspectX 与 aspectY 后,裁剪框会按照所指定的比例出现,放大缩小都不会更改。如果不指定,那么 裁剪框就可以随意调整了。
intent.putExtra("aspectX", 1) //裁剪框的 X 方向的比例,需要为整数
intent.putExtra("aspectY", 1) //裁剪框的 Y 方向的比例,需要为整数
intent.putExtra("outputX", 500) //返回数据的时候的X像素大小。
intent.putExtra("outputY", 500) //返回数据的时候的Y像素大小。
//uriClipUri为Uri类变量,实例化uriClipUri
//android11 分区存储
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
    imageCropFile = CropFileUtils.createImageFile(this, true)
    //设置裁剪的图片地址Uri
    uriClipUri = CropFileUtils.uri
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    if (TAKEPAHTO == 1) { //如果是7.0的拍照
        //开启临时访问的读和写权限
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
        //针对7.0以上的操作
        intent.clipData = ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri)
        uriClipUri = uri
    } else { //如果是7.0的相册
        //设置裁剪的图片地址Uri
        uriClipUri = Uri.parse("file://" + "/" + getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path + "/" + "head.jpg")
    }
} else {
    uriClipUri = Uri.parse("file://" + "/" + getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path + "/" + "head.jpg")
}
Log.e("uriClipUri=====", "" + uriClipUri)
//向intent传入 MediaStore.EXTRA_OUTPUT参数后,表明这是一个存储动作
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriClipUri)
intent.putExtra("return-data", false) //是否将数据保留在Bitmap中返回
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()) //输出格式,一般设为Bitmap格式及图片类型
intent.putExtra("noFaceDetection", true) //是否去除面部检测
startActivityForResult(intent, PHOTO_PHOTOCLIP) //裁剪完成的标识
  • 针对android11分区存储,保存文件时可以通过MediaStore相关api进行文件保存。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    imgFile = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES) + File.separator + fileName);
    // 通过 MediaStore API 插入file 为了拿到系统裁剪要保存到的uri(因为App没有权限不能访问公共存储空间,需要通过 MediaStore API来操作)
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());
    values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}else {
    imgFile = new File(rootFile.getAbsolutePath() + File.separator + fileName);
}
  • 针对华为手机裁剪框为圆形的问题,如果产品非要求展示成矩形(圆形或方形裁剪框实际效果都一样,结果都是产生方形图片),可以通过以下设置实现。
intent.putExtra("aspectX", 9999999999) //裁剪框的 X 方向的比例,需要为整数
intent.putExtra("aspectY", 9999999998) //裁剪框的 Y 方向的比例,需要为整数

只要保证aspectX和aspectY不是1:1即展示成方形,数值任意。

附上demo地址: github.com/JackFung201…