前言
這篇文章只是介紹CameraX的簡單使用,其中包含相機預(yù)覽声怔、拍照剂买、和簡單的圖片偵分析。
參考自官方文檔:https://developer.android.google.cn/training/camerax?hl=zh_CN
本文章Demo代碼:https://github.com/L-X-J/JetpackSample/tree/master/cx
概覽(摘自官方文檔)
CameraX 是一個 Jetpack 支持庫俏拱,旨在幫助您簡化相機應(yīng)用的開發(fā)工作。它提供一致且易于使用的 API 界面吼句,適用于大多數(shù) Android 設(shè)備锅必,并可向后兼容至 Android 5.0(API 級別 21)。
雖然它利用的是 camera2 的功能惕艳,但使用的是更為簡單且基于用例的方法搞隐,該方法具有生命周期感知能力。它還解決了設(shè)備兼容性問題远搪,因此您無需在代碼庫中包含設(shè)備專屬代碼劣纲。這些功能減少了將相機功能添加到應(yīng)用時需要編寫的代碼量。
最后谁鳍,借助 CameraX癞季,開發(fā)者只需兩行代碼就能利用與預(yù)安裝的相機應(yīng)用相同的相機體驗和功能。 CameraX Extensions 是可選插件倘潜,通過該插件绷柒,您可以在支持的設(shè)備上向自己的應(yīng)用中添加人像、HDR涮因、夜間模式和美顏等效果废睦。
引入依賴
implementation 'androidx.camera:camera-core:1.0.0-alpha06'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha06'
實現(xiàn)攝像頭預(yù)覽
畫布局
xml
布局文件新增一個TextureView
且取個id
<TextureView
android:id="@+id/view_finder"
...
android:layout_width="380dp"
android:layout_height="380dp"/>
邏輯代碼實現(xiàn)
在activity中新增兩個方法。
private fun startCamera(){}
private fun updateTransform(){}
因為要實現(xiàn)攝像頭預(yù)覽我們需要動態(tài)獲取權(quán)限(Manifest.permission.CAMERA
)养泡。
獲取到權(quán)限后們需要調(diào)用startCamera()
函數(shù)嗜湃。如下代碼
class MainActivity : AppCompatActivity() ,LifecycleOwner {
private lateinit var viewFinder : TextureView
private val executor = Executors.newSingleThreadExecutor()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewFinder = findViewById(R.id.view_finder)
//自定義函數(shù)檢查權(quán)限是否擁有
if (checkAllPermissionsGranted()){
viewFinder.post { startCamera() }
}else{
//如果沒有權(quán)限動態(tài)獲取
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
viewFinder.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
updateTransform()
}
}
}
最后我們實現(xiàn)startCamera()
、updateTransform()
函數(shù)澜掩。
private fun startCamera(){
// 為取景器用例創(chuàng)建配置對象
val previewConfig = PreviewConfig.Builder().apply {
setTargetResolution(Size(viewFinder.width,viewFinder.height))
}.build()
// 構(gòu)建取景器用例
val preview = Preview(previewConfig);
// 每次取景器更新時购披,重新計算布局
preview.setOnPreviewOutputUpdateListener {
// 要更新SurfaceTexture,我們必須將其刪除并重新添加
val parent = viewFinder.parent as ViewGroup
parent.removeView(viewFinder)
parent.addView(viewFinder, 0)
viewFinder.surfaceTexture = it.surfaceTexture
updateTransform()
}
//將用例綁定到生命周期
CameraX.bindToLifecycle(this, preview)
}
private fun updateTransform() {
val matrix = Matrix()
//計算取景器的中心
val centerX = viewFinder.width / 2f
val centerY = viewFinder.height / 2f
// 糾正預(yù)覽輸出以適應(yīng)顯示旋轉(zhuǎn)
val rotationDegrees = when(viewFinder.display.rotation) {
Surface.ROTATION_0 -> 0
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> return
}
matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
// 最后肩榕,將轉(zhuǎn)換應(yīng)用于我們的TextureView
viewFinder.setTransform(matrix)
}
這樣我們就實現(xiàn)了攝像頭預(yù)覽刚陡,是不是比之前簡單很多。
拍照
實現(xiàn)拍照功能,我們需要改造一下startCamera()
函數(shù)橘荠,同樣還是很少的代碼。
private fun startCamera(){
...
//在 CameraX.bindToLifecycle(this, preview)前添加以下代碼
// 為圖像捕獲用例創(chuàng)建配置對象
val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
// 我們沒有為圖像捕獲設(shè)置分辨率郎逃;相反哥童,我們
//選擇一個可以推斷出合適的捕獲模式
// 基于寬高比和請求模式的分辨率
setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
}.build()
// 構(gòu)建圖像捕獲用例并附加按鈕單擊偵聽器
val imageCapture = ImageCapture(imageCaptureConfig)
//拍照按鈕
findViewById<ImageButton>(R.id.capture_button).setOnClickListener {
val file = File(externalMediaDirs.first(),"${System.currentTimeMillis()}.jpg")
imageCapture.takePicture(file,executor,object : ImageCapture.OnImageSavedListener{
override fun onImageSaved(file: File) {
val msg = "成功: ${file.absolutePath}"
Log.d("CameraXApp", msg)
viewFinder.post {
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
}
}
override fun onError(
imageCaptureError: ImageCapture.ImageCaptureError,
message: String,
cause: Throwable?
) {
val msg = "失敗: $message"
Log.e("CameraXApp", msg, cause)
viewFinder.post {
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
}
}
})
}
最后綁定一下生命周期
// CameraX.bindToLifecycle(this, preview)//只是預(yù)覽
CameraX.bindToLifecycle(this, preview,imageCapture)//可以預(yù)覽可以拍照
}