Android CameraXでプレビューを表示する
はじめに
先日のGoogle I/Oにて発表されたCameraXを試してみました。
本稿では、プレビュー表示までを行います。
Dependencies
// projectRoot/build.gradle allprojects { repositories { google() jcenter() } } // app/build.gradle dependencies { def camerax_version = "1.0.0-alpha01" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" }
Implementation
パーミッションまわりは、PermissionsDispatcher にお任せしています。
いつもお世話になっております(感謝)
@RuntimePermissions class CameraPreviewFragment : Fragment() { private lateinit var finder: TextureView override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_camera_preview, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) finder = view.findViewById(R.id.preview) // View描画後にカメラを開始 finder.post { startCameraWithPermissionCheck() } } override fun onDestroyView() { super.onDestroyView() CameraX.unbindAll() } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { onRequestPermissionsResult(requestCode, grantResults) } @NeedsPermission(Manifest.permission.CAMERA) fun startCamera() { CameraX.unbindAll() val preview = AutoFitPreviewBuilder.build(PreviewConfig.Builder().build(), finder) // 作成したUseCaseをバインド CameraX.bindToLifecycle(this, preview) } @OnPermissionDenied(Manifest.permission.CAMERA) fun close() { findNavController().popBackStack() } }
Preview
CameraXでは、各機能をUseCaseで管理しています。
提供されているUseCaseは以下です。
プレビューの表示を行いたいので、Previewを利用します。
TextureView
TextureViewをカメラ解像度のアスペクト比に合わせる必要がありますが、大体同じような処理になってしまうので、今回は公式サンプルのUtilを活用します。
色々とやってくれていますが、目的の処理はこちらです。
一部改変しています。
private fun updateTransform( textureView: TextureView?, rotation: Int?, newBufferDimens: Size, newViewFinderDimens: Size ) { // ~~ val matrix = Matrix() val centerX = viewFinderDimens.width / 2f val centerY = viewFinderDimens.height / 2f matrix.postRotate(-viewFinderRotation!!.toFloat(), centerX, centerY) val bufferRatio = bufferDimens.width / bufferDimens.height.toFloat() if (viewFinderDimens.width > viewFinderDimens.height) { val scaledHeight = Math.round(viewFinderDimens.width * bufferRatio) val yScale = scaledHeight / viewFinderDimens.height.toFloat() matrix.preScale(1f, yScale, centerX, centerY) } else { val scaledWidth = Math.round(viewFinderDimens.height / bufferRatio) val xScale = scaledWidth / viewFinderDimens.width.toFloat() matrix.preScale(xScale, 1f, centerX, centerY) } tv.setTransform(matrix) }
Viewに合わせて、回転・拡縮を行います。
※回転は今までセンサー・画面向きを考慮していましたが、ライブラリ内部のCameraOrientationUtil
にて対応してくれています。
単純に回転している分、マイナスで戻すだけになっています。
おわりに
TextureViewの設定(Camera2でもやっていたこと)以外、特筆すべき点もなく簡単にプレビュー表示できました!
Camera2でプレビューを表示するまでを考えると、とても簡単になったと感じます。
今までのカメラ機能は、「お作法」的な部分に時間を取られていましたが
今後は要件・仕様に合わせてカスタマイズすることに集中できそうです。
AutoFitPreviewBuilder
はリファクタリングしたいと思います。