日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

自定義 UI 下使用掃碼功能

本文將引導(dǎo)您繪制自定義 UI 界面并將自定義 UI 掃碼的能力添加到工程中。

如需在自定義 UI 下使用掃碼功能,請參考 代碼示例

該過程主要分為以下四個步驟:

  1. 創(chuàng)建依賴工程

  2. 在依賴工程中創(chuàng)建定義 UI 界面

  3. 在依賴工程中使用掃碼功能

  4. 在主工程中調(diào)用自定義 UI 下的掃碼功能

操作步驟

創(chuàng)建依賴工程

  1. 單擊 File > New > New Module

  2. 選擇 Android Library,單擊 Next

  3. 輸入 Module name,單擊 Finish。

在依賴工程中創(chuàng)建定義 UI 界面

  1. customcom.example.custom 包中創(chuàng)建 widget 包。在 widget 包中添加 APSurfaceTexture 類,讓其繼承 SurfaceTexture 類,以獲取圖像流。

    public class APSurfaceTexture extends SurfaceTexture {
    
     private static final String TAG = "APSurfaceTexture";
    
     public SurfaceTexture mSurface;
    
     public APSurfaceTexture() {
         super(0);
     }
    
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
     @Override
     public void attachToGLContext(int texName) {
         mSurface.attachToGLContext(texName);
     }
    
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
     @Override
     public void detachFromGLContext() {
         try {
             mSurface.detachFromGLContext();
         } catch (Exception ex) {
             try {
                 Method nativeMethod = SurfaceTexture.class.getDeclaredMethod("nativeDetachFromGLContext");
                 nativeMethod.setAccessible(true);
                 int retCode = (Integer) nativeMethod.invoke(mSurface);
                 LoggerFactory.getTraceLogger().debug(TAG, "nativeDetachFromGLContext invoke retCode:" + retCode);
             } catch (Exception e) {
                 LoggerFactory.getTraceLogger().error(TAG, "nativeDetachFromGLContext invoke exception:" + e.getMessage());
             }
             LoggerFactory.getTraceLogger().error(TAG, "mSurface.detachFromGLContext() exception:" + ex.getMessage());
         }
     }
    
     @Override
     public boolean equals(Object o) {
         return mSurface.equals(o);
     }
    
     @Override
     public long getTimestamp() {
         return mSurface.getTimestamp();
     }
    
     @Override
     public void getTransformMatrix(float[] mtx) {
         mSurface.getTransformMatrix(mtx);
     }
    
     @Override
     public void release() {
         super.release();
         mSurface.release();
     }
    
     @Override
     public int hashCode() {
         return mSurface.hashCode();
     }
    
     @TargetApi(Build.VERSION_CODES.KITKAT)
     @Override
     public void releaseTexImage() {
         mSurface.releaseTexImage();
     }
    
     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     @Override
     public void setDefaultBufferSize(int width, int height) {
         mSurface.setDefaultBufferSize(width, height);
     }
    
     @Override
     public void setOnFrameAvailableListener(OnFrameAvailableListener listener) {
         mSurface.setOnFrameAvailableListener(listener);
     }
    
     @Override
     public String toString() {
         return mSurface.toString();
     }
    
     @Override
     public void updateTexImage() {
         mSurface.updateTexImage();
     }
    }
  2. customwidget 包中添加 APTextureView 類,讓其繼承 TextureView 類,實(shí)現(xiàn)圖像流的顯示。

    public class APTextureView extends TextureView {
    
     private static final String TAG = "APTextureView";
    
     private Field mSurfaceField;
    
     public APTextureView(Context context) {
         super(context);
     }
    
     public APTextureView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
    
     public APTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
    
     @Override
     protected void onDetachedFromWindow() {
         try {
             super.onDetachedFromWindow();
         } catch (Exception ex) {
             LoggerFactory.getTraceLogger().error(TAG, "onDetachedFromWindow exception:" + ex.getMessage());
         }
     }
    
     @Override
     public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
         super.setSurfaceTexture(surfaceTexture);
         afterSetSurfaceTexture();
     }
    
     private void afterSetSurfaceTexture() {
         LoggerFactory.getTraceLogger().debug(TAG, "afterSetSurfaceTexture Build.VERSION.SDK_INT:" + Build.VERSION.SDK_INT);
         if (Build.VERSION.SDK_INT < 16 || Build.VERSION.SDK_INT > 20) {
             return;
         }
    
         try {
             if (mSurfaceField == null) {
                 mSurfaceField = TextureView.class.getDeclaredField("mSurface");
                 mSurfaceField.setAccessible(true);
             }
    
             SurfaceTexture innerSurface = (SurfaceTexture) mSurfaceField.get(this);
             if (innerSurface != null) {
                 if (!(innerSurface instanceof APSurfaceTexture)) {
                     APSurfaceTexture wrapSurface = new APSurfaceTexture();
                     wrapSurface.mSurface = innerSurface;
                     mSurfaceField.set(this, wrapSurface);
                     LoggerFactory.getTraceLogger().debug(TAG, "afterSetSurfaceTexture wrap mSurface");
                 }
             }
         } catch (Exception ex) {
             LoggerFactory.getTraceLogger().error(TAG, "afterSetSurfaceTexture exception:" + ex.getMessage());
         }
     }
    }
  3. com.example.custom 包中創(chuàng)建 Utils 類,實(shí)現(xiàn)圖片的轉(zhuǎn)換。

    public class Utils {
    
     private static String TAG = "Utils";
    
     public static void toast(Context context, String msg) {
         Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
     }
    
     public static Bitmap changeBitmapColor(Bitmap bitmap, int color) {
         int bitmap_w = bitmap.getWidth();
         int bitmap_h = bitmap.getHeight();
         int[] arrayColor = new int[bitmap_w * bitmap_h];
    
         int count = 0;
         for (int i = 0; i < bitmap_h; i++) {
             for (int j = 0; j < bitmap_w; j++) {
    
                 int originColor = bitmap.getPixel(j, i);
                 // 非透明區(qū)域
                 if (originColor != 0) {
                     originColor = color;
                 }
    
                 arrayColor[count] = originColor;
                 count++;
             }
         }
         return Bitmap.createBitmap(arrayColor, bitmap_w, bitmap_h, Bitmap.Config.ARGB_8888);
     }
    
     public static Bitmap uri2Bitmap(Context context, Uri uri) {
         Bitmap bitmap = null;
         InputStream in;
         try {
             in = context.getContentResolver().openInputStream(uri);
             if (in != null) {
                 bitmap = BitmapFactory.decodeStream(in);
                 in.close();
             }
         } catch (Exception e) {
             LoggerFactory.getTraceLogger().error(TAG, "uri2Bitmap: Exception " + e.getMessage());
         }
         return bitmap;
     }
    }
  4. custom 中創(chuàng)建 res > values > attrs.xml 文件并添加如下代碼。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
     <declare-styleable name="scan">
         <attr name="shadowColor" format="color" />
     </declare-styleable>
    </resources>
  5. customres > drawable 文件夾中粘貼如下 資源文件

    12
  6. customwidget 包中添加 FinderView 類,讓其繼承 View 類,并添加如下代碼。實(shí)現(xiàn)掃碼窗口、邊角及周邊陰影的繪制功能。

    public class FinderView extends View {
    
    private static final int DEFAULT_SHADOW_COLOR = 0x96000000;
    
    private int scanWindowLeft, scanWindowTop, scanWindowRight, scanWindowBottom;
    private Bitmap leftTopCorner, rightTopCorner, leftBottomCorner, rightBottomCorner;
    private Paint paint;
    private int shadowColor;
    
    public FinderView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }
    
    public FinderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }
    
    private void init(Context context, AttributeSet attrs) {
        applyConfig(context, attrs);
        setVisibility(INVISIBLE);
        initCornerBitmap(context);
    
        paint = new Paint();
        paint.setAntiAlias(true);
    }
    
    private void applyConfig(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.scan);
            shadowColor = typedArray.getColor(R.styleable.scan_shadowColor, DEFAULT_SHADOW_COLOR);
            typedArray.recycle();
        }
    }
    //初始化掃碼窗口邊角樣式
    private void initCornerBitmap(Context context) {
        Resources res = context.getResources();
        leftTopCorner = BitmapFactory.decodeResource(res, R.drawable.scan_window_corner_left_top);
        rightTopCorner = BitmapFactory.decodeResource(res, R.drawable.scan_window_corner_right_top);
        leftBottomCorner = BitmapFactory.decodeResource(res, R.drawable.scan_window_corner_left_bottom);
        rightBottomCorner = BitmapFactory.decodeResource(res, R.drawable.scan_window_corner_right_bottom);
    }
    
    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        drawShadow(canvas);
        drawCorner(canvas);
    }
    //繪制掃碼窗口邊角樣式
    private void drawCorner(Canvas canvas) {
        paint.setAlpha(255);
        canvas.drawBitmap(leftTopCorner, scanWindowLeft, scanWindowTop, paint);
        canvas.drawBitmap(rightTopCorner, scanWindowRight - rightTopCorner.getWidth(), scanWindowTop, paint);
        canvas.drawBitmap(leftBottomCorner, scanWindowLeft, scanWindowBottom - leftBottomCorner.getHeight(), paint);
        canvas.drawBitmap(rightBottomCorner, scanWindowRight - rightBottomCorner.getWidth(), scanWindowBottom - rightBottomCorner.getHeight(), paint);
    }
    //繪制掃碼周邊陰影
    private void drawShadow(Canvas canvas) {
        paint.setColor(shadowColor);
        canvas.drawRect(0, 0, getWidth(), scanWindowTop, paint);
        canvas.drawRect(0, scanWindowTop, scanWindowLeft, scanWindowBottom, paint);
        canvas.drawRect(scanWindowRight, scanWindowTop, getWidth(), scanWindowBottom, paint);
        canvas.drawRect(0, scanWindowBottom, getWidth(), getHeight(), paint);
    }
    
    /**
     * 根據(jù) RayView 的位置決定掃碼窗口的位置
     */
    public void setScanWindowLocation(int left, int top, int right, int bottom) {
        scanWindowLeft = left;
        scanWindowTop = top;
        scanWindowRight = right;
        scanWindowBottom = bottom;
        invalidate();
        setVisibility(VISIBLE);
    }
    
    public void setShadowColor(int shadowColor) {
        this.shadowColor = shadowColor;
    }
    //設(shè)置掃碼窗口邊角顏色
    public void setCornerColor(int angleColor) {
        leftTopCorner = Utils.changeBitmapColor(leftTopCorner, angleColor);
        rightTopCorner = Utils.changeBitmapColor(rightTopCorner, angleColor);
        leftBottomCorner = Utils.changeBitmapColor(leftBottomCorner, angleColor);
        rightBottomCorner = Utils.changeBitmapColor(rightBottomCorner, angleColor);
    }
    }
  7. customwidget 包中添加 RayView 類,讓其繼承 ImageView 類,并添加如下代碼。實(shí)現(xiàn)掃描射線的繪制功能。

    public class RayView extends ImageView {
    
    private FinderView mFinderView;
    private ScaleAnimation scanAnimation;
    private int[] location = new int[2];
    
    public RayView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public RayView(Context context) {
        super(context);
    }
    
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    
        // 設(shè)置 FinderView 中掃碼窗口的位置
        getLocationOnScreen(location);
        if (mFinderView != null) {
            mFinderView.setScanWindowLocation(location[0], location[1], location[0] + getWidth(), location[1] + getHeight());
        }
    }
    
    public void startScanAnimation() {
        setVisibility(VISIBLE);
        if (scanAnimation == null) {
            scanAnimation = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f);
            scanAnimation.setDuration(3000L);
            scanAnimation.setFillAfter(true);
            scanAnimation.setRepeatCount(Animation.INFINITE);
            scanAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        }
        startAnimation(scanAnimation);
    }
    
    public void stopScanAnimation() {
        setVisibility(INVISIBLE);
        if (scanAnimation != null) {
            this.clearAnimation();
            scanAnimation = null;
        }
    }
    
    public void setFinderView(FinderView FinderView) {
        mFinderView = FinderView;
    }
    }
  8. customres 中創(chuàng)建 layout > File > view_scan.xml 文件,并添加如下代碼,繪制掃描頁面的布局界面。

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android">
    
        <com.example.custom.widget.FinderView
            android:id="@+id/finder_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center_vertical"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/back"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:scaleType="center"
                android:src="@drawable/icon_back" />
    
            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@string/custom_title"
                android:textColor="#ffffff"
                android:textSize="16sp" />
    
            <ImageView
                android:id="@+id/gallery"
                android:layout_width="34dp"
                android:layout_height="34dp"
                android:layout_marginEnd="10dp"
                android:layout_marginRight="10dp"
                android:scaleType="fitXY"
                android:src="@drawable/selector_scan_from_gallery" />
    
            <ImageView
                android:id="@+id/torch"
                android:layout_width="34dp"
                android:layout_height="34dp"
                android:layout_marginEnd="10dp"
                android:layout_marginRight="10dp"
                android:scaleType="fitXY"
                android:src="@drawable/selector_torch" />
        </LinearLayout>
    
        <com.example.custom.widget.RayView
            android:id="@+id/ray_view"
            android:layout_width="270dp"
            android:layout_height="280dp"
            android:layout_centerInParent="true"
            android:background="@drawable/custom_scan_ray" />
    
        <TextView
            android:id="@+id/tip_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/ray_view"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:includeFontPadding="false"
            android:text="@string/scan_tip"
            android:textColor="#7fffffff"
            android:textSize="14sp" />
    
    </merge>
  9. widget 包中添加 ScanView 類,讓其繼承 RelativeLayout 類,并添加如下代碼。實(shí)現(xiàn)掃碼相關(guān)的 View 與掃碼引擎的交互功能。

    public class ScanView extends RelativeLayout {
    
    private RayView mRayView;
    
    public ScanView(Context context) {
        super(context);
        init(context);
    }
    
    public ScanView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    public ScanView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    
    private void init(Context ctx) {
        LayoutInflater.from(ctx).inflate(R.layout.view_scan, this, true);
        FinderView finderView = (FinderView) findViewById(R.id.finder_view);
        mRayView = (RayView) findViewById(R.id.ray_view);
        mRayView.setFinderView(finderView);
    }
    
    public void onStartScan() {
        mRayView.startScanAnimation();
    }
    
    public void onStopScan() {
        mRayView.stopScanAnimation();
    }
    
    public float getCropWidth() {
        return mRayView.getWidth() * 1.1f;
    }
    
    public Rect getScanRect(Camera camera, int previewWidth, int previewHeight) {
        if (camera == null) {
            return null;
        }
        int[] location = new int[2];
        mRayView.getLocationOnScreen(location);
        Rect r = new Rect(location[0], location[1],
                location[0] + mRayView.getWidth(), location[1] + mRayView.getHeight());
        Camera.Size size;
        try {
            size = camera.getParameters().getPreviewSize();
        } catch (Exception e) {
            return null;
        }
        if (size == null) {
            return null;
        }
        double rateX = (double) size.height / (double) previewWidth;
        double rateY = (double) size.width / (double) previewHeight;
        // 裁剪框大小 = 網(wǎng)格動畫框大?。?.1
        int expandX = (int) (mRayView.getWidth() * 0.05);
        int expandY = (int) (mRayView.getHeight() * 0.05);
        Rect resRect = new Rect(
                (int) ((r.top - expandY) * rateY),
                (int) ((r.left - expandX) * rateX),
                (int) ((r.bottom + expandY) * rateY),
                (int) ((r.right + expandX) * rateX));
    
        Rect finalRect = new Rect(
                resRect.left < 0 ? 0 : resRect.left,
                resRect.top < 0 ? 0 : resRect.top,
                resRect.width() > size.width ? size.width : resRect.width(),
                resRect.height() > size.height ? size.height : resRect.height());
    
        Rect rect1 = new Rect(
                finalRect.left / 4 * 4,
                finalRect.top / 4 * 4,
                finalRect.right / 4 * 4,
                finalRect.bottom / 4 * 4);
    
        int max = Math.max(rect1.right, rect1.bottom);
        int diff = Math.abs(rect1.right - rect1.bottom) / 8 * 4;
    
        Rect rect2;
        if (rect1.right > rect1.bottom) {
            rect2 = new Rect(rect1.left, rect1.top - diff, max, max);
        } else {
            rect2 = new Rect(rect1.left - diff, rect1.top, max, max);
        }
        return rect2;
    }
    }
  10. customlayout 文件夾中創(chuàng)建 activity_custom_scan.xml 文件并添加如下代碼。繪制自定義掃碼功能的主界面。

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.mpaas.aar.demo.custom.widget.APTextureView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <com.mpaas.aar.demo.custom.widget.ScanView
            android:id="@+id/scan_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </FrameLayout>

