项目中经常需要用户从相册或者调用相机拍照来获取照片,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
