Android 开发者 04月06日 19:51
在 Jetpack Compose 中解锁 CameraX 的强大功能
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何使用 camera-compose 组件构建功能齐全的 Android 相机取景器,并涵盖了权限处理和基本集成。文章详细讲解了添加必要的库依赖项、授予相机权限,以及创建视图模型以管理相机预览。通过结合 Accompanist 权限库和 CameraXViewfinder 组件,开发者可以轻松构建出与 Compose 无缝集成的相机界面,实现自适应 API 和动画支持等特性。最终,文章展示了如何构建一个能够正常运行的相机取景器,为后续的开发提供了坚实的基础。

📸文章介绍了使用 Android 的 camera-compose 组件构建相机取景器的过程。

🔑首先,通过添加必要的库依赖项,包括 camera-core、camera-compose、camera-lifecycle、camera-camera2 和 accompanist-permissions,为项目配置相机功能。

✅接着,使用 Accompanist 权限库,通过修改 AndroidManifest.xml 文件并调用相关函数,轻松授予相机权限。

💻然后,创建一个 ViewModel 来管理相机预览逻辑,包括配置 Preview 用例和绑定相机到界面。

🖼️最后,通过 CameraXViewfinder 组件,将相机预览与 Compose UI 集成,实现一个功能齐全的全屏取景器。

原创 Android 2025-02-21 17:30 北京

本文是 "相机与媒体 Spotlight Week" 系列内容的第一篇,将为您介绍如何构建一个功能齐全的相机取景器,包括使用新的 camera-compose 组件构建基础相机预览,并涵盖权限处理和基本集成。

作者 / Google 开发者关系工程师 Jolanda Verhoef


本文是 "相机与媒体 Spotlight Week" 系列的内容之一。此系列中,我们会提供文章、视频、示例代码等资源,以帮助您提升应用中的媒体体验。


我们了解到您喜欢 CameraX 和 Jetpack Compose 库提供的强大功能,但希望使用更符合语言习惯的 Compose API 来构建相机界面。今年,我们的工程团队开发了两个新的 Compose 工件,即低层级 viewfinder-compose 和高层级 camera-compose。两者现在均已推出 alpha 版本 🚀🚀🚀。


在本系列文章中,我们不仅将为您介绍如何将 camera-compose API 集成到应用中,还将向您展示与 Compose 集成所带来的一些令人愉悦的界面体验。所有令人赞叹的 Compose 功能 (例如自适应 API 和动画支持) 均已与相机预览无缝集成。


完成所有这些操作后,我们的最终应用将如下所示:

此外,应用可以顺畅地在桌面模式之间切换:

到本文 (该系列第一篇文章) 的末尾,您将构建一个功能齐全的相机取景器,并将在后续系列文章中对其进行扩展。欢迎您跟随我们一起编写代码,在实践中更好地学习。


添加库依赖项



假设您已经在应用中设置了 Compose。如果您想继续,只需在 Android Studio 中新建一个应用即可。我们通常使用最新的 Canary 版本,因为这个版本会提供最新的 Compose 模板。


