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()
    }

 

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 26
    评论
Android中,要调用系统相机相册裁剪图片,需要使用一些系统提供的Intent和API。下面是一个示例的源码,实现了这个功能。 首先,在AndroidManifest.xml文件中添加如下权限: ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 然后,在你的Activity中添加如下代码: ```java private static final int REQUEST_IMAGE_CAPTURE = 1; // 调用相机的请求码 private static final int REQUEST_IMAGE_PICK = 2; // 调用相册的请求码 private static final int REQUEST_IMAGE_CROP = 3; // 调用裁剪的请求码 private Uri imageUri; // 保存相机拍照或相册选择的照片Uri // 调用系统相机拍照 private void takePicture() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (intent.resolveActivity(getPackageManager()) != null) { // 创建临时文件保存拍照的图片 File imageFile = createImageFile(); if (imageFile != null) { imageUri = FileProvider.getUriForFile(this, "com.example.fileprovider", imageFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, REQUEST_IMAGE_CAPTURE); } } } // 调用系统相册选择照片 private void pickPicture() { Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "选择图片"), REQUEST_IMAGE_PICK); } // 创建临时文件保存拍照的图片 private File createImageFile() { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "IMG_" + timeStamp; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try { File imageFile = File.createTempFile(imageFileName, ".jpg", storageDir); return imageFile; } catch (IOException e) { e.printStackTrace(); } return null; } // 调用系统裁剪图片 private void cropPicture(Uri sourceUri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(sourceUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 500); intent.putExtra("outputY", 500); intent.putExtra("return-data", true); startActivityForResult(intent, REQUEST_IMAGE_CROP); } // 处理相机相册返回的结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_IMAGE_CAPTURE: cropPicture(imageUri); // 拍照后裁剪图片 break; case REQUEST_IMAGE_PICK: cropPicture(data.getData()); // 选择照片后裁剪图片 break; case REQUEST_IMAGE_CROP: Bundle extras = data.getExtras(); if (extras != null) { Bitmap bitmap = extras.getParcelable("data"); // 在这里处理裁剪后的图片 } break; } } } ``` 以上就是调用系统相机相册裁剪图片的简单示例代码。你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值