Android如何写一个拍照页面
引言
在Android中,拍照功能被广泛应用于各种应用程序中,如社交媒体、相机应用、扫描应用等。本文将介绍如何在Android应用程序中编写一个功能完善的拍照页面。
准备工作
在开始编写代码之前,我们需要确保项目中已经添加了相机权限。在AndroidManifest.xml文件中添加以下权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
同时,还需要在build.gradle文件中添加以下依赖:
implementation 'androidx.camera:camera-core:1.0.0'
implementation 'androidx.camera:camera-camera2:1.0.0'
implementation 'androidx.camera:camera-lifecycle:1.0.0'
implementation 'androidx.camera:camera-view:1.0.0'
创建拍照页面布局
首先,我们需要创建一个拍照页面的布局文件。在res/layout目录下创建一个名为activity_camera.xml
的文件,并添加以下代码:
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/captureButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="拍照" />
在这个布局中,我们使用了PreviewView
来显示相机预览界面,并添加了一个Button
来触发拍照操作。
初始化相机
接下来,我们需要在拍照页面的Activity中初始化相机。在Activity的onCreate
方法中添加以下代码:
private lateinit var cameraProvider: ProcessCameraProvider
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
// 获取相机Provider
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
cameraProvider = cameraProviderFuture.get()
bindCameraUseCases()
}, ContextCompat.getMainExecutor(this))
}
在这段代码中,我们使用ProcessCameraProvider.getInstance(this)
来获取相机Provider,并在监听器中异步获取的到的相机Provider对象。
配置相机用例
在初始化相机后,我们需要配置相机用例,以便进行预览和拍照操作。添加以下代码:
private fun bindCameraUseCases() {
val viewFinder = findViewById<PreviewView>(R.id.viewFinder)
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(viewFinder.surfaceProvider)
}
val imageCapture = ImageCapture.Builder().build()
findViewById<Button>(R.id.captureButton).setOnClickListener {
val file = File(externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
val outputOptions = ImageCapture.OutputFileOptions.Builder(file).build()
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
val savedUri = Uri.fromFile(file)
val msg = "图片已保存至: $savedUri"
Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
}
override fun onError(exception: ImageCaptureException) {
val msg = "拍照失败: ${exception.message}"
Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
}
}
)
}
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture)
}
在这段代码中,我们首先通过findViewById获取到PreviewView对象,并创建了一个Preview用例,并将其与PreviewView关联起来。
然后,我们创建了一个ImageCapture用例,并在拍照按钮的点击事件中调用了takePicture
方法来触发拍照操作。在拍照完成后,我们可以通过onImageSaved
回调中的outputFileResults
参数获取到保存的图片文件,并显示一个Toast提示用户图片保存的路径。
最后,我们使用cameraProvider.unbindAll()
来解绑之前绑定的用例,并通过cameraProvider.bindToLifecycle
将Preview、ImageCapture用例与相机生命周期绑定。
请求相机权限
为了保证应用程序能够正常访问相机,我们还需要在Activity中请求相机