我在項目中用到了二維碼掃描的技術,用的是Google提供的ZXing開源項目,它提供二維碼和條形碼的掃描。掃描條形碼就是直接讀取條形碼的內容,掃描二維碼是按照自己指定的二維碼格式進行編碼和解碼。
可以到http://code.google.com/p/zxing/下載ZXing項目的源碼,然後按照官方文檔進行開發,我這裡使用的ZXing是經過簡化版的,去除了一些一般使用不必要的文件,項目工程截圖如下:
其中encoding包是我在它的基礎上自己加上去的,功能是根據傳入的字符串來生成二維碼圖片,返回一個Bitmap,其余的包是ZXing項目自帶的。另外對掃描界面的布局我也進行了修改,官方的掃描界面是橫向的,我改成了縱向的,並加入了頂部的Tab和取消按鈕(camera.xml),另外還需要的一些文件是colors.xml、ids.xml,這些都是原本ZXing項目中自帶的,最後就是libs下面的jar包。
先來看看最後的效果:
首先是根據輸入的字符串生成二維碼圖片(左圖),然後掃描二維碼圖片可以在界面上顯示掃描結果(右圖):
點擊Open Camera按鈕代開掃描框(左圖),掃描條形碼結果如下(右圖):
接下來看如何使用,首先是把ZXing項目中的一些文件拷貝到我們自己的項目中,然後在Mainifest文件中進行配置權限:
[html] view plaincopy
- <uses-permission android:name="android.permission.VIBRATE" />
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-feature android:name="android.hardware.camera" />
- <uses-feature android:name="android.hardware.camera.autofocus" />
[html] view plain copy
- <uses-permission android:name="android.permission.VIBRATE" />
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-feature android:name="android.hardware.camera" />
- <uses-feature android:name="android.hardware.camera.autofocus" />
還有就是掃描界面Activity的配置:
[html] view plaincopy
- <activity
- android:configChanges="orientation|keyboardHidden"
- android:name="com.zxing.activity.CaptureActivity"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:windowSoftInputMode="stateAlwaysHidden" >
- </activity>
[html] view plain copy
- <activity
- android:configChanges="orientation|keyboardHidden"
- android:name="com.zxing.activity.CaptureActivity"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:windowSoftInputMode="stateAlwaysHidden" >
- </activity>
接下來是我自己項目的布局文件:
[html] view plaincopy
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@android:color/white"
- android:orientation="vertical" >
-
- <Button
- android:id="@+id/btn_scan_barcode"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="30dp"
- android:text="Open camera" />
-
- <LinearLayout
- android:orientation="horizontal"
- android:layout_marginTop="10dp"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:textSize="18sp"
- android:text="Scan result:" />
-
- <TextView
- android:id="@+id/tv_scan_result"
- android:layout_width="fill_parent"
- android:textSize="18sp"
- android:textColor="@android:color/black"
- android:layout_height="wrap_content" />
- </LinearLayout>
-
- <EditText
- android:id="@+id/et_qr_string"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="30dp"
- android:hint="Input the text"/>
-
- <Button
- android:id="@+id/btn_add_qrcode"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="Generate QRcode" />
-
- <ImageView
- android:id="@+id/iv_qr_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:layout_gravity="center"/>
-
- </LinearLayout>
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@android:color/white"
- android:orientation="vertical" >
-
- <Button
- android:id="@+id/btn_scan_barcode"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="30dp"
- android:text="Open camera" />
-
- <LinearLayout
- android:orientation="horizontal"
- android:layout_marginTop="10dp"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:textSize="18sp"
- android:text="Scan result:" />
-
- <TextView
- android:id="@+id/tv_scan_result"
- android:layout_width="fill_parent"
- android:textSize="18sp"
- android:textColor="@android:color/black"
- android:layout_height="wrap_content" />
- </LinearLayout>
-
- <EditText
- android:id="@+id/et_qr_string"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="30dp"
- android:hint="Input the text"/>
-
- <Button
- android:id="@+id/btn_add_qrcode"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="Generate QRcode" />
-
- <ImageView
- android:id="@+id/iv_qr_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:layout_gravity="center"/>
-
- </LinearLayout>
下面是主Activity的代碼,主要功能是打開掃描框、顯示掃描結果、根據輸入的字符串生成二維碼圖片:
[java] view plaincopy
- public class BarCodeTestActivity extends Activity {
- /** Called when the activity is first created. */
- private TextView resultTextView;
- private EditText qrStrEditText;
- private ImageView qrImgImageView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- resultTextView = (TextView) this.findViewById(R.id.tv_scan_result);
- qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string);
- qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image);
-
- Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
- scanBarCodeButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- //打開掃描界面掃描條形碼或二維碼
- Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
- startActivityForResult(openCameraIntent, 0);
- }
- });
-
- Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode);
- generateQRCodeButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- try {
- String contentString = qrStrEditText.getText().toString();
- if (!contentString.equals("")) {
- //根據字符串生成二維碼圖片並顯示在界面上,第二個參數為圖片的大小(350*350)
- Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
- qrImgImageView.setImageBitmap(qrCodeBitmap);
- }else {
- Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
- }
-
- } catch (WriterException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- });
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- //處理掃描結果(在界面上顯示)
- if (resultCode == RESULT_OK) {
- Bundle bundle = data.getExtras();
- String scanResult = bundle.getString("result");
- resultTextView.setText(scanResult);
- }
- }
- }
[java] view plain copy
- public class BarCodeTestActivity extends Activity {
- /** Called when the activity is first created. */
- private TextView resultTextView;
- private EditText qrStrEditText;
- private ImageView qrImgImageView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- resultTextView = (TextView) this.findViewById(R.id.tv_scan_result);
- qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string);
- qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image);
-
- Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
- scanBarCodeButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- //打開掃描界面掃描條形碼或二維碼
- Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
- startActivityForResult(openCameraIntent, 0);
- }
- });
-
- Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode);
- generateQRCodeButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- try {
- String contentString = qrStrEditText.getText().toString();
- if (!contentString.equals("")) {
- //根據字符串生成二維碼圖片並顯示在界面上,第二個參數為圖片的大小(350*350)
- Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
- qrImgImageView.setImageBitmap(qrCodeBitmap);
- }else {
- Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
- }
-
- } catch (WriterException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- });
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- //處理掃描結果(在界面上顯示)
- if (resultCode == RESULT_OK) {
- Bundle bundle = data.getExtras();
- String scanResult = bundle.getString("result");
- resultTextView.setText(scanResult);
- }
- }
- }
其中生成二維碼圖片的代碼在EncodingHandler.java中:
[java] view plaincopy
- public final class EncodingHandler {
- private static final int BLACK = 0xff000000;
-
- public static Bitmap createQRCode(String str,int widthAndHeight) throws WriterException {
- Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
- hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
- BitMatrix matrix = new MultiFormatWriter().encode(str,
- BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
- int width = matrix.getWidth();
- int height = matrix.getHeight();
- int[] pixels = new int[width * height];
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- if (matrix.get(x, y)) {
- pixels[y * width + x] = BLACK;
- }
- }
- }
- Bitmap bitmap = Bitmap.createBitmap(width, height,
- Bitmap.Config.ARGB_8888);
- bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
- return bitmap;
- }
- }
[java] view plain copy
- public final class EncodingHandler {
- private static final int BLACK = 0xff000000;
-
- public static Bitmap createQRCode(String str,int widthAndHeight) throws WriterException {
- Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
- hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
- BitMatrix matrix = new MultiFormatWriter().encode(str,
- BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
- int width = matrix.getWidth();
- int height = matrix.getHeight();
- int[] pixels = new int[width * height];
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- if (matrix.get(x, y)) {
- pixels[y * width + x] = BLACK;
- }
- }
- }
- Bitmap bitmap = Bitmap.createBitmap(width, height,
- Bitmap.Config.ARGB_8888);
- bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
- return bitmap;
- }
- }
最後是在哪裡對掃描結果進行解碼,進入CaptureActivity.java找到下面這個方法便可以對自己對結果進行操作:
[java] view plaincopy
- /**
- * Handler scan result
- * @param result
- * @param barcode
- */
- public void handleDecode(Result result, Bitmap barcode) {
- inactivityTimer.onActivity();
- playBeepSoundAndVibrate();
- String resultString = result.getText();
- //FIXME
- if (resultString.equals("")) {
- Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
- }else {
- // System.out.println("Result:"+resultString);
- Intent resultIntent = new Intent();
- Bundle bundle = new Bundle();
- bundle.putString("result", resultString);
- resultIntent.putExtras(bundle);
- this.setResult(RESULT_OK, resultIntent);
- }
- CaptureActivity.this.finish();
- }
[java] view plain copy
- /**
- * Handler scan result
- * @param result
- * @param barcode
- */
- public void handleDecode(Result result, Bitmap barcode) {
- inactivityTimer.onActivity();
- playBeepSoundAndVibrate();
- String resultString = result.getText();
- //FIXME
- if (resultString.equals("")) {
- Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
- }else {
- // System.out.println("Result:"+resultString);
- Intent resultIntent = new Intent();
- Bundle bundle = new Bundle();
- bundle.putString("result", resultString);
- resultIntent.putExtras(bundle);
- this.setResult(RESULT_OK, resultIntent);
- }
- CaptureActivity.this.finish();
- }
-