This guide helps you migrate from older versions of compose-camera to the latest API.
The rememberCameraController function has moved from the core module to the compose module.
Before:
import io.github.l2hyunwoo.compose.camera.core.rememberCameraController
@Composable
fun CameraScreen() {
val controller = rememberCameraController(configuration)
}After:
import io.github.l2hyunwoo.compose.camera.ui.rememberCameraController
@Composable
fun CameraScreen() {
val controller = rememberCameraController(configuration)
}The old import will show a deprecation warning. Simply update the import statement.
focus(Offset) is deprecated in favor of focus(FocusPoint) for platform-agnostic focus control.
Before:
import androidx.compose.ui.geometry.Offset
// Using Compose Offset
cameraControl.focus(Offset(0.5f, 0.5f))After:
import io.github.l2hyunwoo.compose.camera.core.FocusPoint
// Using platform-agnostic FocusPoint
cameraControl.focus(FocusPoint(0.5f, 0.5f))
// Or use the CENTER constant
cameraControl.focus(FocusPoint.CENTER)
// For tap coordinates from UI, use clamped() to ensure valid range
val focusPoint = FocusPoint.clamped(tapX / viewWidth, tapY / viewHeight)
cameraControl.focus(focusPoint)Compose Extension: If you're using Compose, convenience extensions are available:
import io.github.l2hyunwoo.compose.camera.ui.toFocusPoint
import io.github.l2hyunwoo.compose.camera.ui.toOffset
// Convert Offset to FocusPoint
val focusPoint = offset.toFocusPoint()
// Convert FocusPoint back to Offset
val offset = focusPoint.toOffset()The new DSL provides a cleaner way to configure the camera controller.
Before (Configuration only):
val controller = rememberCameraController(
configuration = CameraConfiguration(
lens = CameraLens.BACK,
flashMode = FlashMode.AUTO
)
)After (DSL with extensions and plugins):
// Simple usage
val controller = CameraController()
// Full DSL configuration
val controller = CameraController {
configuration = CameraConfiguration(
lens = CameraLens.BACK,
flashMode = FlashMode.AUTO
)
extensions {
+ManualFocusExtension()
+WhiteBalanceExtension()
}
plugins {
+QRScannerPlugin()
}
imageCaptureUseCase = CustomCaptureUseCase()
}Extensions allow you to add custom camera controls without modifying the core library.
class ManualFocusExtension : CameraControlExtension {
override val id = "manual-focus"
private var controller: CameraController? = null
var focusDistance: Float = 0f
set(value) {
field = value
applyFocusDistance(value)
}
override fun onAttach(controller: CameraController) {
this.controller = controller
}
override fun onDetach() {
controller = null
}
override fun onCameraReady() {
// Camera is initialized, safe to access hardware features
}
override fun onCameraReleased() {
// Clean up before camera release
}
private fun applyFocusDistance(distance: Float) {
// Platform-specific implementation
}
}
// Usage
val controller = CameraController {
extensions {
+ManualFocusExtension()
}
}
// Retrieve and use the extension
val focusExt = controller.getExtension<ManualFocusExtension>("manual-focus")
focusExt?.focusDistance = 0.5fReplace the default capture behavior with custom implementations.
class RawCaptureUseCase : ImageCaptureUseCase {
override suspend fun capture(
controller: CameraController,
config: CaptureConfig
): ImageCaptureResult {
// Custom RAW capture implementation
val androidController = controller as AndroidCameraController
// ... capture logic
return ImageCaptureResult.Success(bytes, width, height)
}
}
// Usage
val controller = CameraController {
imageCaptureUseCase = RawCaptureUseCase()
}
// Capture uses your custom implementation
val result = controller.takePicture()For advanced use cases, you can bypass CameraPreview and use the core library directly.
Android:
class CustomPreviewView(context: Context) : SurfaceView(context) {
fun attachToController(controller: CameraController) {
// Get the SurfaceRequest flow
lifecycleScope.launch {
controller.surfaceRequestFlow.collect { request ->
request?.let { surfaceRequest ->
// Provide your surface to CameraX
surfaceRequest.provideSurface(
holder.surface,
executor
) { result -> }
}
}
}
}
}iOS:
// In Kotlin
val session = controller.captureSession
// In Swift
let previewLayer = AVCaptureVideoPreviewLayer(session: controller.captureSession)
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)- All deprecated APIs continue to work and will emit compiler warnings
- Binary compatibility is maintained for existing code
- The deprecation level is
WARNING, notERROR, so your existing code will compile
If you encounter issues during migration, please:
- Check the API documentation
- Review the sample applications
- Open an issue on GitHub