Compose从相册和系统相机拍照获取照片

项目中经常需要用户从相册或者调用相机拍照来获取照片,Compose中的实现和之前的View实现基础相同。为了简化照片选择器的集成,从androidx.activity版本1.7.0开始,提供了PickVisualMedia选择单张照片或单个视频,PickMultipleVisualMedia选择多张照片或多个视频。如果照片选择器在设备上不可用,该库会自动调用 ACTION_OPEN_DOCUMENT intent 操作。搭载 Android 4.4(API 级别 19)或更高版本的设备支持此 intent。

创建底部弹窗

模态底部面板可作为内联菜单或简单对话框的替代方案,尤其适用于提供较长的操作列表,或需要更详细描述和图标的操作项。与对话框类似,模态底部面板会出现在应用内容的前方,出现时会禁用应用的所有其他功能,并一直显示在屏幕上,直到用户确认、关闭或执行所需操作为止。

kotlin 复制代码
ModalBottomSheet(
  onDismissRequest = { },
  sheetGesturesEnabled = false,
  dragHandle = null
) {}

onDismissRequest用于处理弹窗隐藏回调;sheetGesturesEnabled设置为false,禁止手势拖动;dragHandle设置为false隐藏拖动条。

调系统相机拍照

注意

当AndroidManifest中注册了相机权限时,则调系统相机前必须先检查是否有相机权限;如果没有注册相机权限,则可直接调用系统相机进行拍照

权限处理

先检查AndroidManifest是否注册了相机权限,再判断是否有权限,否则直接当有权限处理,判断逻辑如下

kotlin 复制代码
private fun checkPermission(): Boolean {
  return application.packageManager.getPackageInfo(application.packageName, PackageManager.GET_PERMISSIONS)
    ?.takeIf { it.requestedPermissions?.contains(Manifest.permission.CAMERA) == true }
    ?.let {
      ContextCompat.checkSelfPermission(application, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
    } ?: true
}

若没有权限,则动态申请权限,代码如下

kotlin 复制代码
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()){}
launcher.launch(Manifest.permission.CAMERA)

使用FileProvider提供照片路径

由于使用的是系统相机进行拍照,需要使用FileProvider提供一个Uri,让相机拍完照后,保存到这个Uri对应的文件中。先在xml目录下定义文件file_paths.xml路径规则

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<paths>
  <files-path name="internal_files" path="." />
  <cache-path name="cache" path="." />
  <external-path name="external" path="." />
  <external-files-path name="external_files" path="." />
  <external-cache-path name="external_cache" path="." />
</paths>

在AndroidManifest中注册provider

xml 复制代码
<provider
  android:name="androidx.core.content.FileProvider"
  android:authorities="${applicationId}.provider"
  android:exported="false"
  android:grantUriPermissions="true">
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_paths" />
</provider>

调系统相机进行拍照

使用FileProvider提供的Uri进行拍照

kotlin 复制代码
if(checkPermission()){
  val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()){}
  val dir = File(application.cacheDir, Environment.DIRECTORY_PICTURES)
  val file = File(dir, "${SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(System.currentTimeMillis())}.jpg")
  launcher.launch(FileProvider.getUriForFile(application, "${application.packageName}.provider", file))
} else {
  val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()){}
  launcher.launch(Manifest.permission.CAMERA)
}

从相册选择照片

选择单张照片或视频

使用PickVisualMedia activity结果协定选择单张照片或视频

kotlin 复制代码
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) {}
launcher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))

PickVisualMedia.ImageOnly仅选择照片,PickVisualMedia.VideoOnly仅选择视频,PickVisualMedia.ImageAndVideo同时选择照片和视频。

注意:使用 PickVisualMedia 时,照片选择器会以半屏模式打开。

选择多张照片或视频

使用PickMultipleVisualMedia activity结果协定选择单张照片或视频

kotlin 复制代码
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(9)){}
launcher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))

平台会限制在照片选择器中选择的文件数量上限,如上代码最多选择9张照片。

注意:如果照片选择器不可用,且支持库调用 ACTION_OPEN_DOCUMENT intent 操作,则系统会忽略指定的可选媒体文件数量上限。这里的最大数量必须大于1

相关推荐
IT乐手4 小时前
Android 获取定位信息工具类
android
yangjunjin4 小时前
Android ANR的解决方案
android
低调小一4 小时前
Android Gradle 的 compileOptions 与 Kotlin jvmTarget 全面理解(含案例)
android·开发语言·kotlin
苦学编程啊8 小时前
【2025Flutter 入门指南】Dart SDK 安装与 VS Code 环境配置-Windows
android·dart
yuanManGan14 小时前
走进Linux的世界:初识操作系统(Operator System)
android·linux·运维
叶羽西14 小时前
Android15跟踪函数调用关系
android
消失的旧时光-194316 小时前
webView 的canGoBack/goBack 回退栈
android·webview
SHEN_ZIYUAN16 小时前
Flow 责任链模式图解
android
沐怡旸18 小时前
【底层机制】LeakCanary深度解析:从对象监控到内存泄漏分析的完整技术体系
android·面试