android10调用相机和相册,裁剪图片,anroid11 图片操作工具类

 

这个工具类我弃坑了,弃坑原因有两个

1、startActivityForResult即将方法过期

2、选择图片和调用相机,官方新api:registerForActivityResult()都有相应简单的方法,而裁剪图片需要跨app文件操作,android11之后app间文件操作需要先把文件复制到共享目录下,文件操作过于频繁且不友好,建议使用第三方裁剪库

从android10开始,我们无法直接使用外部文件,因此所有外部文件都需要使用匿名uri进行操作

获取到uri之后,如果想转换成file,可以参考:https://blog.csdn.net/jingzz1/article/details/106188462

兼容android4.0-android11

使用前,PhotoUtils.authorities 一定要改成你自己的authorities (什么是authorities)

kotlin使用方法:

       
由于是调用系统功能,因此不需权限

        //调用相机拍照
       PhotoUtils.camera(activity){
           uri, success, msg ->
            //uri返回的图片 success是否成功 msg错误信息
           if(success)
               Glide.with(this).load(uri).into(binding.ivImage)
       } 

        //调用相册
        PhotoUtils.select(activity){
            uri, success, msg ->
            if(success)
                Glide.with(this).load(uri).into(binding.ivImage)
        }

        //裁剪图片
        PhotoUtils.crop(fragment).apply { 
            setAspect(1,1)//设置裁剪比例
            setOutput(300,300)//设置输出大小
        }.build(uri){cropUri, success, msg ->  
            if(success)
            Glide.with(this).load(cropUri).into(binding.ivImage)
        }

java使用方法:

        //从相册中选择
        PhotoUtils.select(activity, new Function3<Uri, Boolean, String, Unit>() {
            @Override
            public Unit invoke(Uri uri, Boolean success, String msg) {
                return null;
            }
        });

        //调用系统相机
        PhotoUtils.camera(activity,new Function3<Uri, Boolean, String, Unit>() {
            @Override
            public Unit invoke(Uri uri, Boolean success, String msg) {
                return null;
            }
        });

        //裁剪图片
        PhotoUtils.crop(activity)
                .build(uri,new Function3<Uri, Boolean, String, Unit>() {
                    @Override
                    public Unit invoke(Uri uri, Boolean success, String msg) {
                        return null;
                    }
                });

PhotoUtils源码:

import android.app.Activity
import android.content.ContentResolver
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.provider.OpenableColumns
import androidx.annotation.IntRange
import androidx.core.content.FileProvider
import androidx.core.net.toFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import com.blankj.utilcode.util.LogUtils
import com.jingzz.picturepicker.PicturePicker
import java.io.File
import java.lang.RuntimeException
import kotlin.random.Random

/**
 * Created by jingzz on 2020/5/11.
 */
class PhotoUtils {

    companion object{

        private val authorities = 换成你自己的authorities 
        /**
         * 调用裁剪功能
         */
        @JvmStatic
        fun crop(manager:FragmentManager):Crop = Crop(manager)
        /**
         * 调用裁剪功能
         */
        @JvmStatic
        fun crop(activity: FragmentActivity):Crop = Crop(activity.supportFragmentManager)
        /**
         * 调用裁剪功能
         */
        @JvmStatic
        fun crop(fragment: Fragment):Crop = Crop(fragment.childFragmentManager)


        class Crop(private val manager:FragmentManager){

        private var aspectX = 0
        private var aspectY = 0
        private var outputX = 0
        private var outputY = 0

        /**
         * 设置比例
         */
        fun setAspect(@IntRange(from = 0) aspectX:Int,@IntRange(from = 0) aspectY:Int):Crop{
            this.aspectX = aspectX
            this.aspectY = aspectY
            return this
        }

        /**
         * 设置输出图片的宽高
         */
        fun setOutput(@IntRange(from = 0) width:Int,@IntRange(from = 0) height:Int):Crop{
            this.outputX = width
            this.outputY = height
            return this
        }
        fun build(uri:Uri,cropCallBack:(cropUri:Uri?,success: Boolean,msg:String) -> Unit){
            crop(manager,uri,aspectX,aspectY,outputX,outputY,cropCallBack)
        }
    }

        /**
         * 打开相册
         */
        @JvmStatic
        fun select(manager:FragmentManager,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit)=getPhotoFragment(manager).select(photoCallBack) /**
         * 打开相册
         */
        @JvmStatic
        fun select(activity:FragmentActivity,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit)=getPhotoFragment(activity.supportFragmentManager).select(photoCallBack) /**
         * 打开相册
         */
        @JvmStatic
        fun select(fragment: Fragment,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit)=getPhotoFragment(fragment.childFragmentManager).select(photoCallBack)

        /**
         * 调用相机拍照
         */
        @JvmStatic
        fun camera(manager:FragmentManager,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit) = getPhotoFragment(manager).camera(photoCallBack) /**
         * 调用相机拍照
         */
        @JvmStatic
        fun camera(activity:FragmentActivity,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit) = getPhotoFragment(activity.supportFragmentManager).camera(photoCallBack) /**
         * 调用相机拍照
         */
        @JvmStatic
        fun camera(fragment: Fragment,photoCallBack:(uri:Uri?,success: Boolean,msg:String) -> Unit) = getPhotoFragment(fragment.childFragmentManager).camera(photoCallBack)

        private fun crop(manager:FragmentManager,uri: Uri,aspectX:Int, aspectY:Int, outputX:Int,outputY:Int,cropCallBack:(Uri?, Boolean, String) -> Unit)
         = getPhotoFragment(manager).crop(uri,aspectX,aspectY,outputX,outputY,cropCallBack)



    }

