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

如何在Fragment中显示相机实时画面?适配低版本安卓的图文对比需求

在Android Fragment中实现相机实时预览(适配5.0-6.0,无需系统相机APP)

我正好做过类似的相机预览+图片对比的应用,结合你的需求(适配Marshmallow/Lollipop,不支持Nougat分屏),给你梳理下核心方案:

首先明确:你完全不需要调用系统默认相机APP,SurfaceView 或者 TextureView 就是用来直接渲染相机实时画面的核心控件——条码阅读器、快速图片编辑器这类应用,都是基于这两个组件实现相机预览的。


1. 核心方案选择

  • SurfaceView:性能优先,它的渲染逻辑在独立线程运行,不会阻塞UI线程,适合相机这种高帧率实时预览场景,是大多数相机类APP的首选。
  • TextureView:灵活性更高,支持对预览画面做缩放、旋转、裁剪等自定义变换,如果你需要和图库图片做精准叠加对比,这个控件会更合适。

2. 完整实现步骤(以SurfaceView为例)

2.1 权限处理(适配Marshmallow动态权限)

Android 6.0开始相机权限属于危险权限,必须动态申请。在Fragment中先检查权限,未授权则发起申请:

@Override
public void onResume() {
    super.onResume();
    if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) 
        == PackageManager.PERMISSION_GRANTED) {
        initCamera();
    } else {
        requestPermissions(new String[]{Manifest.permission.CAMERA}, 100);
    }
}

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

2.2 Fragment布局(叠加相机预览+图库图片)

布局里同时放SurfaceView(相机预览)和ImageView(图库图片),通过透明度实现半透明叠加对比:

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

    <!-- 相机实时预览 -->
    <SurfaceView
        android:id="@+id/camera_surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 图库图片(半透明叠加) -->
    <ImageView
        android:id="@+id/gallery_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:alpha="0.5"
        android:scaleType="fitCenter" />

</RelativeLayout>

2.3 Fragment核心代码(相机预览逻辑)

public class CameraCompareFragment extends Fragment implements SurfaceHolder.Callback {
    private Camera mCamera;
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private ImageView mGalleryImg;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_camera_compare, container, false);
        mSurfaceView = view.findViewById(R.id.camera_surface);
        mGalleryImg = view.findViewById(R.id.gallery_img);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        // 这里可以添加图库图片选择逻辑(比如点击按钮打开图库)
        return view;
    }

    private void initCamera() {
        try {
            mCamera = Camera.open(); // 默认打开后置摄像头,需要前置则传1
            setupCameraParams();
        } catch (Exception e) {
            Toast.makeText(getContext(), "相机初始化失败", Toast.LENGTH_SHORT).show();
        }
    }

    private void setupCameraParams() {
        Camera.Parameters params = mCamera.getParameters();
        // 设置最优预览尺寸(和SurfaceView尺寸匹配,避免拉伸)
        List<Camera.Size> previewSizes = params.getSupportedPreviewSizes();
        Camera.Size optimalSize = getOptimalPreviewSize(previewSizes, mSurfaceView.getWidth(), mSurfaceView.getHeight());
        params.setPreviewSize(optimalSize.width, optimalSize.height);
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // 自动对焦
        mCamera.setParameters(params);
    }

    // 计算和控件尺寸匹配的最优预览尺寸
    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int targetWidth, int targetHeight) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) targetWidth / targetHeight;
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        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;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mSurfaceHolder.getSurface() == null) return;
        // 画面尺寸变化时重新设置相机参数
        mCamera.stopPreview();
        setupCameraParams();
        try {
            mCamera.setPreviewDisplay(mSurfaceHolder);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 相机资源在onPause中统一释放
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

3. 适配注意事项

  • 禁止Nougat分屏:在Manifest的<activity>标签中添加android:resizeableActivity="false",这样Nougat及以上系统会禁止该应用进入分屏模式。
  • Lollipop适配:Android 5.0不需要动态权限,直接在Manifest声明<uses-permission android:name="android.permission.CAMERA" />即可。
  • 多摄像头支持:如果需要切换前后摄像头,调用Camera.open(0)(后置)或Camera.open(1)(前置)即可,注意切换前要释放旧的相机实例。

内容的提问来源于stack exchange,提问作者Wesos de Queso

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:10:39