Android中SurfaceView二维码阅读器的自动对焦实现求助
解决SurfaceView二维码阅读器的自动对焦问题
嘿,我明白你现在的困扰——用SurfaceView做二维码阅读器,却卡在自动对焦上了对吧?别担心,我来帮你搞定这个问题!
首先咱们得搞清楚核心原因:你用的是Google Vision库的CameraSource,这个类默认并没有开启自动对焦功能,所以需要咱们手动去设置底层Camera的参数。因为CameraSource没有直接暴露Camera实例,咱们得用反射来获取它,然后修改对焦模式。
具体实现步骤:
- 添加自动对焦设置方法
在你的page_qr类里新增一个专门设置自动对焦的方法,通过反射获取Camera实例并调整参数:
private void setAutoFocus(CameraSource cameraSource) { try { // 通过反射获取CameraSource里的私有mCamera字段 Field cameraField = CameraSource.class.getDeclaredField("mCamera"); cameraField.setAccessible(true); Camera camera = (Camera) cameraField.get(cameraSource); if (camera != null) { Camera.Parameters params = camera.getParameters(); // 优先选择连续自动对焦(适合扫码场景) List<String> supportedFocusModes = params.getSupportedFocusModes(); if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } // 设备不支持连续拍照对焦的话,用连续视频对焦 else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } // 以上都不支持的话, fallback到单次自动对焦 else { params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } camera.setParameters(params); } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } }
- 启动相机后调用自动对焦方法
在surfaceCreated方法里,启动cameraSource之后立即调用上面的方法,确保相机启动后马上开启自动对焦:
@Override public void surfaceCreated(SurfaceHolder holder) { try { cameraSource.start(cameraView.getHolder()); // 启动相机后立刻设置自动对焦 setAutoFocus(cameraSource); } catch (IOException ie) { Log.e("CAMERA SOURCE", ie.getMessage()); } }
- 补上相机权限处理(重要)
如果你的App targetSdkVersion >=23(Android 6.0+),必须动态申请相机权限,否则相机无法正常启动。咱们把权限检查和相机初始化拆分开,让代码更清晰:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.page_qr); _C = this; cameraView = (SurfaceView) findViewById(R.id.camera_view); barcodeInfo = (TextView) findViewById(R.id.code_info); // 先检查相机权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 100); } else { // 权限已允许,初始化相机相关逻辑 initCamera(); } } // 相机初始化逻辑抽成单独方法,方便复用 private void initCamera() { barcodeDetector = new BarcodeDetector.Builder(this) .setBarcodeFormats(Barcode.QR_CODE) .build(); cameraSource = new CameraSource .Builder(this, barcodeDetector) .setRequestedPreviewSize(640, 480) .setFacing(CameraSource.CAMERA_FACING_BACK) .setRequestedFps(30.0f) .build(); cameraView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { try { cameraSource.start(cameraView.getHolder()); setAutoFocus(cameraSource); } catch (IOException ie) { Log.e("CAMERA SOURCE", ie.getMessage()); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) { cameraSource.stop(); } }); barcodeDetector.setProcessor(new Detector.Processor<Barcode>() { @Override public void release() {} @Override public void receiveDetections(Detector.Detections<Barcode> detections) { final SparseArray<Barcode> barcodes = detections.getDetectedItems(); if (barcodes.size() != 0) { barcodeInfo.post(() -> barcodeInfo.setText(barcodes.valueAt(0).displayValue)); } } }); } // 权限申请回调处理 @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(this, "需要相机权限才能扫描二维码哦", Toast.LENGTH_SHORT).show(); finish(); } } }
补充说明:
- 你布局里给
SurfaceView设置的focusable="true"和focusableInTouchMode="true"是没问题的,但这和相机自动对焦无关,主要是确保SurfaceView能获取焦点,不影响咱们的对焦设置。 - 反射的方式是因为
CameraSource的mCamera字段是私有的,目前这个方法在大多数设备上都能正常工作,如果后续Google Vision库更新字段名,可能需要微调,但现阶段是最直接的解决方案。
这样修改之后,你的二维码阅读器应该就能自动对焦了,试试看吧!
内容的提问来源于stack exchange,提问作者Naser Ghafari
相关产品推荐
相关产品推荐

