如何在Jetpack Compose中实现相机/相册选图并直接裁剪功能
Android 图片选择+裁剪实现方案(Kotlin+XML)
一、原生实现(无第三方依赖,稳定可靠)
1. 弹出相机/相册选择菜单
在按钮点击事件中弹出选项对话框:
btnSelectImage.setOnClickListener { val options = arrayOf("拍照", "从相册选择") AlertDialog.Builder(this) .setTitle("选择图片来源") .setItems(options) { _, which -> when (which) { 0 -> openCamera() 1 -> openGallery() } } .show() }
2. 调用相机拍照
需提前申请相机、存储权限,通过FileProvider处理文件Uri避免权限问题:
private lateinit var photoUri: Uri private val REQUEST_CAMERA = 1001 private fun openCamera() { // 权限检查 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CAMERA) return } // 创建临时文件存储拍照结果 val photoFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "temp_photo.jpg") photoUri = FileProvider.getUriForFile(this, "${packageName}.fileprovider", photoFile) // 启动相机Intent val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { putExtra(MediaStore.EXTRA_OUTPUT, photoUri) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) } startActivityForResult(intent, REQUEST_CAMERA) }
在AndroidManifest.xml注册FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
在res/xml目录创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="photos" path="Pictures" /> </paths>
3. 调用相册选择图片
private val REQUEST_GALLERY = 1002 private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI).apply { type = "image/*" } startActivityForResult(intent, REQUEST_GALLERY) }
4. 图片裁剪
调用系统裁剪功能,支持比例锁定和尺寸设置:
private val REQUEST_CROP = 1003 private fun cropImage(uri: Uri) { val cropIntent = Intent("com.android.camera.action.CROP").apply { setDataAndType(uri, "image/*") putExtra("crop", "true") // 设置1:1裁剪比例 putExtra("aspectX", 1) putExtra("aspectY", 1) // 设置输出图片尺寸 putExtra("outputX", 300) putExtra("outputY", 300) putExtra("return-data", true) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivityForResult(cropIntent, REQUEST_CROP) }
5. 处理返回结果
用registerForActivityResult替代过时的onActivityResult:
// 相册选择结果 private val galleryResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { result.data?.data?.let { cropImage(it) } } } // 相机拍照结果 private val cameraResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { cropImage(photoUri) } } // 裁剪结果 private val cropResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val bitmap = result.data?.extras?.getParcelable<Bitmap>("data") // 将裁剪后的图片显示到ImageView imageView.setImageBitmap(bitmap) } } // 注意:openCamera和openGallery中需改用launch启动Intent // 例如openGallery()中替换为:galleryResult.launch(intent)
二、推荐第三方库(文档完善+兼容性好)
UCrop
目前最主流的图片裁剪库,支持自定义裁剪比例、圆形裁剪、样式定制,Kotlin兼容良好:
- 添加依赖:
implementation 'com.github.yalantis:ucrop:2.2.8'
- 调用裁剪:
val destinationUri = Uri.fromFile(File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "cropped_photo.jpg")) UCrop.of(sourceUri, destinationUri) .withAspectRatio(1f, 1f) .withMaxResultSize(500, 500) .start(this)
- 处理裁剪结果:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == RESULT_OK && requestCode == UCrop.REQUEST_CROP) { val croppedUri = UCrop.getOutput(data!!) // 使用裁剪后的图片 } else if (resultCode == UCrop.RESULT_ERROR) { val error = UCrop.getError(data!!) // 处理错误 } }
PictureSelector
一站式图片选择+裁剪+压缩库,内置相机相册选择逻辑,无需自己处理权限和Uri:
添加依赖后,可通过简单配置实现选择+裁剪的完整流程,文档详细易上手。
三、常见问题排查
- 权限问题:Android 13+需额外申请
READ_MEDIA_IMAGES权限,动态权限申请要处理用户拒绝的情况。 - FileProvider配置错误:检查
authorities是否与代码中一致,file_paths.xml的路径是否正确指向存储目录。 - 系统裁剪不兼容:部分机型系统裁剪Intent参数有差异,可直接改用UCrop替代系统裁剪。
内容的提问来源于stack exchange,提问作者propeace
相关产品推荐
相关产品推荐

