自定義ZXing二維碼掃描界面並解決取景框拉伸等問題

来源:http://www.cnblogs.com/tommylemon/archive/2016/06/07/5565565.html
-Advertisement-
Play Games

Google開源的二維碼庫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 	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • iOS 直播 閃光燈的使用 應用場景是這樣的,最近公司決定做一款直播類的軟體. 在開發中就遇到了不曾使用過的硬體功能 閃光燈. 這篇博客將簡單介紹一下閃光燈的使用. ` ` ...
  • 1.第一個Fragment 2.第二個Fragment ...
  • iOS FFmpeg 優秀博客(資源)集錦 這篇博客沒有我自己寫的內容: 主要是對FFmpeg一些優秀博客的記錄 隨時更新 1 "iOS編譯FFmpeg,kxmovie實現視頻播放" 2 "視音頻編解碼技術零基礎學習方法" 3 "一個不依賴FFmpeg的播放器,支持RTMP" ...
  • 說到自定義控制項不得不提的就是介面回調,在Android開發中介面回調用的還是蠻多的。在這篇博客開始的時候呢,我想聊一下iOS的自定義控制項。在iOS中自定義控制項的思路是繼承自UIView, 在UIView的子類中組合一些控制項,對外暴漏一些屬性和回調介面,並留有必要的實現方法。在iOS自定義控制項中常用的 ...
  • 想在移動開發大餐中分一杯羹,體驗最火最炫的技術?小伙子,很有眼光嘛 毫無疑問,移動開發在目前和未來幾年內都會盛極一時。無數開發職位虛位以待。各大公司都在尋找各種層次的程式員——新手級、入門級、中級、老手、專家。 本文是寫給新手們的——我會幫你們找到第一份iOS開發工作。 “我幹嘛聽你的?”, 你可能 ...
  • 歸屬地數據源 http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx webxml網站還支持其他請求方式 如SOAP等等 界面比較簡單 <?xml version="1.0" encoding="utf-8"?> <LinearLa ...
  • 1. iPad 現有型號: iPad Pro, iPad Air, iPad mini 均配備Retina顯示屏。早期還有iPad 依次對應的坐標系及解析度: iPad Pro 坐標系:1366 x 1024 解析度:2732 x 2048 iPad Air 坐標系:1024 x 768 解析度:2 ...
  • dark_gmn 的博客 http://blog.csdn.net/dark_gmn?viewmode=contents Tel_小超 的博客 http://blog.csdn.net/qq_26544491?viewmode=contents youxianming的博客 http://www.c ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...