|
|
@@ -1,272 +0,0 @@
|
|
|
-package com.narutohuo.xindazhou.common.camera
|
|
|
-
|
|
|
-import android.app.Activity
|
|
|
-import android.content.Intent
|
|
|
-import android.net.Uri
|
|
|
-import android.os.Build
|
|
|
-import android.provider.MediaStore
|
|
|
-import androidx.activity.ComponentActivity
|
|
|
-import androidx.activity.result.ActivityResultLauncher
|
|
|
-import androidx.activity.result.contract.ActivityResultContracts
|
|
|
-import androidx.core.content.FileProvider
|
|
|
-import androidx.fragment.app.Fragment
|
|
|
-import java.io.File
|
|
|
-
|
|
|
-/**
|
|
|
- * 相机/相册管理器
|
|
|
- *
|
|
|
- * 统一封装相机拍照、相册选择、图片裁剪功能
|
|
|
- *
|
|
|
- * 使用方式:
|
|
|
- * ```kotlin
|
|
|
- * // 注册拍照
|
|
|
- * private val takePhotoLauncher = CameraHelper.registerTakePhoto(this) { uri ->
|
|
|
- * // 处理拍照结果
|
|
|
- * }
|
|
|
- * takePhotoLauncher.launch()
|
|
|
- *
|
|
|
- * // 注册相册选择
|
|
|
- * private val pickGalleryLauncher = CameraHelper.registerPickGallery(this) { uri ->
|
|
|
- * // 处理相册选择结果
|
|
|
- * }
|
|
|
- * pickGalleryLauncher.launch()
|
|
|
- *
|
|
|
- * // 注册图片裁剪
|
|
|
- * private val cropImageLauncher = CameraHelper.registerCropImage(this) { uri ->
|
|
|
- * // 处理裁剪结果
|
|
|
- * }
|
|
|
- * cropImageLauncher.launch(sourceUri)
|
|
|
- * ```
|
|
|
- */
|
|
|
-object CameraHelper {
|
|
|
-
|
|
|
- /**
|
|
|
- * 临时文件目录(用于存储拍照和裁剪的临时文件)
|
|
|
- * 需要在 Application 中设置
|
|
|
- */
|
|
|
- var tempFileDir: File? = null
|
|
|
-
|
|
|
- /**
|
|
|
- * FileProvider Authority(用于 Android 7.0+ 文件共享)
|
|
|
- * 需要在 Application 中设置,格式:${applicationId}.fileprovider
|
|
|
- */
|
|
|
- var fileProviderAuthority: String? = null
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册拍照功能(Activity)
|
|
|
- *
|
|
|
- * @param activity ComponentActivity 实例
|
|
|
- * @param onResult 拍照结果回调
|
|
|
- * @return ActivityResultLauncher,调用 launch(uri) 启动相机(需要先创建临时文件并获取 URI)
|
|
|
- */
|
|
|
- fun registerTakePhoto(
|
|
|
- activity: ComponentActivity,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Uri> {
|
|
|
- return activity.registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
|
|
|
- if (success) {
|
|
|
- // 注意:TakePicture 会自动保存到传入的 URI,这里需要调用者传入 URI
|
|
|
- // 实际使用时应该在调用处创建临时文件并传入 URI
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册拍照功能(Fragment)
|
|
|
- *
|
|
|
- * @param fragment Fragment 实例
|
|
|
- * @param onResult 拍照结果回调
|
|
|
- * @return ActivityResultLauncher
|
|
|
- */
|
|
|
- fun registerTakePhoto(
|
|
|
- fragment: Fragment,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Uri> {
|
|
|
- return fragment.registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
|
|
|
- if (success) {
|
|
|
- val tempFile = createTempImageFile(fragment.requireContext())
|
|
|
- val uri = getUriForFile(fragment.requireContext(), tempFile)
|
|
|
- onResult(uri)
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 创建临时文件并启动拍照
|
|
|
- *
|
|
|
- * @param launcher ActivityResultLauncher(通过 registerTakePhoto 获取)
|
|
|
- * @param context 上下文
|
|
|
- * @param onResult 拍照结果回调(返回图片 URI)
|
|
|
- */
|
|
|
- fun takePhoto(
|
|
|
- launcher: ActivityResultLauncher<Uri>,
|
|
|
- context: android.content.Context,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ) {
|
|
|
- val tempFile = createTempImageFile(context)
|
|
|
- val uri = getUriForFile(context, tempFile)
|
|
|
- launcher.launch(uri)
|
|
|
- // 注意:TakePicture 会自动保存到传入的 URI,所以这里需要保存 URI 以便后续使用
|
|
|
- // 实际使用时应该在调用处保存 URI 并在回调中处理
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册相册选择功能(Activity)
|
|
|
- *
|
|
|
- * @param activity ComponentActivity 实例
|
|
|
- * @param onResult 选择结果回调
|
|
|
- * @return ActivityResultLauncher
|
|
|
- */
|
|
|
- fun registerPickGallery(
|
|
|
- activity: ComponentActivity,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Intent> {
|
|
|
- return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
|
|
- if (result.resultCode == Activity.RESULT_OK) {
|
|
|
- val uri = result.data?.data
|
|
|
- onResult(uri)
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册相册选择功能(Fragment)
|
|
|
- *
|
|
|
- * @param fragment Fragment 实例
|
|
|
- * @param onResult 选择结果回调
|
|
|
- * @return ActivityResultLauncher
|
|
|
- */
|
|
|
- fun registerPickGallery(
|
|
|
- fragment: Fragment,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Intent> {
|
|
|
- return fragment.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
|
|
- if (result.resultCode == Activity.RESULT_OK) {
|
|
|
- val uri = result.data?.data
|
|
|
- onResult(uri)
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 启动相册选择
|
|
|
- *
|
|
|
- * @param launcher ActivityResultLauncher(通过 registerPickGallery 获取)
|
|
|
- */
|
|
|
- fun pickFromGallery(launcher: ActivityResultLauncher<Intent>) {
|
|
|
- val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
|
|
|
- launcher.launch(intent)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册图片裁剪功能(Activity)
|
|
|
- *
|
|
|
- * @param activity ComponentActivity 实例
|
|
|
- * @param onResult 裁剪结果回调
|
|
|
- * @return ActivityResultLauncher,调用 launch(intent) 启动裁剪
|
|
|
- */
|
|
|
- fun registerCropImage(
|
|
|
- activity: ComponentActivity,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Intent> {
|
|
|
- return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
|
|
- if (result.resultCode == Activity.RESULT_OK) {
|
|
|
- val uri = result.data?.data
|
|
|
- onResult(uri)
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 注册图片裁剪功能(Fragment)
|
|
|
- *
|
|
|
- * @param fragment Fragment 实例
|
|
|
- * @param onResult 裁剪结果回调
|
|
|
- * @return ActivityResultLauncher
|
|
|
- */
|
|
|
- fun registerCropImage(
|
|
|
- fragment: Fragment,
|
|
|
- onResult: (Uri?) -> Unit
|
|
|
- ): ActivityResultLauncher<Uri> {
|
|
|
- return fragment.registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
|
|
|
- if (success) {
|
|
|
- val tempFile = createTempImageFile(fragment.requireContext())
|
|
|
- val uri = getUriForFile(fragment.requireContext(), tempFile)
|
|
|
- onResult(uri)
|
|
|
- } else {
|
|
|
- onResult(null)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 启动图片裁剪
|
|
|
- *
|
|
|
- * @param launcher ActivityResultLauncher(通过 registerCropImage 获取)
|
|
|
- * @param context 上下文
|
|
|
- * @param sourceUri 源图片 URI
|
|
|
- * @param outputUri 输出图片 URI(可选,如果为 null 则使用临时文件)
|
|
|
- */
|
|
|
- fun cropImage(
|
|
|
- launcher: ActivityResultLauncher<Intent>,
|
|
|
- context: android.content.Context,
|
|
|
- sourceUri: Uri,
|
|
|
- outputUri: Uri? = null
|
|
|
- ) {
|
|
|
- val finalOutputUri = outputUri ?: run {
|
|
|
- val tempFile = createTempImageFile(context)
|
|
|
- getUriForFile(context, tempFile)
|
|
|
- }
|
|
|
-
|
|
|
- val intent = Intent("com.android.camera.action.CROP").apply {
|
|
|
- setDataAndType(sourceUri, "image/*")
|
|
|
- putExtra("crop", "true")
|
|
|
- putExtra("aspectX", 1)
|
|
|
- putExtra("aspectY", 1)
|
|
|
- putExtra("outputX", 800)
|
|
|
- putExtra("outputY", 800)
|
|
|
- putExtra("scale", true)
|
|
|
- putExtra("return-data", false)
|
|
|
- putExtra(MediaStore.EXTRA_OUTPUT, finalOutputUri)
|
|
|
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
|
- addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
|
- }
|
|
|
-
|
|
|
- launcher.launch(intent)
|
|
|
- }
|
|
|
-
|
|
|
- // ========== 内部辅助方法 ==========
|
|
|
-
|
|
|
- /**
|
|
|
- * 创建临时图片文件
|
|
|
- */
|
|
|
- private fun createTempImageFile(context: android.content.Context): File {
|
|
|
- val dir = tempFileDir ?: context.cacheDir
|
|
|
- val fileName = "temp_image_${System.currentTimeMillis()}.jpg"
|
|
|
- return File(dir, fileName)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取文件的 URI(兼容 Android 7.0+)
|
|
|
- */
|
|
|
- private fun getUriForFile(context: android.content.Context, file: File): Uri {
|
|
|
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
- val authority = fileProviderAuthority
|
|
|
- ?: throw IllegalStateException("fileProviderAuthority 未设置,请在 Application 中设置")
|
|
|
- FileProvider.getUriForFile(context, authority, file)
|
|
|
- } else {
|
|
|
- Uri.fromFile(file)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|