Android Studio中使用ActivityResultLauncher选图库图片后无三方库实现1:1裁剪
实现方案(无第三方库,兼容API 16+)
你可以直接调用Android系统原生的裁剪组件实现需求,仅需要新增裁剪逻辑和配套的ActivityResultLauncher即可,以下是完整实现步骤:
1. 前置配置(适配高版本系统文件访问)
首先在AndroidManifest.xml中添加权限和FileProvider配置,避免Android 7.0+以上的Uri暴露异常:
<!-- 必要权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <application ...> <!-- FileProvider配置 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${你的应用包名}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
然后在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="my_images" path="Pictures" /> </paths>
2. 声明两个ActivityResultLauncher
替换你原有代码的Launcher声明,新增裁剪结果接收的Launcher:
// 1. 图库选图Launcher ActivityResultLauncher<String> pickImageLauncher = registerForActivityResult( new ActivityResultContracts.GetContent(), result -> { if (result != null) { // 选图成功,启动系统裁剪 startCrop(result); } } ); // 2. 裁剪结果接收Launcher ActivityResultLauncher<Intent> cropImageLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK && result.getData() != null) { // 裁剪成功,加载到ImageView Uri croppedUri = Uri.fromFile(cropOutputFile); Picasso.with(MainActivity.this).load(croppedUri).into(shapeableImageView); } } ); // 全局变量,保存裁剪后输出的文件 private File cropOutputFile;
3. 实现裁剪启动方法
private void startCrop(Uri sourceUri) { // 先创建裁剪后输出的文件 File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try { cropOutputFile = File.createTempFile( "cropped_" + System.currentTimeMillis(), ".jpg", storageDir ); } catch (IOException e) { e.printStackTrace(); return; } Uri outputUri; // 适配Android 7.0+的Uri获取 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { outputUri = FileProvider.getUriForFile( this, "${你的应用包名}.fileprovider", cropOutputFile ); } else { outputUri = Uri.fromFile(cropOutputFile); } // 构建裁剪意图 Intent intent = new Intent("com.android.camera.action.CROP"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(sourceUri, "image/*"); // 配置裁剪参数 intent.putExtra("crop", "true"); // 1:1裁剪比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // 裁剪输出的分辨率,可根据需求调整 intent.putExtra("outputX", 500); intent.putExtra("outputY", 500); intent.putExtra("scale", true); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); cropImageLauncher.launch(intent); }
4. 原有选图触发方法保持不变
private void openImagePicker() { pickImageLauncher.launch("image/*"); }
注意事项
- 请把代码中
${你的应用包名}替换为你项目实际的包名,和Manifest里的authorities保持一致 - 部分国产定制系统可能裁剪组件存在兼容性问题,但覆盖95%以上的主流机型完全没问题
- 如果不需要保存裁剪后的文件到本地,也可以直接读取outputUri的Bitmap使用,避免占用存储空间
内容的提问来源于stack exchange,提问作者Intelligence
相关产品推荐
相关产品推荐

