实现缩放功能:增加缩放功能检索和设置方法,更新UI以支持缩放调整,增强缩放比例的状态管理。

This commit is contained in:
2026-06-12 16:38:31 +08:00
parent cf1c2d7d0e
commit a3a02e623f
11 changed files with 573 additions and 18 deletions

View File

@@ -2,6 +2,7 @@ package com.dronex.rec.recording
import android.content.Context
import android.util.Log
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
@@ -24,8 +25,10 @@ class RecordingCameraController(
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
private var videoCapture: VideoCapture<Recorder>? = null
private var camera: Camera? = null
private var activeRecording: Recording? = null
private var boundLifecycleOwner: LifecycleOwner? = null
private var currentZoomRatio: Float = 1f
var status: RecordingStatus = RecordingStatus(RecordingState.IDLE)
private set
@@ -61,12 +64,14 @@ class RecordingCameraController(
videoCapture = VideoCapture.withOutput(recorder)
provider.unbindAll()
provider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
videoCapture,
)
camera =
provider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
videoCapture,
)
applyCurrentZoom()
updateStatus(RecordingStatus(RecordingState.PREVIEWING))
onReady(true)
@@ -108,12 +113,14 @@ class RecordingCameraController(
try {
boundLifecycleOwner = lifecycleOwner
provider.unbindAll()
provider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
videoCapture,
)
camera =
provider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
videoCapture,
)
applyCurrentZoom()
onReady(true)
} catch (error: Exception) {
Log.e(TAG, "rebindForRecording failed", error)
@@ -221,6 +228,52 @@ class RecordingCameraController(
activeRecording = null
}
fun zoomCapabilitiesMap(): Map<String, Any> {
val zoomState = camera?.cameraInfo?.zoomState?.value
val minZoom = zoomState?.minZoomRatio ?: 1f
val maxZoom = zoomState?.maxZoomRatio ?: 3f
val zoom = (zoomState?.zoomRatio ?: currentZoomRatio).coerceIn(minZoom, maxZoom)
currentZoomRatio = zoom
return mapOf(
"zoomRatio" to zoom.toDouble(),
"minZoomRatio" to minZoom.toDouble(),
"maxZoomRatio" to maxZoom.toDouble(),
)
}
fun setZoomRatio(
ratio: Double,
onComplete: (Boolean, Map<String, Any>, String?) -> Unit,
) {
val boundCamera = camera
if (boundCamera == null) {
val clamped = ratio.toFloat().coerceAtLeast(1f)
currentZoomRatio = clamped
onComplete(true, zoomCapabilitiesMap(), null)
return
}
val zoomState = boundCamera.cameraInfo.zoomState.value
val minZoom = zoomState?.minZoomRatio ?: 1f
val maxZoom = zoomState?.maxZoomRatio ?: clampedMaxZoom()
val nextZoom = ratio.toFloat().coerceIn(minZoom, maxZoom)
currentZoomRatio = nextZoom
val future = boundCamera.cameraControl.setZoomRatio(nextZoom)
future.addListener(
{
try {
future.get()
onComplete(true, zoomCapabilitiesMap(), null)
} catch (error: Exception) {
Log.e(TAG, "setZoomRatio failed", error)
onComplete(false, zoomCapabilitiesMap(), error.message)
}
},
mainExecutor,
)
}
fun unbind() {
activeRecording?.stop()
activeRecording = null
@@ -228,7 +281,9 @@ class RecordingCameraController(
cameraProvider = null
preview = null
videoCapture = null
camera = null
boundLifecycleOwner = null
currentZoomRatio = 1f
updateStatus(RecordingStatus(RecordingState.IDLE))
}
@@ -242,6 +297,19 @@ class RecordingCameraController(
statusListener?.invoke(next)
}
private fun applyCurrentZoom() {
val boundCamera = camera ?: return
val zoomState = boundCamera.cameraInfo.zoomState.value
val minZoom = zoomState?.minZoomRatio ?: 1f
val maxZoom = zoomState?.maxZoomRatio ?: clampedMaxZoom()
currentZoomRatio = currentZoomRatio.coerceIn(minZoom, maxZoom)
boundCamera.cameraControl.setZoomRatio(currentZoomRatio)
}
private fun clampedMaxZoom(): Float {
return camera?.cameraInfo?.zoomState?.value?.maxZoomRatio ?: 3f
}
companion object {
private const val TAG = "RecordingCamera"
}

View File

@@ -50,6 +50,11 @@ class RecordingPlatformHandler(
startRecording(withAudio, enableDnd, displayName, result)
}
"stopRecording" -> stopRecording(result)
"getZoomCapabilities" -> result.success(controller.zoomCapabilitiesMap())
"setZoomRatio" -> {
val ratio = call.argument<Double>("zoomRatio") ?: 1.0
setZoomRatio(ratio, result)
}
"disposePreview" -> {
controller.unbind()
result.success(null)
@@ -172,6 +177,18 @@ class RecordingPlatformHandler(
}
}
private fun setZoomRatio(ratio: Double, result: MethodChannel.Result) {
controller.setZoomRatio(ratio) { success, capabilities, message ->
mainHandler.post {
if (success) {
result.success(capabilities)
} else {
result.error("ZOOM_FAILED", message ?: "Failed to set camera zoom", null)
}
}
}
}
private fun deliverStopResult(result: MethodChannel.Result, path: String?) {
val gallerySaved = path != null && controller.status.state != RecordingState.ERROR
val payload =