🦁
【Camera2】画面全幅カスタムカメラアプリの実装
CameraActivity - Android Camera2 API 実装
概要
本ファイルは、Camera2 API・SurfaceView を用いた Android カメラ画面の実装例です。
以下の要件を満たしています:
- プレビューを16:9のアスペクト比で表示(縦幅に合わせ、横ははみ出し)
- 撮影ボタンを画面下に配置
- 白い横長の枠線(クレジットカード比率)をオーバーレイで表示
- 正方形ボタンを画面上部に配置
CameraActivity.kt
package com.example.cameraapp
import android.app.Activity
import android.hardware.camera2.*
import android.os.Bundle
import android.util.Size
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class CameraActivity : AppCompatActivity() {
private lateinit var surfaceView: SurfaceView
private lateinit var cameraManager: CameraManager
private var cameraDevice: CameraDevice? = null
private var previewSession: CameraCaptureSession? = null
private lateinit var captureRequestBuilder: CaptureRequest.Builder
private lateinit var previewSize: Size
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
surfaceView = findViewById(R.id.surfaceView)
cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
openCamera()
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraDevice?.close()
}
})
}
private fun openCamera() {
val cameraId = cameraManager.cameraIdList.first()
val stateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraDevice = camera
startPreview()
}
override fun onDisconnected(camera: CameraDevice) {
camera.close()
}
override fun onError(camera: CameraDevice, error: Int) {
camera.close()
}
}
cameraManager.openCamera(cameraId, stateCallback, null)
}
private fun startPreview() {
val surface = surfaceView.holder.surface
cameraDevice?.let { camera ->
captureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder.addTarget(surface)
camera.createCaptureSession(listOf(surface), object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
previewSession = session
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
session.setRepeatingRequest(captureRequestBuilder.build(), null, null)
}
override fun onConfigureFailed(session: CameraCaptureSession) {}
}, null)
}
}
}
res/layout/activity_camera.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
<View
android:id="@+id/cardOverlay"
android:layout_width="300dp"
android:layout_height="189dp"
android:layout_gravity="center"
android:background="@drawable/overlay_border" />
<Button
android:id="@+id/shutterButton"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="32dp"
android:background="@drawable/shutter_button_background" />
<Button
android:id="@+id/topButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="top|end"
android:layout_margin="16dp"
android:text="≡" />
</FrameLayout>
res/drawable/overlay_border.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<stroke
android:width="2dp"
android:color="@android:color/white" />
</shape>
res/drawable/shutter_button_background.xml
<item>
<shape android:shape="oval">
<solid android:color="#FFFFFF" />
<stroke
android:width="3dp"
android:color="#CCCCCC" />
</shape>
</item>
備考
- SurfaceView のアスペクト比調整には LayoutParams または ConstraintLayout が有効です。
- 撮影処理や保存処理は CameraCaptureSession に追加してください。
Discussion