首页 > 解决方案 > 在android中使用相机

问题描述

我正在尝试构建一个简单地使用相机拍照而不启动默认相机应用程序的 Android 应用程序。换句话说,我想制作一个自定义相机应用程序。我可以使用 Camera 硬件对象类来做到这一点,但是这已被弃用,我想使用 camerax 的一些新功能,而不必担心代码在一段时间后无法工作。我还阅读了相机 API 文档,但仍不清楚如何使用相机。是否有任何非常简单的分步教程或指南可以帮助我?谢谢,

标签: javaandroidmobile

解决方案


您可以查看我的示例,了解如何使用 AndroidX 库和 TextureView 进行相机自定义。

https://github.com/icerrate/Custom-Camera-App

首先,定义你的布局。这是我的activity_main.xml文件:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextureView
        android:id="@+id/view_finder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/take_photo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_margin="@dimen/horizontal_margin"
        app:layout_constraintStart_toStartOf="parent"
        android:src="@drawable/ic_camera"/>

</androidx.constraintlayout.widget.ConstraintLayout>

请记住,TextureView将接收相机预览,并且浮动操作按钮用作“拍照”按钮。

然后添加您的MainActivity.java文件:

public class MainActivity extends AppCompatActivity implements LifecycleOwner {

    private static final int RC_PERMISSIONS = 100;

    private TextureView viewFinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        viewFinder = findViewById(R.id.view_finder);
        FloatingActionButton takePhotoFab = findViewById(R.id.take_photo);

        //Check permissions
        if (allPermissionGranted()) {
            viewFinder.post(new Runnable() {
                @Override
                public void run() {
                    startCamera();
                }
            });
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[] {Manifest.permission.CAMERA}, RC_PERMISSIONS);
        }

        takePhotoFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePhoto();
            }
        });
    }

    private void startCamera() {
        Point screenSize = getScreenSize();
        int width = screenSize.x;
        int height = screenSize.y;

        //Get real aspect ratio
        DisplayMetrics displayMetrics = new DisplayMetrics();
        Display display = getWindowManager().getDefaultDisplay();
        display.getRealMetrics(displayMetrics);
        Rational rational = new Rational(displayMetrics.widthPixels, displayMetrics.heightPixels);

        //Build the camera preview
        PreviewConfig build = new PreviewConfig.Builder()
                .setTargetAspectRatio(rational)
                .setTargetResolution(new Size(width,height))
                .build();
        Preview preview = new Preview(build);

        preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
            @Override
            public void onUpdated(Preview.PreviewOutput output) {
                ViewGroup group = (ViewGroup) viewFinder.getParent();
                group.removeView(viewFinder);
                group.addView(viewFinder, 0);

                viewFinder.setSurfaceTexture(output.getSurfaceTexture());
            }
        });

        CameraX.bindToLifecycle(this, preview);
    }

    private void takePhoto() {
        Toast.makeText(this, "Shot!",
                Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == RC_PERMISSIONS) {
            if (allPermissionGranted()) {
                viewFinder.post(new Runnable() {
                    @Override
                    public void run() {
                        startCamera();
                    }
                });
            } else {
                Toast.makeText(this, "Permission not granted",
                        Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    private boolean allPermissionGranted() {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
    }

    private Point getScreenSize() {
        Display display = getWindowManager(). getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        return size;
    }
}

在此类中,您将能够在PreviewConfig.Builder()的帮助下将相机预览发送到TextureView并使用CameraX.bindToLifeCycle()将其绑定到 Activity lifeCycle

另外,不要忘记将相机权限添加到清单并考虑运行时权限。

屏幕截图: 自定义相机预览

希望这对你有帮助!


推荐阅读