如何在移动视觉条码扫描仪顶部绘制叠加层?

问题描述 投票:0回答:1

我一直在努力完成这项工作,但最近几天没有成功。我正在尝试在 Mobile Vison 条形码扫描仪顶部添加一个方形框覆盖层(如果它也可以包含 2 个按钮,那就太好了)。我尝试了不同的方法和解决方案,但没有成功。

最终结果应该类似于:

谢谢你!

更新

我的xml文件是:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:orientation="vertical">


<ui.camera.CameraSourcePreview
    android:id="@+id/preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ui.camera.GraphicOverlay
        android:id="@+id/graphicOverlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</ui.camera.CameraSourcePreview>

</LinearLayout>

Java类是:

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.CommonStatusCodes;

import data.model.Post;
import data.model.PostResponse;
import data.remote.APIService;
import data.remote.ApiUtils;
import ui.camera.CameraSource;
import ui.camera.CameraSourcePreview;

import ui.camera.GraphicOverlay;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import com.google.android.gms.vision.MultiProcessor;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;

import java.io.IOException;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public final class BarcodeCaptureActivity extends AppCompatActivity                 
implements BarcodeGraphicTracker.BarcodeUpdateListener {
private static final String TAG = "Barcode-reader";

private static final int RC_HANDLE_GMS = 9001;

private static final int RC_HANDLE_CAMERA_PERM = 2;

public static final String AutoFocus = "AutoFocus";
public static final String UseFlash = "UseFlash";
public static final String BarcodeObject = "Barcode";

private CameraSource mCameraSource;
private CameraSourcePreview mPreview;
private GraphicOverlay<BarcodeGraphic> mGraphicOverlay;

private ScaleGestureDetector scaleGestureDetector;
private GestureDetector gestureDetector;

private APIService mAPIService;

private Boolean codeSent;

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.barcode_capture);

    codeSent = false;

    mPreview = (CameraSourcePreview) findViewById(R.id.preview);
    mGraphicOverlay = (GraphicOverlay<BarcodeGraphic>) findViewById(R.id.graphicOverlay);

    boolean autoFocus = getIntent().getBooleanExtra(AutoFocus, false);
    boolean useFlash = getIntent().getBooleanExtra(UseFlash, false);

    int rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
    if (rc == PackageManager.PERMISSION_GRANTED) {
        createCameraSource(autoFocus, useFlash);
    } else {
        requestCameraPermission();
    }

    gestureDetector = new GestureDetector(this, new CaptureGestureListener());
    scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());

    Snackbar.make(mGraphicOverlay, R.string.camera_info,
            Snackbar.LENGTH_LONG)
            .show();

    mAPIService = ApiUtils.getAPIService(((BaseApplication) this.getApplication()).getBaseUrl());
}

private void requestCameraPermission() {
    Log.w(TAG, "Camera permission is not granted. Requesting permission");

    final String[] permissions = new String[]{Manifest.permission.CAMERA};

    if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.CAMERA)) {
        ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
        return;
    }

    final Activity thisActivity = this;

    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            ActivityCompat.requestPermissions(thisActivity, permissions,
                    RC_HANDLE_CAMERA_PERM);
        }
    };

    findViewById(R.id.topLayout).setOnClickListener(listener);
    Snackbar.make(mGraphicOverlay, R.string.permission_camera_rationale,
            Snackbar.LENGTH_INDEFINITE)
            .setAction(R.string.ok, listener)
            .show();
}

@Override
public boolean onTouchEvent(MotionEvent e) {
    boolean b = scaleGestureDetector.onTouchEvent(e);

    boolean c = gestureDetector.onTouchEvent(e);

    return b || c || super.onTouchEvent(e);
}

@SuppressLint("InlinedApi")
private void createCameraSource(boolean autoFocus, boolean useFlash) {
    Context context = getApplicationContext();

    BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
    BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay, this);
    barcodeDetector.setProcessor(
            new MultiProcessor.Builder<>(barcodeFactory).build());

    if (!barcodeDetector.isOperational()) {
        Log.w(TAG, "Detector dependencies are not yet available.");

        IntentFilter lowStorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
        boolean hasLowStorage = registerReceiver(null, lowStorageFilter) != null;

        if (hasLowStorage) {
            Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show();
            Log.w(TAG, getString(R.string.low_storage_error));
        }
    }

    CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
            .setFacing(CameraSource.CAMERA_FACING_BACK)
            .setRequestedPreviewSize(1600, 1024)
            .setRequestedFps(15.0f);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        builder = builder.setFocusMode(
                autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE : null);
    }


  /*  mCameraSource = builder
            .setFlashMode( Camera.Parameters.FLASH_MODE_AUTO)
            .build();*/

    mCameraSource = builder
            .setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null)
            .build();
}

@Override
protected void onResume() {
    super.onResume();
    startCameraSource();
}

