簡體   English   中英

如何在 CameraX 上使用搜索欄實現“縮放”?

[英]How to implement "zoom" with seekbar on CameraX?

我是 Android 應用程序開發的新手。 我閱讀了https://github.com/Pinkal7600/camera-samples/blob/master/CameraXBasic/app/src/main/java/com/android/example/cameraxbasic/fragments/CameraFragment.kt以更好地理解如何編寫縮放功能。

但是,我的程序不起作用。 我正在考慮它是否與我更改的值有關,這意味着我需要返回 setLinearZoom。 感謝您的閱讀!

以下是我的代碼:


import android.Manifest
import android.content.ContentValues
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.SeekBar
import android.widget.Toast
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.mycamerax.databinding.ActivityMainBinding
import com.google.common.util.concurrent.ListenableFuture
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

typealias LumaListener = (luma: Double) -> Unit //typealias: nick name some datatypes
//(Double)-> Unit means input double and output nothing

class MainActivity : AppCompatActivity() {

    //viewBinding can help with the multi-widgets
    private lateinit var viewBinding: ActivityMainBinding
    private var imageCapture: ImageCapture? = null

    private var videCpature: VideoCapture<Recorder>? = null
    private var recording: Recording? = null

    private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
//  no need!  private var preview: Preview? = null //預覽物件
//    private var cameraProvider: ProcessCameraProvider? = null//相機資訊
//    private var camera: Camera? = null//相機物件

    private lateinit var cameraExecutor: ExecutorService


    companion object { // same thing as static object
        private const val TAG = "CameraXAPP"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10 // here is the definition
        private val REQUIRED_PERMISSIONS =
            mutableListOf(
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO
            ).apply {
                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P){
                    add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                }
            }.toTypedArray()
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)

        cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        //Request camera permissions
        if(allPermissionsGranted()){
            startCamera()
        }else{
            ActivityCompat.requestPermissions(
                this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
            )
        }

        //set up the listeners for take photo and video capture buttons
        viewBinding.imageCaptureButton.setOnClickListener { takePhoto() }
        viewBinding.videoCaptureButton.setOnClickListener { captureVideo() }


        //use single thread to execute my program
        cameraExecutor = Executors.newSingleThreadExecutor()
    }


    private fun takePhoto() {
        //Get a stable reference of the modifiable image capture use case
        val imageCapture = imageCapture?:return// if the camera hasn't been set up, it will be null. return 0, finish the program.

        //create time stamped name and MediaStore entry.
        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
                    .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)//use MediaStore to store ImageCapture
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P){
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
            }
        }

        //Create output options object which contains file + metadata
        //we want to save in MediaStore so that other apps can display
        val outputOptions = ImageCapture.OutputFileOptions.Builder(
            contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues
        ).build()

        //Set up image capture listener, which is triggered after photo has been taken
        imageCapture.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this),
            object: ImageCapture.OnImageSavedCallback{
                //if capture or save failed
                override fun onError(exc: ImageCaptureException){
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }
                //succeeded
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
//                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo capture succeeded: ${output.savedUri}"
                    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                    Log.d(TAG, msg)
                }
            }
        )

    }

    private fun updateCameraUi(){
        val cameraSelector = cameraSelector
        val preview = Preview.Builder().build().also{
            it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
        }
        val cameraProvider = cameraProviderFuture.get()
        val camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
        val cameraControl = camera.cameraControl
        val cameraInfo = camera.cameraInfo
        val currentZoomRatio = cameraInfo.zoomState.value?.zoomRatio

        viewBinding.zoomSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(
                seekBar: SeekBar?,
                progress: Int,
                fromUser: Boolean
            ) {
                cameraControl.setLinearZoom(progress / 100.toFloat())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })
    }


    private fun startCamera() {
        //create the instance for binding the lifecycle of camera to the lifecycle owner
//        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        //returns the Executor for two arguments
        cameraProviderFuture.addListener({

            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()//bind the lifecycle of our camera to the Lifecycle owner

            //Preview
            //initialize our Preview
            val preview = Preview.Builder().build().also{
                it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
            }

            //image capture
            imageCapture = ImageCapture.Builder().build()

            //Create a camera selector and select back camera
            val cameraSelector = cameraSelector
            updateCameraUi()

            try{
                cameraProvider.unbindAll()//unbind use cases before rebuilding
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
            }catch(exc: Exception){
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))

    }


    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(
            baseContext, it) == PackageManager.PERMISSION_GRANTED
    }


    //    Check if the request code is correct; ignore it otherwise.
    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {//If the permissions are granted,
                startCamera()
            } else {//If permissions are not granted, present a toast to notify the user that the permissions were not granted.
                Toast.makeText(this,
                    "Permissions not granted by the user.",
                    Toast.LENGTH_SHORT).show()
                finish()
            }
        }
    }

    private fun captureVideo() {}


    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
    }

}

這是 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.camera.view.PreviewView
        android:id="@+id/viewFinder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteX="-56dp"
        tools:layout_editor_absoluteY="-36dp" />

    <Button
        android:id="@+id/image_capture_button"
        android:layout_width="110dp"
        android:layout_height="110dp"
        android:layout_marginBottom="50dp"
        android:layout_marginEnd="50dp"
        android:elevation="2dp"
        android:text="@string/take_photo"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintEnd_toStartOf="@id/vertical_centerline" />

    <Button
        android:id="@+id/video_capture_button"
        android:layout_width="110dp"
        android:layout_height="110dp"
        android:layout_marginBottom="50dp"
        android:layout_marginStart="50dp"
        android:elevation="2dp"
        android:text="@string/start_capture"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/vertical_centerline" />

    <SeekBar
        android:id="@+id/zoom_Seek_Bar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:thumb="@drawable/ic_action_name"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/vertical_centerline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent=".50" />

</androidx.constraintlayout.widget.ConstraintLayout>

我試過運行你的程序,它在我這邊有效! 我使用了 CameraX 版本1.1.0-rc02並在 Pixel 4a 上進行了測試。

嘗試將 CameraX 更新到較新的版本,如果問題仍然存在,這可能表明您的設備存在兼容性問題,您應該將其報告給CameraX 的問題跟蹤器

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM