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