@Override
protected void onPause() {
    super.onPause();
    if (mPreview != null) {
        mPreview.stop();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mPreview != null) {
        mPreview.release();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    if (requestCode != RC_HANDLE_CAMERA_PERM) {
        Log.d(TAG, "Got unexpected permission result: " + requestCode);
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }

    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        Log.d(TAG, "Camera permission granted - initialize the camera source");
        // we have permission, so create the camerasource
        boolean autoFocus = getIntent().getBooleanExtra(AutoFocus, false);
        boolean useFlash = getIntent().getBooleanExtra(UseFlash, false);
        createCameraSource(autoFocus, useFlash);
        return;
    }

    Log.e(TAG, "Permission not granted: results len = " + grantResults.length +
            " Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)"));

    DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            finish();
        }
    };

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Multitracker sample")
            .setMessage(R.string.no_camera_permission)
            .setPositiveButton(R.string.ok, listener)
            .show();
}

private void startCameraSource() throws SecurityException {
    // check that the device has play services available.
    int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
            getApplicationContext());
    if (code != ConnectionResult.SUCCESS) {
        Dialog dlg =
                GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS);
        dlg.show();
    }

    if (mCameraSource != null) {
        try {
            mPreview.start(mCameraSource, mGraphicOverlay);
        } catch (IOException e) {
            Log.e(TAG, "Unable to start camera source.", e);
            mCameraSource.release();
            mCameraSource = null;
        }
    }
}

private boolean onTap(float rawX, float rawY) {
    int[] location = new int[2];
    mGraphicOverlay.getLocationOnScreen(location);
    float x = (rawX - location[0]) / mGraphicOverlay.getWidthScaleFactor();
    float y = (rawY - location[1]) / mGraphicOverlay.getHeightScaleFactor();

    Barcode best = null;
    float bestDistance = Float.MAX_VALUE;
    for (BarcodeGraphic graphic : mGraphicOverlay.getGraphics()) {
        Barcode barcode = graphic.getBarcode();
        if (barcode.getBoundingBox().contains((int) x, (int) y)) {
            best = barcode;
            break;
        }
        float dx = x - barcode.getBoundingBox().centerX();
        float dy = y - barcode.getBoundingBox().centerY();
        float distance = (dx * dx) + (dy * dy);  // actually squared distance
        if (distance < bestDistance) {
            best = barcode;
            bestDistance = distance;
        }
    }

    if (best != null) {
        Intent data = new Intent();
        data.putExtra(BarcodeObject, best);
        setResult(CommonStatusCodes.SUCCESS, data);
        finish();
        return true;
    }
    return false;
}

private class CaptureGestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        return onTap(e.getRawX(), e.getRawY()) || super.onSingleTapConfirmed(e);
    }
}

private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        return false;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        mCameraSource.doZoom(detector.getScaleFactor());
    }
}

@Override
public void onBarcodeDetected(Barcode barcode) {
    //do something with barcode data returned
    Date date = new Date();

    sendPost(barcode, formatDate(date));
}

private void sendPost(Barcode barcode, String date) {
    if (!codeSent) {
        codeSent = true;
        String urlApi = ((BaseApplication) this.getApplication()).getUrl() + ((BaseApplication) this.getApplication()).getApiKey();
        mAPIService.savePost(urlApi, new Post(barcode.displayValue, date)).enqueue(new Callback<PostResponse>() {
            @Override
            public void onResponse(Call<PostResponse> call, Response<PostResponse> response) {
                codeSent = false;
                if (response.isSuccessful()) {
                    Log.i(TAG, "post submitted to API: " + response.body().toString());
                    LaunchNewWin(response.body());
                }
            }

            @Override
            public void onFailure(Call<PostResponse> call, Throwable t) {
                Log.e(TAG, "Unable to submit post to API.", t);
                codeSent = false;
            }
        });
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

private static String formatDate(Date date) {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(date);
}

private void LaunchNewWin(PostResponse postResponse) {
    Intent intent = new Intent(this, ResultActivity.class);
    intent.putExtra("postResponse", postResponse.toString());
    startActivityForResult(intent, 1);
}
}
android overlay barcode barcode-scanner
1个回答
0
投票

我刚刚看到你的问题,同时必须自己实现二维码扫描仪。

对我来说最简单的方法是将所有内容放置在RelativeLayout 中,然后简单地将视图堆叠在SurfaceView 之上。这样就可以获得所需的叠加效果。

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.activity.QRActivity">

<SurfaceView android:id="@+id/surfaceViewBarcode"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>

<View   android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:alpha="0.5"
        android:background="@android:color/black" />

<TextView android:text="@string/qr_scanText"
          android:gravity="center"
          android:textColor="@android:color/white"
          android:textStyle="bold"
          android:layout_centerInParent="true"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_alignBottom="@+id/surfaceViewBarcode"
          android:layout_alignParentTop="true"/>

唯一的不便之处在于,即使二维码没有放置在指定区域,条形码扫描仪也会拾取该二维码。

在关注此线程之后,我发现您有多种选择来实现所需的结果。 一种方法是实现一个自定义处理器

另一种方法是通过 BoxDetector

我想这个例子可能也会派上用场

© www.soinside.com 2019 - 2024. All rights reserved.