在依賴工程中使用掃碼功能

  1. customcom.example.custom 包中添加 ScanHelper 類,并添加如下代碼。調(diào)用掃碼功能以及獲取掃碼結(jié)果的回調(diào)結(jié)果。

    public class ScanHelper {
    
     private static class Holder {
         private static ScanHelper instance = new ScanHelper();
     }
    
     private ScanCallback scanCallback;
    
     private ScanHelper() {
     }
    
     public static ScanHelper getInstance() {
         return Holder.instance;
     }
    
     public void scan(Context context, ScanCallback scanCallback) {
         if (context == null) {
             return;
         }
         this.scanCallback = scanCallback;
         context.startActivity(new Intent(context, CustomScanActivity.class));
     }
    
     void notifyScanResult(boolean isProcessed, Intent resultData) {
         if (scanCallback != null) {
             scanCallback.onScanResult(isProcessed, resultData);
             scanCallback = null;
         }
     }
    
     public interface ScanCallback {
         void onScanResult(boolean isProcessed, Intent result);
     }
    }
  2. customcom.example.custom 包中添加 CustomScanActivity 類,讓其繼承 Activity 類。設(shè)置界面沉浸模式并創(chuàng)建資源文件對應(yīng)的 ViewButton。

    public class CustomScanActivity extends Activity {
     private final String TAG = CustomScanActivity.class.getSimpleName();
     private static final int REQUEST_CODE_PERMISSION = 1;
     private static final int REQUEST_CODE_PHOTO = 2;
     private ImageView mTorchBtn;
     private APTextureView mTextureView;
     private ScanView mScanView;
     private boolean isFirstStart = true;
     private boolean isPermissionGranted;
     private boolean isScanning;
     private boolean isPaused;
     private Rect scanRect;
     private MPScanner mpScanner;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_custom_scan);
    
         // 設(shè)置沉浸模式
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             getWindow().setFlags(
                     WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                     WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
         }
    
         mTextureView = findViewById(R.id.surface_view);
         mScanView = findViewById(R.id.scan_view);
         mTorchBtn = findViewById(R.id.torch);
    
     }
    
      @Override
     public void onPause() {
         super.onPause();
    
     }
    
     @Override
     public void onResume() {
         super.onResume();
    
     }
    
     @Override
     public void onDestroy() {
         super.onDestroy();
    
     }
    
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
     }
      @Override
     public void onBackPressed() {
         super.onBackPressed();
    
     }
    
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
    
     }
    }
  3. 實(shí)現(xiàn)打開手機(jī)相冊的功能。

    1. CustomScanActivity 中創(chuàng)建 pickImageFromGallery 方法。

      private void pickImageFromGallery() {
       Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
       intent.setType("image/*");
       startActivityForResult(intent, REQUEST_CODE_PHOTO);
      }
    2. onCreate 方法中添加 gallery 的單擊事件,并調(diào)用 pickImageFromGallery 方法。

       findViewById(R.id.gallery).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               pickImageFromGallery();
           }
       });
  4. 實(shí)現(xiàn)切換手電開關(guān)的功能。

    1. CustomScanActivity 中創(chuàng)建 switchTorch 方法。

       private void switchTorch() {
           boolean torchOn = mpScanner.switchTorch();
           mTorchBtn.setSelected(torchOn);
       }
    2. onCreate 方法中添加 mTorchBtn 的單擊事件,并調(diào)用 switchTorch 方法。

      mTorchBtn.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   switchTorch();
               }
           });
  5. CustomScanActivity 中創(chuàng)建 notifyScanResult 方法,onBackPressed 中調(diào)用 notifyScanResult 方法。

     private void notifyScanResult(boolean isProcessed, Intent resultData) {
         ScanHelper.getInstance().notifyScanResult(isProcessed, resultData);
     }
    
     @Override
     public void onBackPressed() {
         super.onBackPressed();
         notifyScanResult(false, null);
     }
  6. CustomScanActivityonCreate 方法中添加 back 的單擊事件,并調(diào)用 onBackPressed 方法。

         findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 onBackPressed();
             }
         });
  7. CustomScanActivity 中創(chuàng)建 initMPScanner 方法,并使用 mpScanner 對象的 setRecognizeType 方法設(shè)置識別碼的類型。

    private void initMPScanner() {
        mpScanner = new MPScanner(this);
        mpScanner.setRecognizeType(
                MPRecognizeType.QR_CODE,
                MPRecognizeType.BAR_CODE,
                MPRecognizeType.DM_CODE,
                MPRecognizeType.PDF417_CODE
        );
    }
  8. CustomScanActivity 中創(chuàng)建 onScanSuccess 方法,并實(shí)現(xiàn)如下代碼。

    private void onScanSuccess(final MPScanResult result) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (result == null) {
                    notifyScanResult(true, null);
                } else {
                    Intent intent = new Intent();
                    intent.setData(Uri.parse(result.getText()));
                    notifyScanResult(true, intent);
                }
                CustomScanActivity.this.finish();
            }
        });
    }
  9. CustomScanActivity 中創(chuàng)建 initScanRect 方法,初始化掃描功能。

    1. 調(diào)用 mpScanner 對象的 getCamera 方法獲取 Camera 對象并調(diào)用 mpScanner 對象的 setScanRegion 方法設(shè)置掃描區(qū)域。

      private void initScanRect() {
       if (scanRect == null) {
           scanRect = mScanView.getScanRect(
                   mpScanner.getCamera(), mTextureView.getWidth(), mTextureView.getHeight());
      
           float cropWidth = mScanView.getCropWidth();
           LoggerFactory.getTraceLogger().debug(TAG, "cropWidth: " + cropWidth);
           if (cropWidth > 0) {
               // 預(yù)覽放大 = 屏幕寬 / 裁剪框?qū)?         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
               float screenWith = wm.getDefaultDisplay().getWidth();
               float screenHeight = wm.getDefaultDisplay().getHeight();
               float previewScale = screenWith / cropWidth;
               if (previewScale < 1.0f) {
                   previewScale = 1.0f;
               }
               if (previewScale > 1.5f) {
                   previewScale = 1.5f;
               }
               LoggerFactory.getTraceLogger().debug(TAG, "previewScale: " + previewScale);
               Matrix transform = new Matrix();
               transform.setScale(previewScale, previewScale, screenWith / 2, screenHeight / 2);
               mTextureView.setTransform(transform);
           }
       }
       mpScanner.setScanRegion(scanRect);
      }
    2. 使用 mpScanner 對象的 setMPScanListener 方法實(shí)現(xiàn)掃描監(jiān)聽器的功能。

      mpScanner.setMPScanListener(new MPScanListener() {
          @Override
          public void onConfiguration() {
              mpScanner.setDisplayView(mTextureView);
          }
      
          @Override
          public void onStart() {
              if (!isPaused) {
                  runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          if (!isFinishing()) {
                              initScanRect();
                              mScanView.onStartScan();
                          }
                      }
                  });
              }
          }
      
          @Override
          public void onSuccess(MPScanResult mpScanResult) {
              mpScanner.beep();
              onScanSuccess(mpScanResult);
          }
      
          @Override
          public void onError(MPScanError mpScanError) {
              if (!isPaused) {
                  runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          Utils.toast(CustomScanActivity.this, getString(R.string.camera_open_error));
                      }
                  });
              }
          }
      });
    3. 使用 mpScanner 對象的 setMPImageGrayListener 方法實(shí)現(xiàn)識別圖像灰度值的監(jiān)聽功能。

      mpScanner.setMPImageGrayListener(new MPImageGrayListener() {
          @Override
          public void onGetImageGray(int gray) {
              // 注意:該回調(diào)在昏暗環(huán)境下可能會連續(xù)多次執(zhí)行
              if (gray < MPImageGrayListener.LOW_IMAGE_GRAY) {
                  runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          Utils.toast(CustomScanActivity.this, "光線太暗,請打開手電筒");
                      }
                  });
              }
          }
      });
      }
  10. CustomScanActivity 中分別創(chuàng)建 startScanstopScan 方法,實(shí)現(xiàn)開啟和關(guān)閉相機(jī)掃碼權(quán)限。

    private void startScan() {
        try {
            mpScanner.openCameraAndStartScan();
            isScanning = true;
        } catch (Exception e) {
            isScanning = false;
            LoggerFactory.getTraceLogger().error(TAG, "startScan: Exception " + e.getMessage());
        }
    }
    
    private void stopScan() {
        mpScanner.closeCameraAndStopScan();
        mScanView.onStopScan();
        isScanning = false;
        if (isFirstStart) {
            isFirstStart = false;
        }
    }
  11. CustomScanActivity 中創(chuàng)建 onPermissionGranted 方法、checkCameraPermission 方法和 scanFromUri 方法。

    private void onPermissionGranted() {
        isPermissionGranted = true;
        startScan();
    }
    
    private void checkCameraPermission() {
        if (PermissionChecker.checkSelfPermission(
                this, Manifest.permission.CAMERA) != PermissionChecker.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_PERMISSION);
        } else {
            onPermissionGranted();
        }
    }
    
    private void scanFromUri(Uri uri) {
        final Bitmap bitmap = Utils.uri2Bitmap(this, uri);
        if (bitmap == null) {
            notifyScanResult(true, null);
            finish();
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    MPScanResult mpScanResult = mpScanner.scanFromBitmap(bitmap);
                    mpScanner.beep();
                    onScanSuccess(mpScanResult);
                }
            }, "scanFromUri").start();
        }
    }
  12. CustomScanActivityonCreate 方法中調(diào)用 checkCameraPermission 方法檢查相機(jī)權(quán)限。

    checkCameraPermission();
  13. CustomScanActivityonPause、onResumeonDestroy、onRequestPermissionsResultonActivityResult 方法中分別添加如下內(nèi)容。

    @Override
    public void onPause() {
        super.onPause();
        isPaused = true;
        if (isScanning) {
            stopScan();
        }
    }
    
    @Override
    public void onResume() {
        super.onResume();
        isPaused = false;
        if (!isFirstStart && isPermissionGranted) {
            startScan();
        }
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        mpScanner.release();
    }   
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_PERMISSION) {
            int length = Math.min(permissions.length, grantResults.length);
            for (int i = 0; i < length; i++) {
                if (TextUtils.equals(permissions[i], Manifest.permission.CAMERA)) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        Utils.toast(this, getString(R.string.camera_no_permission));
                    } else {
                        onPermissionGranted();
                    }
                    break;
                }
            }
        }
          @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null) {
            return;
        }
        if (requestCode == REQUEST_CODE_PHOTO) {
            scanFromUri(data.getData());
        }
    }
    }
  14. customAndroidManifest.xml 文件中設(shè)置 CustomScanActivitycustom 的主入口。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mpaas.aar.demo.custom">
    
        <application>
            <activity
                android:name=".CustomScanActivity"
                android:configChanges="orientation|keyboardHidden|navigation"
                android:exported="false"
                android:launchMode="singleTask"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.NoTitleBar"
                android:windowSoftInputMode="adjustResize|stateHidden" />
        </application>
    
    </manifest>