    class PhotoFragment:Fragment(){
        private val REQUEST_CODE_CROP = 601
        private val REQUEST_CODE_CAMERA = 602
        private val REQUEST_CODE_SELECT = 603
        private var cropCallback: ((Uri?, Boolean, String) -> Unit)? = null
        private var selectCallback: ((Uri?, Boolean, String) -> Unit)? = null
        private var cameraCallback: ((Uri?, Boolean, String) -> Unit)? = null

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setRetainInstance(true)
        }


        lateinit var cameraPath:String
        //调用相机
        fun camera(photoCallBack:(Uri?, Boolean, String) -> Unit) {
            if(authorities.isNullOrBlank())
                throw RuntimeException("authority不能为空")

            this.cameraCallback = photoCallBack
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
            val file = File(requireContext().externalCacheDir!!.absolutePath,
                "${System.currentTimeMillis()}${Random.nextInt(9999)}.jpg"
            )
            cameraPath = file.absolutePath
            val uri = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
                FileProvider.getUriForFile(requireContext(),authorities,file)
            }else{
                Uri.fromFile(file)
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
            startActivityForResult(intent, REQUEST_CODE_CAMERA)
        }

        //选择图片
        fun select(photoCallBack:(Uri?, Boolean, String) -> Unit) {
            this.selectCallback = photoCallBack
            val intent = Intent()
            intent.action = Intent.ACTION_PICK
            intent.type = "image/*"
            startActivityForResult(
                intent, REQUEST_CODE_SELECT)
        }

        var outUri:Uri? = null
        //裁剪
        fun crop(uri: Uri,aspectX:Int, aspectY:Int, outputX:Int,outputY:Int,callBack:(Uri?, Boolean, String) -> Unit){
            if(authorities.isBlank())
                throw RuntimeException("请填写正确的authority")
            val uri1 = if(uri.scheme.equals(ContentResolver.SCHEME_FILE))
                FileProvider.getUriForFile(requireContext(),authorities,uri.toFile())
            else uri

            val cursor = requireContext().contentResolver.query(uri1, null, null, null, null, null)
            cursor?.let {
                it.moveToFirst()

                this.cropCallback = callBack
                val intent = Intent("com.android.camera.action.CROP")
                //文件名
                val displayName = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                outUri = Uri.fromFile(File(requireContext().externalCacheDir!!.absolutePath, "crop${Random.nextInt(0,9999)}$displayName"))
                requireContext().grantUriPermission(
                    requireContext().getPackageName(),
                    outUri,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION
                )
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                intent.putExtra("noFaceDetection", true) //去除默认的人脸识别,否则和剪裁匡重叠
                intent.setDataAndType(uri1, requireContext().contentResolver.getType(uri))
                intent.putExtra("crop", "true") // crop=true 有这句才能出来最后的裁剪页面.
                intent.putExtra("output", outUri)
                intent.putExtra("outputFormat", "JPEG") // 返回格式
                var ax = aspectX
                var ay = aspectY
                if (ay != 0 && ay != 0) {
                    if (ax == ay && Build.MANUFACTURER == "HUAWEI") {
                        ax = 9998
                        ay = 9999
                    }
                    intent.putExtra("aspectX", ax) // 这两项为裁剪框的比例.
                    intent.putExtra("aspectY", ay) // x:y=1:2
                }
                if (outputX != 0 && outputY != 0) {
                    intent.putExtra("outputX", outputX)
                    intent.putExtra("outputY", outputY)
                }
                intent.putExtra("return-data", false)
                startActivityForResult(
                    intent,REQUEST_CODE_CROP
                )
            }
            cursor?.close()
        }

        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
            if(resultCode == Activity.RESULT_OK){
                when(requestCode){
                    REQUEST_CODE_CROP->{
                        //裁剪
                        //把outUri转成
                        val uri = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
                            //把uri转成匿名uri
                            if(outUri?.scheme.equals(ContentResolver.SCHEME_FILE))
                                FileProvider.getUriForFile(requireContext(),authorities,outUri!!.toFile())
                            else outUri
                        }else outUri
                        cropCallback?.invoke(uri,true,"")
                        cropCallback = null
                    }
                    REQUEST_CODE_CAMERA ->{
                        val uri = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
                            FileProvider.getUriForFile(requireContext(),
                                authorities,File(cameraPath))
                        }else{
                            Uri.fromFile(File(cameraPath))
                        }
                        cameraCallback?.invoke(uri,true,"")
                        cameraCallback = null
                    }
                    REQUEST_CODE_SELECT->{
                        val uri = data?.data
                        selectCallback?.invoke(uri,true,"")
                        selectCallback = null
                    }
                }
            }else{
                when(requestCode){
                    REQUEST_CODE_CROP->{
                        //裁剪
                        cropCallback?.invoke(null,false,"裁剪失败")
                        cropCallback = null
                    }
                    REQUEST_CODE_CAMERA ->{

                        cameraCallback?.invoke(null,false,"拍照失败")
                        cameraCallback = null
                    }
                    REQUEST_CODE_SELECT->{
                        selectCallback?.invoke(null,false,"选择图片失败")
                        selectCallback = null
                    }
                }
            }
        }


    }
}

private fun getPhotoFragment(manager: FragmentManager) =
    manager.findFragmentByTag("photoFragmen") as? PhotoUtils.PhotoFragment?:
    PhotoUtils.PhotoFragment().apply {
        manager.beginTransaction()
            .add(this,"photoFragmen")
            .commitAllowingStateLoss()
        manager.executePendingTransactions()
    }

猜你喜欢

转载自blog.csdn.net/jingzz1/article/details/106052591