• 自定义ZXing二维码扫描界面并解决取景框拉伸等问题


    先看效果

    扫描内容是下面这张,二维码是用zxing库生成的

    由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java

      1 package com.zxing.activity;
      2 
      3 import java.io.IOException;
      4 import java.util.Vector;
      5 
      6 import android.app.Activity;
      7 import android.content.Intent;
      8 import android.content.res.AssetFileDescriptor;
      9 import android.graphics.Bitmap;
     10 import android.media.AudioManager;
     11 import android.media.MediaPlayer;
     12 import android.media.MediaPlayer.OnCompletionListener;
     13 import android.os.Handler;
     14 import android.os.Vibrator;
     15 import android.view.SurfaceHolder;
     16 import android.view.SurfaceHolder.Callback;
     17 import android.view.SurfaceView;
     18 import android.widget.Toast;
     19 
     20 import com.ericssonlabs.R;
     21 import com.google.zxing.BarcodeFormat;
     22 import com.google.zxing.Result;
     23 import com.zxing.camera.CameraManager;
     24 import com.zxing.decoding.CaptureActivityHandler;
     25 import com.zxing.decoding.CaptureActivityHandler.DecodeCallback;
     26 import com.zxing.decoding.InactivityTimer;
     27 import com.zxing.view.ViewfinderView;
     28 /**
     29  * Initial the camera
     30  * @author Ryan.Tang
     31  * @modifier Lemon
     32  * @use extends CaptureActivity并且在setContentView方法后调用init方法
     33  */
     34 public abstract class CaptureActivity extends Activity implements Callback, DecodeCallback {
     35     //    private static final String TAG = "CaptureActivity";
     36 
     37     protected Activity context;
     38     protected SurfaceView surfaceView;
     39     protected ViewfinderView viewfinderView;
     40     /**初始化,必须在setContentView之后
     41      * @param context
     42      * @param viewfinderView
     43      */
     44     protected void init(Activity context, SurfaceView surfaceView, ViewfinderView viewfinderView) {
     45         this.context = context;
     46         this.surfaceView = surfaceView;
     47         this.viewfinderView = viewfinderView;
     48 
     49         CameraManager.init(getApplication());
     50 
     51         hasSurface = false;
     52         inactivityTimer = new InactivityTimer(this);
     53     }
     54 
     55 
     56     private CaptureActivityHandler handler;
     57     private boolean hasSurface;
     58     private Vector<BarcodeFormat> decodeFormats;
     59     private String characterSet;
     60     private InactivityTimer inactivityTimer;
     61     private MediaPlayer mediaPlayer;
     62     private boolean playBeep;
     63     private static final float BEEP_VOLUME = 0.10f;
     64     private boolean vibrate;
     65 
     66 
     67     @Override
     68     protected void onResume() {
     69         super.onResume();
     70         SurfaceHolder surfaceHolder = surfaceView.getHolder();
     71         if (hasSurface) {
     72             initCamera(surfaceHolder);
     73         } else {
     74             surfaceHolder.addCallback(this);
     75             surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     76         }
     77         decodeFormats = null;
     78         characterSet = null;
     79 
     80         playBeep = true;
     81         AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
     82         if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
     83             playBeep = false;
     84         }
     85         initBeepSound();
     86         vibrate = true;
     87     }
     88 
     89     @Override
     90     protected void onPause() {
     91         super.onPause();
     92         if (handler != null) {
     93             handler.quitSynchronously();
     94             handler = null;
     95         }
     96         CameraManager.get().closeDriver();
     97     }
     98 
     99     @Override
    100     protected void onDestroy() {
    101         inactivityTimer.shutdown();
    102         super.onDestroy();
    103     }
    104 
    105 
    106     public static final String RESULT_QRCODE_STRING = "RESULT_QRCODE_STRING";
    107     /**
    108      * Handler scan result
    109      * @param result
    110      * @param barcode
    111      */
    112     public void handleDecode(Result result, Bitmap barcode) {
    113         inactivityTimer.onActivity();
    114         playBeepSoundAndVibrate();
    115         String resultString = result.getText();
    116         //FIXME
    117         if (resultString.equals("")) {
    118             Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
    119         }
    120 
    121         setResult(RESULT_OK, new Intent().putExtra(RESULT_QRCODE_STRING, resultString));
    122         finish();
    123     }
    124 
    125     private void initCamera(SurfaceHolder surfaceHolder) {
    126         try {
    127             CameraManager.get().openDriver(surfaceHolder);
    128         } catch (IOException ioe) {
    129             return;
    130         } catch (RuntimeException e) {
    131             return;
    132         }
    133         if (handler == null) {
    134             handler = new CaptureActivityHandler(this, decodeFormats,
    135                     characterSet, viewfinderView, this);
    136         }
    137     }
    138 
    139     @Override
    140     public void drawViewfinder() {
    141         viewfinderView.drawViewfinder();        
    142     }
    143 
    144 
    145     @Override
    146     public void surfaceChanged(SurfaceHolder holder, int format, int width,
    147             int height) {
    148 
    149     }
    150 
    151     @Override
    152     public void surfaceCreated(SurfaceHolder holder) {
    153         if (!hasSurface) {
    154             hasSurface = true;
    155             initCamera(holder);
    156         }
    157 
    158     }
    159 
    160     @Override
    161     public void surfaceDestroyed(SurfaceHolder holder) {
    162         hasSurface = false;
    163 
    164     }
    165 
    166 
    167     public Handler getHandler() {
    168         return handler;
    169     }
    170 
    171 
    172     private void initBeepSound() {
    173         if (playBeep && mediaPlayer == null) {
    174             // The volume on STREAM_SYSTEM is not adjustable, and users found it
    175             // too loud,
    176             // so we now play on the music stream.
    177             setVolumeControlStream(AudioManager.STREAM_MUSIC);
    178             mediaPlayer = new MediaPlayer();
    179             mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    180             mediaPlayer.setOnCompletionListener(beepListener);
    181 
    182             AssetFileDescriptor file = getResources().openRawResourceFd(
    183                     R.raw.beep);
    184             try {
    185                 mediaPlayer.setDataSource(file.getFileDescriptor(),
    186                         file.getStartOffset(), file.getLength());
    187                 file.close();
    188                 mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
    189                 mediaPlayer.prepare();
    190             } catch (IOException e) {
    191                 mediaPlayer = null;
    192             }
    193         }
    194     }
    195 
    196     private static final long VIBRATE_DURATION = 200L;
    197 
    198     private void playBeepSoundAndVibrate() {
    199         if (playBeep && mediaPlayer != null) {
    200             mediaPlayer.start();
    201         }
    202         if (vibrate) {
    203             Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
    204             vibrator.vibrate(VIBRATE_DURATION);
    205         }
    206     }
    207 
    208     /**
    209      * When the beep has finished playing, rewind to queue up another one.
    210      */
    211     private final OnCompletionListener beepListener = new OnCompletionListener() {
    212         public void onCompletion(MediaPlayer mediaPlayer) {
    213             mediaPlayer.seekTo(0);
    214         }
    215     };
    216 
    217 }

    使用方法: 新建一个Activity继承CaptureActivity并且在setContentView方法后调用init方法即可。
    示例:

    CameraScanActivity.java

      1 package zuo.biao.activity;
      2 
      3 import zuo.biao.R;
      4 import zuo.biao.library.interfaces.OnBottomDragListener;
      5 import zuo.biao.util.ActivityUtil;
      6 import android.content.Context;
      7 import android.content.Intent;
      8 import android.os.Bundle;
      9 import android.view.SurfaceHolder.Callback;
     10 import android.view.SurfaceView;
     11 import android.view.View;
     12 import android.view.View.OnClickListener;
     13 
     14 import com.zxing.activity.CaptureActivity;
     15 import com.zxing.camera.CameraManager;
     16 import com.zxing.view.ViewfinderView;
     17 
     18 /**扫描二维码Activity
     19  * @author Lemon
     20  * @use 参考zuo.biao.library.ModelActivity
     21  */
     22 public class CameraScanActivity extends CaptureActivity implements Callback, OnClickListener, OnBottomDragListener {
     23     public static final String TAG = "CameraScanActivity";
     24 
     25     //启动方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
     26 
     27     /**启动这个Activity的Intent
     28      * @param context
     29      * @param title
     30      * @return
     31      */
     32     public static Intent createIntent(Context context) {
     33         return new Intent(context, CameraScanActivity.class);
     34     }
     35 
     36     //启动方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     37 
     38 
     39 
     40     @Override
     41     protected void onCreate(Bundle savedInstanceState) {
     42         super.onCreate(savedInstanceState);
     43         setContentView(R.layout.camera_scan_activity);
     44         init(this, (SurfaceView) findViewById(R.id.svCameraScan), (ViewfinderView) findViewById(R.id.vfvCameraScan));
     45 
     46         //功能归类分区方法,必须调用<<<<<<<<<<
     47         initView();
     48         initData();
     49         initListener();
     50         //功能归类分区方法,必须调用>>>>>>>>>>
     51 
     52     }
     53 
     54 
     55     //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
     56 
     57     public void initView() {//必须调用
     58 
     59     }
     60 
     61 
     62 
     63     //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     64 
     65 
     66 
     67 
     68 
     69 
     70 
     71 
     72 
     73 
     74     //data数据区(存在数据获取或处理代码,但不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
     75 
     76     public void initData() {//必须调用
     77 
     78     }
     79 
     80 
     81     //data数据区(存在数据获取或处理代码,但不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     82 
     83 
     84 
     85 
     86 
     87 
     88 
     89 
     90     //listener事件监听区(只要存在事件监听代码就是)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
     91 
     92     public void initListener() {//必须调用
     93 
     94         findViewById(R.id.tvCameraScanReturn).setOnClickListener(this);
     95         findViewById(R.id.ivCameraScanReturn).setOnClickListener(this);
     96         findViewById(R.id.ivCameraScanLight).setOnClickListener(this);
     97         findViewById(R.id.ivCameraScanMyQRCode).setOnClickListener(this);
     98     }
     99 
    100     //系统自带监听方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    101 
    102     @Override
    103     public void onDragBottom(boolean rightToLeft) {
    104         if (rightToLeft) {
    105 
    106             return;
    107         }
    108 
    109         finish();
    110     }
    111 
    112     @Override
    113     public void onClick(View v) {
    114         switch (v.getId()) {
    115         case R.id.tvCameraScanReturn:
    116         case R.id.ivCameraScanReturn:
    117             onDragBottom(false);
    118             break;
    119         case R.id.ivCameraScanLight:
    120             switchLight(! isOpen);
    121             break;
    122         case R.id.ivCameraScanMyQRCode:
    123             //
    124             break;
    125         default:
    126             break;
    127         }
    128     }
    129 
    130 
    131     private boolean isOpen = false;
    132     /**打开或关闭闪关灯
    133      * @param open
    134      */
    135     private void switchLight(boolean open) {
    136         if (open == isOpen) {
    137             return;
    138         }
    139         isOpen = CameraManager.get().switchLight(open);
    140     }
    141 
    142 
    143     //类相关监听<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    144 
    145 
    146     //类相关监听>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    147 
    148     //系统自带监听方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    149 
    150 
    151     //listener事件监听区(只要存在事件监听代码就是)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    152 
    153 
    154 
    155 
    156 
    157 
    158 
    159 
    160     //内部类,尽量少用<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    161 
    162 
    163 
    164     //内部类,尽量少用>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    165 
    166 }

    CameraScanActivity布局文件camera_scan_activity.xml

      1 <?xml version="1.0" encoding="utf-8"?>
      2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      3     style="@style/activity_page" >
      4 
      5     <SurfaceView
      6         android:id="@+id/svCameraScan"
      7         android:layout_width="wrap_content"
      8         android:layout_height="wrap_content"
      9         android:layout_gravity="center" />
     10 
     11     <!-- 必须在最底层,且不能指定宽高,否则扫描读取很难实现 -->
     12     <com.zxing.view.ViewfinderView
     13         android:id="@+id/vfvCameraScan"
     14         android:layout_width="match_parent"
     15         android:layout_height="match_parent" />
     16 
     17     <LinearLayout
     18         style="@style/ll_vertical_match_match"
     19         android:baselineAligned="false" >
     20 
     21         <RelativeLayout
     22             style="@style/topbar_bg"
     23             android:background="@color/white_alpha" >
     24 
     25             <TextView
     26                 android:id="@+id/tvCameraScanReturn"
     27                 style="@style/topbar_left_btn"
     28                 android:text="          " />
     29 
     30             <TextView
     31                 style="@style/topbar_title"
     32                 android:layout_centerHorizontal="true"
     33                 android:text="扫一扫" />
     34         </RelativeLayout>
     35 
     36         <LinearLayout
     37             style="@style/ll_vertical_match_match"
     38             android:layout_gravity="center_horizontal"
     39             android:layout_weight="1" >
     40 
     41             <TextView
     42                 style="@style/text_middle_white"
     43                 android:layout_margin="30dp"
     44                 android:text="@string/camera_scan_remind" />
     45         </LinearLayout>
     46 
     47         <LinearLayout
     48             style="@style/ll_horizontal_match_wrap"
     49             android:layout_gravity="bottom"
     50             android:background="@color/white_alpha"
     51             android:gravity="center" >
     52 
     53             <LinearLayout
     54                 style="@style/ll_vertical_wrap_wrap"
     55                 android:layout_margin="12dp"
     56                 android:paddingBottom="4dp"
     57                 android:paddingLeft="12dp"
     58                 android:paddingRight="12dp"
     59                 android:paddingTop="4dp" >
     60 
     61                 <ImageView
     62                     android:id="@+id/ivCameraScanReturn"
     63                     style="@style/wrap_wrap"
     64                     android:background="@drawable/cilcle_gray_to_white"
     65                     android:padding="12dp"
     66                     android:src="@drawable/back_black_light" />
     67 
     68                 <TextView
     69                     style="@style/text_small"
     70                     android:layout_marginTop="4dp"
     71                     android:text="返回" />
     72             </LinearLayout>
     73 
     74             <LinearLayout
     75                 style="@style/ll_vertical_wrap_wrap"
     76                 android:layout_margin="12dp"
     77                 android:paddingBottom="4dp"
     78                 android:paddingLeft="12dp"
     79                 android:paddingRight="12dp"
     80                 android:paddingTop="4dp" >
     81 
     82                 <ImageView
     83                     android:id="@+id/ivCameraScanLight"
     84                     style="@style/wrap_wrap"
     85                     android:background="@drawable/cilcle_gray_to_white"
     86                     android:padding="12dp"
     87                     android:src="@drawable/flash_light" />
     88 
     89                 <TextView
     90                     style="@style/text_small"
     91                     android:layout_marginTop="4dp"
     92                     android:text="开灯/关灯" />
     93             </LinearLayout>
     94 
     95             <LinearLayout
     96                 style="@style/ll_vertical_wrap_wrap"
     97                 android:layout_margin="12dp"
     98                 android:paddingBottom="4dp"
     99                 android:paddingLeft="12dp"
    100                 android:paddingRight="12dp"
    101                 android:paddingTop="4dp" >
    102 
    103                 <ImageView
    104                     android:id="@+id/ivCameraScanMyQRCode"
    105                     style="@style/wrap_wrap"
    106                     android:background="@drawable/cilcle_gray_to_white"
    107                     android:padding="12dp"
    108                     android:src="@drawable/qrcode" />
    109 
    110                 <TextView
    111                     style="@style/text_small"
    112                     android:layout_marginTop="4dp"
    113                     android:text="我的名片" />
    114             </LinearLayout>
    115         </LinearLayout>
    116     </LinearLayout>
    117 
    118 </FrameLayout>

    布局文件因为使用了ZBLibrary中的一些style,color等,只有这个layout的话会出现一些错误。自己新建一个layout文件并把ViewfinderView放到最外层布局文件内就行了。当然下载好下面附上的源码就没这问题了。

    对了,记得在AndroidManifest.xml中加上这些权限:

        <uses-permission android:name="android.permission.CAMERA" />

        <uses-feature android:name="android.hardware.camera" />

        <uses-feature android:name="android.hardware.camera.autofocus" />

        <uses-permission android:name="android.permission.FLASHLIGHT" />

    附源码(含使用方法)

    GitHub源码      https://github.com/TommyLemon/Android-ZBLibrary 

    开源中国源码    http://git.oschina.net/Lemon19950301/Android-ZBLibrary 

  • 相关阅读:
    WebApi调用及发布
    List<T> 去除重复数据
    C#正则表达式去除XML标签
    SSIS 发送邮件
    域登录验证.net版
    js获取select选中的值
    ionic常见错误
    mac安装brew homebrew
    flutter ios编译报错集
    dart 格式化输出
  • 原文地址:https://www.cnblogs.com/tommylemon/p/5565565.html
Copyright © 2020-2023  润新知