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

相关推荐
fundroid1 分钟前
Androidify:谷歌官方 AI + Android 开源示例应用
android·人工智能·开源
4z3336 分钟前
Android15 Framework(2):应用进程的孵化器 Zygote 进程解析
android·源码阅读
00后程序员张1 小时前
iOS 抓不到包怎么办?从 HTTPS 解密、QUIC 排查到 TCP 数据流分析的完整解决方案
android·tcp/ip·ios·小程序·https·uni-app·iphone
李斯维3 小时前
布局性能优化利器:ViewStub 极简指南
android·性能优化
循环不息优化不止4 小时前
Ktor Pipeline 机制深度解析
android
q***56384 小时前
Springboot3学习(5、Druid使用及配置)
android·学习
q***64974 小时前
SpringSecurity踢出指定用户
android·前端·后端
q***76664 小时前
SpringSecurity 实现token 认证
android·前端·后端
Chejdj4 小时前
ViewModel#onCleared的实现原理
android·源码阅读
CheungChunChiu5 小时前
Android 系统中的 NTP 服务器配置与选择逻辑详解
android·运维·服务器