在主工程中調(diào)用自定義 UI 下的掃碼功能

  1. activity_main.xml 文件中,添加 Button,并設(shè)置 Button 的 ID 為 custom_ui_btn。

     <Button
         android:id="@+id/custom_ui_btn"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="208dp"
         android:background="#108EE9"
         android:gravity="center"
         android:text="自定義 UI 下使用掃一掃"
         android:textColor="#ffffff"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0.0"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
  2. MainActivity 類中編寫代碼。添加 custom_ui_btn 按鈕的單擊事件。獲取自定義 UI 界面,并使用自定義 UI 的掃碼功能。代碼如下所示:

    findViewById(R.id.custom_ui_btn).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 ScanHelper.getInstance().scan(MainActivity.this, new ScanHelper.ScanCallback() {
                     @Override
                     public void onScanResult(boolean isProcessed, Intent result) {
                         if (!isProcessed) {
                             // 掃碼界面單擊物理返回鍵或左上角返回鍵
                             return;
                         }
    
                         if (result == null || result.getData() == null) {
                             Toast.makeText(MainActivity.this, "掃碼失敗,請重試!", Toast.LENGTH_SHORT).show();
                             return;
                         }
                         new AlertDialog.Builder(MainActivity.this)
                                 .setMessage(result.getData().toString())
                                 .setPositiveButton(R.string.confirm, null)
                                 .create()
                                 .show();
                     }
                 });
             }
         });
  3. 編譯運(yùn)行工程后,單擊 自定義 UI 下使用掃一掃 后即可使用自定義 UI 下的掃碼功能。

  4. 掃描二維碼,會彈出該二維碼的信息。