You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio(Java)实现APP内前置摄像头自拍功能需求

Android 应用内实现前置摄像头自拍(无需跳转系统相机)

这个功能的官方叫法是自定义相机预览与拍摄,核心是直接调用系统相机硬件,在应用内的预览控件中显示画面并完成拍摄。以下是基于Java的完整实现步骤:

一、权限申请

首先要配置相机相关权限,Android 6.0及以上需要动态申请:

  1. 在AndroidManifest.xml中添加静态权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.front" android:required="true" />
  1. 动态申请权限的代码:
private static final int REQUEST_CAMERA_PERMISSION = 100;

private void requestCameraPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CAMERA},
                REQUEST_CAMERA_PERMISSION);
    } else {
        initCameraPreview();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initCameraPreview();
        } else {
            Toast.makeText(this, "需要相机权限才能使用自拍功能", Toast.LENGTH_SHORT).show();
        }
    }
}

二、布局添加预览与拍摄控件

使用TextureView实现灵活的相机预览,搭配拍摄按钮:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextureView
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/btn_capture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp"
        android:text="拍照" />
</RelativeLayout>

三、核心相机逻辑实现

完整的Activity代码,包含前置摄像头初始化、预览、拍照及照片处理:

public class SelfieCameraActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
    private Camera camera;
    private TextureView textureView;
    private Button captureBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_selfie_camera);

        textureView = findViewById(R.id.camera_preview);
        captureBtn = findViewById(R.id.btn_capture);

        captureBtn.setOnClickListener(v -> capturePhoto());
        requestCameraPermission();
    }

    private void initCameraPreview() {
        textureView.setSurfaceTextureListener(this);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // 打开前置摄像头
        camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
        try {
            Camera.Parameters parameters = camera.getParameters();
            // 适配预览尺寸,避免变形
            List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size optimalSize = getOptimalPreviewSize(previewSizes, width, height);
            parameters.setPreviewSize(optimalSize.width, optimalSize.height);
            camera.setParameters(parameters);

            // 绑定预览到TextureView
            camera.setPreviewTexture(surface);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
            releaseCamera();
        }
    }

    // 计算适配控件的最佳预览尺寸
    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;
        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    private void capturePhoto() {
        if (camera != null) {
            camera.takePicture(null, null, (data, camera) -> {
                // 解析照片数据
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                // 前置摄像头拍摄的照片是镜像,翻转后恢复正常视角
                bitmap = flipBitmapHorizontally(bitmap);

                // 这里可添加保存照片、设置为头像的逻辑
                // saveBitmapToLocal(bitmap);
                // updateUserAvatar(bitmap);

                // 重启预览,支持再次拍摄
                camera.startPreview();
            });
        }
    }

    // 水平翻转Bitmap
    private Bitmap flipBitmapHorizontally(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.setScale(-1, 1);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        releaseCamera();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {}

    // 释放相机资源
    private void releaseCamera() {
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseCamera();
    }
}

四、额外注意事项

  • 上述代码基于旧版CameraAPI,若适配Android 5.0+(API 21+),推荐使用功能更完善的camera2API,但其代码复杂度更高。
  • 可在清单文件中锁定该Activity为竖屏,避免旋转导致预览变形:
<activity android:name=".SelfieCameraActivity"
    android:screenOrientation="portrait" />

内容的提问来源于stack exchange,提问作者Rocky Malobago

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:15:31