camera1-to-camerax

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Step 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 (
libs.versions.toml
), add the following:
kotlin
[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" }
<br />
And in your
build.gradle.kts
(or
build.gradle
):
kotlin
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)
<br />
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>"
<br />
检查并添加所需的CameraX依赖项。如需兼容性请使用1.3.0或更高版本,如需Compose扩展请使用1.5.0或更高版本。
如果您使用版本目录(
libs.versions.toml
),请添加以下内容:
kotlin
[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" }
<br />
然后在您的
build.gradle.kts
(或
build.gradle
)中添加:
kotlin
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)
<br />
如果不使用版本目录,请使用以下标准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>"
<br />

Step 1: Remove Legacy Implementation

步骤1:移除旧版实现

  1. Delete all
    android.hardware.Camera
    instances.
  2. Delete
    SurfaceView
    and
    SurfaceHolder.Callback
    implementations (
    surfaceCreated
    ,
    surfaceChanged
    ,
    surfaceDestroyed
    ).
  3. Remove custom lifecycle handling that opens or releases the camera in
    onResume
    or
    onPause
    .
  4. Remove manual matrix calculations for orientation.
  1. 删除所有
    android.hardware.Camera
    实例。
  2. 删除
    SurfaceView
    SurfaceHolder.Callback
    实现(
    surfaceCreated
    surfaceChanged
    surfaceDestroyed
    )。
  3. 移除在
    onResume
    onPause
    中打开或释放相机的自定义生命周期处理逻辑。
  4. 移除用于方向的手动矩阵计算。

Step 2: Initialize ProcessCameraProvider

步骤2:初始化ProcessCameraProvider

Request the
ProcessCameraProvider
and bind use cases to the Activity or Fragment lifecycle.
kotlin
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)
  )
}
<br />
请求
ProcessCameraProvider
并将用例绑定到Activity或Fragment的生命周期。
kotlin
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)
  )
}
<br />

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.PreviewView
.
1. Set up preview:
kotlin
preview.setSurfaceProvider(previewView.surfaceProvider)
<br />
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)
<br />
使用
androidx.camera.view.PreviewView
1. 设置预览:
kotlin
preview.setSurfaceProvider(previewView.surfaceProvider)
<br />
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)
<br />

Option B: For Jetpack Compose

选项B:适用于Jetpack Compose

Use
androidx.camera.compose.CameraXViewfinder
.
1. Set up preview and SurfaceRequest:
kotlin
var surfaceRequest by remember { mutableStateOf<SurfaceRequest?>(null) }
val preview = remember {
  Preview.Builder().build().apply {
    setSurfaceProvider { request -> surfaceRequest = request }
  }
}
<br />
2. Render viewfinder:
kotlin
surfaceRequest?.let { request ->
  CameraXViewfinder(
    surfaceRequest = request,
    coordinateTransformer = coordinateTransformer,
    modifier = Modifier
  )
}
<br />
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)
<br />
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
  }
}
<br />
使用
androidx.camera.compose.CameraXViewfinder
1. 设置预览与SurfaceRequest:
kotlin
var surfaceRequest by remember { mutableStateOf<SurfaceRequest?>(null) }
val preview = remember {
  Preview.Builder().build().apply {
    setSurfaceProvider { request -> surfaceRequest = request }
  }
}
<br />
2. 渲染取景器:
kotlin
surfaceRequest?.let { request ->
  CameraXViewfinder(
    surfaceRequest = request,
    coordinateTransformer = coordinateTransformer,
    modifier = Modifier
  )
}
<br />
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)
<br />
4. 更新Compose的目标旋转:
kotlin
LaunchedEffect(configuration) {
  if (!view.isInEditMode) {
    val rotation = view.display?.rotation ?: Surface.ROTATION_0
    imageCapture.targetRotation = rotation
    preview.targetRotation = rotation
  }
}
<br />

Step 4: Capture Photo

步骤4:拍摄照片

Use the
ImageCapture
use case to take the picture. The
ImageProxy
handles rotation directly.
kotlin
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)
    }
  }
)
<br />
使用
ImageCapture
用例拍摄照片。
ImageProxy
会直接处理旋转问题。
kotlin
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)
    }
  }
)
<br />

Step 5: Switch Cameras

步骤5:切换相机

To flip between front and rear cameras, change the
CameraSelector
and re-trigger the
ProcessCameraProvider
logic.
kotlin
lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
  CameraSelector.LENS_FACING_FRONT
} else {
  CameraSelector.LENS_FACING_BACK
}
<br />
要在前后摄像头之间切换,只需更改
CameraSelector
并重新触发
ProcessCameraProvider
逻辑。
kotlin
lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
  CameraSelector.LENS_FACING_FRONT
} else {
  CameraSelector.LENS_FACING_BACK
}
<br />

Constraints

约束条件

  • Don't manage the camera lifecycle manually : Bind the camera to a
    LifecycleOwner
    through the
    ProcessCameraProvider
    . Avoid manual camera open or close logic in
    onResume
    or
    onPause
    .
  • Don't calculate focus matrices manually :
    MeteringPointFactory
    handles coordinate transformations, including device rotation offsets. Avoid custom matrix implementations.
  • Don't forget to close the ImageProxy : Remember to invoke
    image.close()
    in the capture callback. Skipping this call locks the capture pipeline and interrupts subsequent photos.
  • Don't wrap
    PreviewView
    in
    AndroidView
    for Compose code
    : For Compose UI layouts, use
    CameraXViewfinder
    . Compiling
    PreviewView
    in an
    AndroidView
    is an old fallback option that introduces resizing issues.
  • 请勿手动管理相机生命周期:通过
    ProcessCameraProvider
    将相机绑定到
    LifecycleOwner
    。避免在
    onResume
    onPause
    中使用手动打开或关闭相机的逻辑。
  • 请勿手动计算对焦矩阵
    MeteringPointFactory
    会处理坐标转换,包括设备旋转偏移。避免使用自定义矩阵实现。
  • 请勿忘记关闭ImageProxy:记得在捕获回调中调用
    image.close()
    。跳过此调用会锁定捕获管线并中断后续拍摄。
  • 请勿在Compose代码中用
    AndroidView
    包裹
    PreviewView
    :对于Compose UI布局,请使用
    CameraXViewfinder
    。在
    AndroidView
    中编译
    PreviewView
    是旧版 fallback 方案,会导致尺寸调整问题。