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

相关推荐
STCNXPARM15 小时前
Android camera之硬件架构
android·硬件架构·camera
2501_9445255417 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 支出分析页面
android·开发语言·前端·javascript·flutter
松☆18 小时前
Dart 核心语法精讲:从空安全到流程控制(3)
android·java·开发语言
_李小白20 小时前
【Android 美颜相机】第二十三天:GPUImageDarkenBlendFilter(变暗混合滤镜)
android·数码相机
小天源1 天前
银河麒麟 V10(x86_64)离线安装 MySQL 8.0
android·mysql·adb·麒麟v10
2501_915921431 天前
傻瓜式 HTTPS 抓包,简单抓取iOS设备数据
android·网络协议·ios·小程序·https·uni-app·iphone
csj501 天前
安卓基础之《(20)—高级控件(2)列表类视图》
android
JMchen1231 天前
Android计算摄影实战:多帧合成、HDR+与夜景算法深度剖析
android·经验分享·数码相机·算法·移动开发·android-studio
恋猫de小郭1 天前
Flutter 在 Android 出现随机字体裁剪?其实是图层合并时的边界计算问题
android·flutter·ios
2501_915918411 天前
把 iOS 性能监控融入日常开发与测试流程的做法
android·ios·小程序·https·uni-app·iphone·webview