一、camerax的使用
引入依赖
// CameraX core library
def camerax_version = '1.1.0-alpha11'
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-video:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha30"
// CameraX Extensions library
implementation 'androidx.camera:camera-extensions:1.0.0-alpha27'
2、布局中添加
<androidx.camera.view.PreviewView
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="20dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintDimensionRatio="w,1:1"
android:background="@drawable/shape_preview"/>
3、初始化相机
private val cameraExecutor by lazy {
Executors.newSingleThreadExecutor()
}
private var imageCapture: ImageCapture? = null
private var isBack = true
private var isShoting = false
private var mCamera: Camera? = null
private var outFile: File? = null
private var compressFile: File? = null
@SuppressLint("RestrictedApi")
@NeedsPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.CAMERA
)
fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val width = min(ScreenUtils.getWidth(this),
ScreenUtils.getHeight(this))
val preview = Preview.Builder()
.setMaxResolution(Size(width, width))
.build()
.also {
it.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
}
imageCapture = ImageCapture.Builder()
.build()
// Select back camera as a default
val cameraSelector = if (isBack) {
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
} else {
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT).build()
}
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
mCamera = cameraProvider.bindToLifecycle(
this, cameraSelector, imageCapture, preview
)
} catch (exc: Exception) {
Timber.d("userCase绑定失败---->${exc}")
}
}, ContextCompat.getMainExecutor(this))
}
4、完成拍照
@NeedsPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.CAMERA
)
fun takePhoto() {
binding.pbProgress.isVisible = true
// Get a stable reference of the modifiable image capture use case
imageCapture?.let { imageCapture ->
val tFile = File(getCacheFilePath(this), "t")
if (!tFile.exists()) {
tFile.mkdirs()
}
val metadata = ImageCapture.Metadata().apply {
isReversedHorizontal = !isBack
}
outFile = File(tFile.absolutePath, "${System.currentTimeMillis()}.jpg")
val outputOptions = ImageCapture.OutputFileOptions
.Builder(outFile!!)
.setMetadata(metadata)
.build()
// 设置拍照回调
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Timber.d("拍照失败---->: ${exc.message}", exc)
binding.pbProgress.isVisible = false
isShoting = false
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val msg = "后置摄像头------>${isBack},拍照成功:保存路径----> ${output.savedUri}"
Timber.d(msg)
val path = output.savedUri?.path ?: ""
val image = getImage(path)
val temp = File(tFile, "${System.currentTimeMillis()}.jpg")
if (image != null) {
saveBitmap(image, temp.absolutePath)
}
}
}
)
}
}
二、preview设置圆角
上面是如何拍照,但我的设计稿上需要我将preview设置为圆角,方法如下:
/**
* 设置相机预览preview为圆角
* @param radius Float
*/
private fun setCameraPreviewRadius(radius: Float) {
//设置camerax的preview为圆角
val outline = Outline().also {
it.setRoundRect(
Rect(0, 0, binding.cameraPreview.width, binding.cameraPreview.height),
radius * resources.displayMetrics.density
)
}
val outlineProvider = binding.cameraPreview.outlineProvider
outlineProvider.getOutline(binding.cameraPreview, outline)
binding.cameraPreview.outlineProvider = outlineProvider
binding.cameraPreview.clipToOutline = true
}