向您的 libs.versions.toml 中添加以下内容:
    [versions]..camerax = "1.5.0-alpha03"accompanist = "0.36.0" # or whatever matches with your Compose version
    [libraries]..# Contains the basic camera functionality such as SurfaceRequestandroidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "camerax" }# Contains the CameraXViewfinder composableandroidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "camerax" }# Allows us to bind the camera preview to our UI lifecycleandroidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }# The specific camera implementation that renders the previewandroidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }# The helper library to grant the camera permissionaccompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
    然后,将这些添加到您的模块 build.gradle.kts 依赖项块中:
      dependencies {  ..  implementation(libs.androidx.camera.core)  implementation(libs.androidx.camera.compose)  implementation(libs.androidx.camera.lifecycle)  implementation(libs.androidx.camera.camera2)  implementation(libs.accompanist.permissions)}
      为了授予相机权限,我们添加了所有依赖项,然后实际显示相机预览。接下来,让我们看看如何授予正确的权限。


      授予相机权限



      通过使用 Accompanist 权限库,我们可以轻松地授予正确的相机权限。首先,我们需要设置 AndroidManifest.xml
        <manifest xmlns:android="http://schemas.android.com/apk/res/android">    <uses-feature android:name="android.hardware.camera" android:required="true" />    <uses-permission android:name="android.permission.CAMERA" />
        ..
        </manifest>
        🔗 Accompanist 权限库
        https://google.github.io/accompanist/permissions/


        现在,我们只需按照库的说明授予正确的权限:
          class MainActivity : ComponentActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        enableEdgeToEdge()        setContent {            MyApplicationTheme {                CameraPreviewScreen()            }        }    }}
          @OptIn(ExperimentalPermissionsApi::class)@Composablefun CameraPreviewScreen(modifier: Modifier = Modifier) { val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA) if (cameraPermissionState.status.isGranted) { CameraPreviewContent(modifier) } else { Column( modifier = modifier.fillMaxSize().wrapContentSize().widthIn(max = 480.dp), horizontalAlignment = Alignment.CenterHorizontally ) { val textToShow = if (cameraPermissionState.status.shouldShowRationale) { // If the user has denied the permission but the rationale can be shown, // then gently explain why the app requires this permission "Whoops! Looks like we need your camera to work our magic!" + "Don't worry, we just wanna see your pretty face (and maybe some cats). " + "Grant us permission and let's get this party started!" } else { // If it's the first time the user lands on this feature, or the user // doesn't want to be asked again for this permission, explain that the // permission is required "Hi there! We need your camera to work our magic! ✨\n" + "Grant us permission and let's get this party started! \uD83C\uDF89" } Text(textToShow, textAlign = TextAlign.Center) Spacer(Modifier.height(16.dp)) Button(onClick = { cameraPermissionState.launchPermissionRequest() }) { Text("Unleash the Camera!") } } }}
          @Composableprivate fun CameraPreviewContent(modifier: Modifier = Modifier) { // TODO: Implement}
          这样,我们就得到了一个良好的界面,用户可以在显示相机预览之前授予相机权限:


          创建 ViewModel



          将业务逻辑与界面分开是一种很好的实践。为此,我们可以为屏幕创建视图模型来实现这一点。这个视图模型设置了 CameraX Preview 用例。请注意,CameraX 中的用例代表了可以使用该库实现的各种工作流程的配置,即预览、捕获、录制和分析。视图模型还将界面绑定到相机提供程序:
            class CameraPreviewViewModel : ViewModel() {    // Used to set up a link between the Camera and your UI.    private val _surfaceRequest = MutableStateFlow<SurfaceRequest?>(null)    val surfaceRequest: StateFlow<SurfaceRequest?> = _surfaceRequest
            private val cameraPreviewUseCase = Preview.Builder().build().apply { setSurfaceProvider { newSurfaceRequest -> _surfaceRequest.update { newSurfaceRequest } } }
            suspend fun bindToCamera(appContext: Context, lifecycleOwner: LifecycleOwner) { val processCameraProvider = ProcessCameraProvider.awaitInstance(appContext) processCameraProvider.bindToLifecycle( lifecycleOwner, DEFAULT_FRONT_CAMERA, cameraPreviewUseCase )
            // Cancellation signals we're done with the camera try { awaitCancellation() } finally { processCameraProvider.unbindAll() } }}
            此处会执行大量操作。代码定义了一个 CameraPreviewViewModel 类,负责管理相机预览。此类使用 CameraX Preview 构建器来配置预览与界面的绑定方式。bindToCamera 函数用于初始化相机,并将其绑定到指定的 LifecycleOwner,以确保相机至少在生命周期处于 "启动" 状态时运行,并启动预览流。


            相机作为相机库的内部组件,需要渲染到界面提供的 surface。因此,库需要有一种方法来请求 surface。这正是 SurfaceRequest 的用途。因此,每当相机表示需要 surface 时,就会触发 surfaceRequest。然后将该请求转发给界面,以便将 surface 传递给请求对象。


            最后,我们需要等待界面与相机完成绑定,并确保释放相机资源以避免资源泄漏。


            实现相机预览界面



            现在我们有了一个视图模型,可以实现 CameraPreviewContent 可组合项。该项从视图模型中读取 surface 请求,在可组合项位于组合树中时绑定到相机,并从库中调用 CameraXViewfinder
              @Composablefun CameraPreviewContent(    viewModel: CameraPreviewViewModel,    modifier: Modifier = Modifier,    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current) {    val surfaceRequest by viewModel.surfaceRequest.collectAsStateWithLifecycle()    val context = LocalContext.current    LaunchedEffect(lifecycleOwner) {         viewModel.bindToCamera(context.applicationContext, lifecycleOwner)     }
              surfaceRequest?.let { request -> CameraXViewfinder( surfaceRequest = request, modifier = modifier ) }}
              如上部分所述,surfaceRequest 允许相机库在需要渲染时请求一个 surface。在这段代码中,我们收集这些 surfaceRequest 实例,并将它们转发给属于 camera-compose 组件的 CameraXViewfinder


              结果


              就这样,我们构建了一个功能齐全的全屏取景器。了解完整代码片段,请访问相关文档
              https://gist.github.com/JolandaVerhoef/74d4696b804736c698450bd34b5c9ff8

              本文中的代码段包含以下许可证:
                // Copyright 2024 Google LLC. SPDX-License-Identifier: Apache-2.0

                欢迎您持续关注 "Android 开发者" 微信公众号,及时了解更多开发技术和产品更新等资讯动态!





                阅读原文

                跳转微信打开

                Fish AI Reader

                Fish AI Reader

                AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

                FishAI

                FishAI

                鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

                联系邮箱 441953276@qq.com

                相关标签

                Android CameraX Compose 相机开发
                相关文章