要在 Android 13 上实现图片选择、显示并添加裁剪功能,我们可以使用第三方裁剪库如 UCrop。以下是完整实现方案:
1. 添加依赖
在 build.gradle (Module) 中添加:
dependencies {// 基础依赖implementation 'androidx.activity:activity-ktx:1.7.0'implementation 'androidx.fragment:fragment-ktx:1.5.7'implementation 'com.github.bumptech.glide:glide:4.14.2'annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'// 图片裁剪库implementation 'com.github.yalantis:ucrop:2.2.8'// 可选,用于处理Android 13+照片选择器implementation 'androidx.activity:activity-ktx:1.7.0'
}
ImagePickerWithCropActivity.kt
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.bumptech.glide.signature.ObjectKey
import com.yalantis.ucrop.UCrop
import smartconnection.com.smartconnect.R
import java.io.Fileclass ImagePickerWithCropActivity : AppCompatActivity() {private lateinit var imageView: ImageViewprivate lateinit var selectButton: Button// 临时文件用于存储裁剪后的图片private val cropFile by lazy {File(externalCacheDir, "cropped_image.jpg")}// 图片选择启动器private val pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK) {result.data?.data?.let { uri ->// 启动裁剪startCrop(uri)}}}// 裁剪结果启动器private val cropImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK) {result.data?.let { intent ->UCrop.getOutput(intent)?.let { uri ->// 显示裁剪后的图片displayImage(uri)}}} else if (result.resultCode == UCrop.RESULT_ERROR) {result.data?.let {val cropError = UCrop.getError(it)Toast.makeText(this, "裁剪错误: ${cropError?.message}", Toast.LENGTH_SHORT).show()}}}// 权限请求启动器private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->if (isGranted) {openImagePicker()} else {Toast.makeText(this,"需要权限才能访问图片",Toast.LENGTH_SHORT).show()}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_image_picker_crop)imageView = findViewById(R.id.imageView)selectButton = findViewById(R.id.selectButton)selectButton.setOnClickListener {checkPermissionAndPickImage()}}private fun checkPermissionAndPickImage() {// Android 13+使用READ_MEDIA_IMAGES,低版本使用READ_EXTERNAL_STORAGEval permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {Manifest.permission.READ_MEDIA_IMAGES} else {Manifest.permission.READ_EXTERNAL_STORAGE}when {ContextCompat.checkSelfPermission(this,permission) == PackageManager.PERMISSION_GRANTED -> {openImagePicker()}shouldShowRequestPermissionRationale(permission) -> {Toast.makeText(this,"需要权限才能访问您的图片",Toast.LENGTH_SHORT).show()requestPermissionLauncher.launch(permission)}else -> {requestPermissionLauncher.launch(permission)}}}private fun openImagePicker() {val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)pickImageLauncher.launch(intent)}private fun startCrop(sourceUri: Uri) {val destinationUri = Uri.fromFile(cropFile)UCrop.of(sourceUri, destinationUri).withAspectRatio(1f, 1f) // 1:1比例.withMaxResultSize(1000, 1000) // 最大尺寸.withOptions(getCropOptions()) // 自定义选项.start(this, cropImageLauncher)}private fun getCropOptions(): UCrop.Options {val options = UCrop.Options()options.setHideBottomControls(true) // 显示底部控制栏options.setFreeStyleCropEnabled(true) // 允许自由裁剪options.setStatusBarColor(ContextCompat.getColor(this, R.color.white))options.setToolbarColor(ContextCompat.getColor(this, R.color.white))options.setToolbarTitle("图片裁剪")return options}private fun displayImage(uri: Uri) {Glide.with(this).load(uri).signature(ObjectKey(System.currentTimeMillis().toString())) // 使用时间戳作为签名.centerCrop().into(imageView)}
}
activity_image_picker_crop.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"android:gravity="center"><ImageViewandroid:id="@+id/imageView"android:layout_width="300dp"android:layout_height="300dp"android:scaleType="centerCrop"android:background="#f0f0f0"android:contentDescription="Cropped image" /><Buttonandroid:id="@+id/selectButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="24dp"android:text="选择并裁剪图片" /></LinearLayout>
AndroidManifest.xml配置:
<!--相册--><uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><!-- 对于 Android 13 以下版本的回退权限 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"android:maxSdkVersion="32" />
在 AndroidManifest.xml 中添加 UCrop 所需的配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="your.package.name"><application><!-- 其他你的Activity声明 --><!-- UCrop 所需的Activity声明 --><activityandroid:name="com.yalantis.ucrop.UCropActivity"android:screenOrientation="portrait"android:theme="@style/Theme.AppCompat.Light.NoActionBar"/><!-- 其他配置 --></application></manifest>