camera1-to-camerax
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStep 0: Add Dependencies
步骤0:添加依赖项
Check for and add the required CameraX dependencies. Use version 1.3.0 or higher
for interoperability, or version 1.5.0 or higher for Compose extensions.
If you are using a Version Catalog (), add the following:
libs.versions.tomlkotlin
[versions]
camerax = "<minimum_version_needed>"
[libraries]
androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "camerax" }
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "camerax" }
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" }
androidx-camera-compose = { group = "androidx.camera", name = "camera-compose", version.ref = "camerax" }And in your (or ):
build.gradle.ktsbuild.gradlekotlin
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.compose)Without a Version Catalog, fall back to these standard Gradle dependencies:
kotlin
implementation "androidx.camera:camera-core:<minimum_version_needed>"
implementation "androidx.camera:camera-camera2:<minimum_version_needed>"
implementation "androidx.camera:camera-lifecycle:<minimum_version_needed>"
implementation "androidx.camera:camera-view:<minimum_version_needed>"
implementation "androidx.camera:camera-compose:<minimum_version_needed>"检查并添加所需的CameraX依赖项。如需兼容性请使用1.3.0或更高版本,如需Compose扩展请使用1.5.0或更高版本。
如果您使用版本目录(),请添加以下内容:
libs.versions.tomlkotlin
[versions]
camerax = "<minimum_version_needed>"
[libraries]
androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "camerax" }
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "camerax" }
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" }
androidx-camera-compose = { group = "androidx.camera", name = "camera-compose", version.ref = "camerax" }然后在您的(或)中添加:
build.gradle.ktsbuild.gradlekotlin
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.compose)如果不使用版本目录,请使用以下标准Gradle依赖项:
kotlin
implementation "androidx.camera:camera-core:<minimum_version_needed>"
implementation "androidx.camera:camera-camera2:<minimum_version_needed>"
implementation "androidx.camera:camera-lifecycle:<minimum_version_needed>"
implementation "androidx.camera:camera-view:<minimum_version_needed>"
implementation "androidx.camera:camera-compose:<minimum_version_needed>"Step 1: Remove Legacy Implementation
步骤1:移除旧版实现
- Delete all instances.
android.hardware.Camera - Delete and
SurfaceViewimplementations (SurfaceHolder.Callback,surfaceCreated,surfaceChanged).surfaceDestroyed - Remove custom lifecycle handling that opens or releases the camera in or
onResume.onPause - Remove manual matrix calculations for orientation.
- 删除所有实例。
android.hardware.Camera - 删除和
SurfaceView实现(SurfaceHolder.Callback、surfaceCreated、surfaceChanged)。surfaceDestroyed - 移除在或
onResume中打开或释放相机的自定义生命周期处理逻辑。onPause - 移除用于方向的手动矩阵计算。
Step 2: Initialize ProcessCameraProvider
步骤2:初始化ProcessCameraProvider
Request the and bind use cases to the Activity or
Fragment lifecycle.
ProcessCameraProviderkotlin
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(context, lifecycleOwner) {
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
cameraProvider.unbindAll() // Unbind before rebinding
val camera = cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview,
imageCapture
)
val cameraControl = camera.cameraControl
}, ContextCompat.getMainExecutor(context)
)
}请求并将用例绑定到Activity或Fragment的生命周期。
ProcessCameraProviderkotlin
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(context, lifecycleOwner) {
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
cameraProvider.unbindAll() // Unbind before rebinding
val camera = cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview,
imageCapture
)
val cameraControl = camera.cameraControl
}, ContextCompat.getMainExecutor(context)
)
}Step 3: Implement the Preview & Tap-to-Focus
步骤3:实现预览与点击对焦
Choose exactly one of the following patterns based on the app's UI toolkit:
根据应用的UI工具包选择以下其中一种方案:
Option A: For Android Views (XML Legacy)
选项A:适用于Android Views(XML旧版)
Use .
androidx.camera.view.PreviewView1. Set up preview:
kotlin
preview.setSurfaceProvider(previewView.surfaceProvider)2. Handle tap-to-focus:
kotlin
val factory = previewView.meteringPointFactory
val point = factory.createPoint(x, y) // x, y from touch event
val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF).build()
cameraControl?.startFocusAndMetering(action)使用。
androidx.camera.view.PreviewView1. 设置预览:
kotlin
preview.setSurfaceProvider(previewView.surfaceProvider)2. 处理点击对焦:
kotlin
val factory = previewView.meteringPointFactory
val point = factory.createPoint(x, y) // x, y from touch event
val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF).build()
cameraControl?.startFocusAndMetering(action)Option B: For Jetpack Compose
选项B:适用于Jetpack Compose
Use .
androidx.camera.compose.CameraXViewfinder1. Set up preview and SurfaceRequest:
kotlin
var surfaceRequest by remember { mutableStateOf<SurfaceRequest?>(null) }
val preview = remember {
Preview.Builder().build().apply {
setSurfaceProvider { request -> surfaceRequest = request }
}
}2. Render viewfinder:
kotlin
surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
coordinateTransformer = coordinateTransformer,
modifier = Modifier
)
}3. Handle tap-to-focus in Compose:
kotlin
// Inside your tap gesture handler...
val surfaceCoords = with(coordinateTransformer) { offset.transform() }
val factory = SurfaceOrientedMeteringPointFactory(
request.resolution.width.toFloat(),
request.resolution.height.toFloat()
)
val point = factory.createPoint(surfaceCoords.x, surfaceCoords.y)
val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF).build()
cameraControl?.startFocusAndMetering(action)4. Update target rotation for Compose:
kotlin
LaunchedEffect(configuration) {
if (!view.isInEditMode) {
val rotation = view.display?.rotation ?: Surface.ROTATION_0
imageCapture.targetRotation = rotation
preview.targetRotation = rotation
}
}使用。
androidx.camera.compose.CameraXViewfinder1. 设置预览与SurfaceRequest:
kotlin
var surfaceRequest by remember { mutableStateOf<SurfaceRequest?>(null) }
val preview = remember {
Preview.Builder().build().apply {
setSurfaceProvider { request -> surfaceRequest = request }
}
}2. 渲染取景器:
kotlin
surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
coordinateTransformer = coordinateTransformer,
modifier = Modifier
)
}3. 在Compose中处理点击对焦:
kotlin
// Inside your tap gesture handler...
val surfaceCoords = with(coordinateTransformer) { offset.transform() }
val factory = SurfaceOrientedMeteringPointFactory(
request.resolution.width.toFloat(),
request.resolution.height.toFloat()
)
val point = factory.createPoint(surfaceCoords.x, surfaceCoords.y)
val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF).build()
cameraControl?.startFocusAndMetering(action)4. 更新Compose的目标旋转:
kotlin
LaunchedEffect(configuration) {
if (!view.isInEditMode) {
val rotation = view.display?.rotation ?: Surface.ROTATION_0
imageCapture.targetRotation = rotation
preview.targetRotation = rotation
}
}Step 4: Capture Photo
步骤4:拍摄照片
Use the use case to take the picture. The handles
rotation directly.
ImageCaptureImageProxykotlin
imageCapture.takePicture(
cameraExecutor,
object : ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(image: ImageProxy) {
val buffer = image.planes[0].buffer
val bytes = ByteArray(buffer.remaining())
buffer.get(bytes)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
// Adjust rotation natively via ImageProxy
val matrix = Matrix()
matrix.postRotate(image.imageInfo.rotationDegrees.toFloat())
if (lensFacing == CameraSelector.LENS_FACING_FRONT) {
matrix.postScale(-1f, 1f) // Mirror for front camera
}
val rotatedBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true
)
// MUST close proxy
image.close()
}
override fun onError(exception: ImageCaptureException) {
Log.e("CameraX", "Capture failed: ${exception.message}", exception)
}
}
)使用用例拍摄照片。会直接处理旋转问题。
ImageCaptureImageProxykotlin
imageCapture.takePicture(
cameraExecutor,
object : ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(image: ImageProxy) {
val buffer = image.planes[0].buffer
val bytes = ByteArray(buffer.remaining())
buffer.get(bytes)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
// Adjust rotation natively via ImageProxy
val matrix = Matrix()
matrix.postRotate(image.imageInfo.rotationDegrees.toFloat())
if (lensFacing == CameraSelector.LENS_FACING_FRONT) {
matrix.postScale(-1f, 1f) // Mirror for front camera
}
val rotatedBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true
)
// MUST close proxy
image.close()
}
override fun onError(exception: ImageCaptureException) {
Log.e("CameraX", "Capture failed: ${exception.message}", exception)
}
}
)Step 5: Switch Cameras
步骤5:切换相机
To flip between front and rear cameras, change the and
re-trigger the logic.
CameraSelectorProcessCameraProviderkotlin
lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
CameraSelector.LENS_FACING_FRONT
} else {
CameraSelector.LENS_FACING_BACK
}要在前后摄像头之间切换,只需更改并重新触发逻辑。
CameraSelectorProcessCameraProviderkotlin
lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
CameraSelector.LENS_FACING_FRONT
} else {
CameraSelector.LENS_FACING_BACK
}Constraints
约束条件
- Don't manage the camera lifecycle manually : Bind the camera to a through the
LifecycleOwner. Avoid manual camera open or close logic inProcessCameraProvideroronResume.onPause - Don't calculate focus matrices manually : handles coordinate transformations, including device rotation offsets. Avoid custom matrix implementations.
MeteringPointFactory - Don't forget to close the ImageProxy : Remember to invoke in the capture callback. Skipping this call locks the capture pipeline and interrupts subsequent photos.
image.close() - Don't wrap in
PreviewViewfor Compose code : For Compose UI layouts, useAndroidView. CompilingCameraXViewfinderin anPreviewViewis an old fallback option that introduces resizing issues.AndroidView
- 请勿手动管理相机生命周期:通过将相机绑定到
ProcessCameraProvider。避免在LifecycleOwner或onResume中使用手动打开或关闭相机的逻辑。onPause - 请勿手动计算对焦矩阵:会处理坐标转换,包括设备旋转偏移。避免使用自定义矩阵实现。
MeteringPointFactory - 请勿忘记关闭ImageProxy:记得在捕获回调中调用。跳过此调用会锁定捕获管线并中断后续拍摄。
image.close() - 请勿在Compose代码中用包裹
AndroidView:对于Compose UI布局,请使用PreviewView。在CameraXViewfinder中编译AndroidView是旧版 fallback 方案,会导致尺寸调整问题。PreviewView