基於google Zxing實現二維碼、條碼掃描,仿微信二維碼掃描效果

來源:互聯網
上載者:User

轉載請註明出處:http://blog.csdn.net/xiaanming/article/details/10163203


瞭解二維碼這個東西還是從中,當時推出二維碼掃描功能,自己感覺挺新穎的,從一張圖片中掃一下竟然能直接加好友,不可思議啊,那時候還不瞭解二維碼,呵呵,然後做項目的時候,老闆說要加上二維碼掃描功能,然後自己的屁顛屁顛的去百度,google啥的,發現很多朋友都有介紹二維碼掃描的功能,然後我就跟著人家的介紹自己搞起了二維碼掃描功能,跟著人家的文章,很快我的項目就加入了掃描二維碼的功能,然後自己還很開心。


隨著的到來,二維碼越來越火爆,隨處能看到二維碼,比如商城裡面,肯德基,餐廳等等,對於二維碼掃描我們使用的是google的開源架構Zxing,我們可以去http://code.google.com/p/zxing/下載源碼和Jar包,之前我項目中的二維碼掃描功能只實現了掃描功能,其UI真的是其醜無比,一個好的應用軟體,其UI介面也要被福士所接納,不然人家就不會用你的軟體啦,所以說應用軟體功能和介面一樣都很重要,例如,相信UI被很多應用軟體所模仿,我也仿照掃描二維碼效果進行模仿,雖然沒有做的那麼精緻,但是效果還是可以的,所以將自己修改UI的代碼和掃描二維碼的代碼分享給大家,一是自己以後項目遇到同樣的功能直接拷貝來用,二是給還沒有加入二維碼功能的人一個參考,站在巨人的肩膀上,哈哈,我之前也是站在巨人的肩膀上加上此功能,接下來跟著我一步一步來實現此項功能,裡面去除了很多不必要的檔案


我們先看下項目的結構

  • 如果你項目也想加入此功能,你直接將com.mining.app.zxing.camera,com.mining.app.zxing.decoding,com.mining.app.zxing.view這三個包拷貝到你的項目中,然後引入相對應的資源進去,我也是從我的項目中直接引用過來的,包名都沒改呢,當然還需要引用Zxing.jar

  • com.example.qr_codescan包裡面有一個MipcaActivityCapture,也是直接引入我之前項目的代碼的,這個Activity主要處理掃描介面的類,比如,掃描成功有聲音和震動等等,主要關注裡面的handleDecode(Result
    result, Bitmap barcode)方法,掃描完成之後將掃描到的結果和二維碼的bitmap當初參數傳遞到handleDecode(Result result, Bitmap barcode)裡面,我們只需要在裡面寫出相對應的處理代碼即可,其他的地方都不用改得,我這裡處理掃描結果和掃描拍的照片

/** * 處理掃描結果 * @param result * @param barcode */public void handleDecode(Result result, Bitmap barcode) {inactivityTimer.onActivity();playBeepSoundAndVibrate();String resultString = result.getText();if (resultString.equals("")) {Toast.makeText(MipcaActivityCapture.this, "Scan failed!", Toast.LENGTH_SHORT).show();}else {Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString("result", resultString);bundle.putParcelable("bitmap", barcode);resultIntent.putExtras(bundle);this.setResult(RESULT_OK, resultIntent);}MipcaActivityCapture.this.finish();}

  • 我對MipcaActivityCapture介面的布局做了自己的改動,先看下,主要是用到FrameLayout,裡面嵌套RelativeLayout,裡面的圖片也是從裡面拿出來的,平常我看到需要什麼圖片就去裡面找,沒有美工的公司的程式員就是苦逼

布局代碼如下

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"        android:layout_height="fill_parent" >    <RelativeLayout        android:layout_width="fill_parent"        android:layout_height="fill_parent" >        <SurfaceView            android:id="@+id/preview_view"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:layout_gravity="center" />        <com.mining.app.zxing.view.ViewfinderView            android:id="@+id/viewfinder_view"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />        <include            android:id="@+id/include1"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:layout_alignParentTop="true"            layout="@layout/activity_title" />    </RelativeLayout></FrameLayout>

在裡面我將介面上面部分寫在另一個布局裡面,然後include進來,因為這個activity_title在我項目裡面還供其他的Activity使用,我也是直接拷貝出來的

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:background="@drawable/mmtitle_bg_alpha" >    <Button        android:id="@+id/button_back"        android:layout_width="75.0dip"        android:text="返回"        android:background="@drawable/mm_title_back_btn"        android:textColor="@android:color/white"        android:layout_height="wrap_content"        android:layout_centerVertical="true"        android:layout_marginLeft="2dip" />    <TextView        android:id="@+id/textview_title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/button_back"        android:layout_alignBottom="@+id/button_back"        android:layout_centerHorizontal="true"        android:gravity="center_vertical"        android:text="二維碼掃描"        android:textColor="@android:color/white"        android:textSize="18sp" /></RelativeLayout>

  • 在我這個demo裡面,有一個主介面MainActivity,裡面一個Button, 一個ImageView和一個TextView,點擊Button進入到二維碼掃描介面,當掃描OK的時候,回到主介面,將掃描的結果顯示到TextView,將圖片顯示到ImageView裡面,然後你可以不處理圖片,我這裡隨帶的加片,主介面的布局很簡單如下
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#ffe1e0de" >    <Button        android:id="@+id/button1"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:text="掃描二維碼" />    <TextView        android:id="@+id/result"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_below="@+id/button1"        android:lines="2"        android:gravity="center_horizontal"        android:textColor="@android:color/black"        android:textSize="16sp" />    <ImageView        android:id="@+id/qrcode_bitmap"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_alignParentLeft="true"        android:layout_below="@+id/result"/></RelativeLayout>
  • MainActivity裡面的代碼如下,裡面的功能在上面已經說了

package com.example.qr_codescan;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;public class MainActivity extends Activity {private final static int SCANNIN_GREQUEST_CODE = 1;/** * 顯示掃描結果 */private TextView mTextView ;/** * 顯示掃描拍的圖片 */private ImageView mImageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mTextView = (TextView) findViewById(R.id.result); mImageView = (ImageView) findViewById(R.id.qrcode_bitmap);//點擊按鈕跳轉到二維碼掃描介面,這裡用的是startActivityForResult跳轉//掃描完了之後調到該介面Button mButton = (Button) findViewById(R.id.button1);mButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();intent.setClass(MainActivity.this, MipcaActivityCapture.class);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);startActivityForResult(intent, SCANNIN_GREQUEST_CODE);}});}@Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        switch (requestCode) {case SCANNIN_GREQUEST_CODE:if(resultCode == RESULT_OK){Bundle bundle = data.getExtras();//顯示掃描到的內容mTextView.setText(bundle.getString("result"));//顯示mImageView.setImageBitmap((Bitmap) data.getParcelableExtra("bitmap"));}break;}    }}

  • 上面的代碼還是比較簡單,但是要想做出像那樣只的掃描框,緊緊上面的代碼是沒有那種效果的,我們必須重寫com.mining.app.zxing.view包下面的ViewfinderView類,裡面的都是用的圖片,我是自己畫出來的,代碼注釋的比較清楚,大家直接看代碼吧,相信你能理解的,如果你要修改掃描框的大小,去CameraManager類裡面修改

/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.mining.app.zxing.view;import java.util.Collection;import java.util.HashSet;import android.content.Context;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Typeface;import android.util.AttributeSet;import android.view.View;import com.example.qr_codescan.R;import com.google.zxing.ResultPoint;import com.mining.app.zxing.camera.CameraManager;/** * This view is overlaid on top of the camera preview. It adds the viewfinder * rectangle and partial transparency outside it, as well as the laser scanner * animation and result points. *  */public final class ViewfinderView extends View {private static final String TAG = "log";/** * 重新整理介面的時間 */private static final long ANIMATION_DELAY = 10L;private static final int OPAQUE = 0xFF;/** * 四個綠色邊角對應的長度 */private int ScreenRate;/** * 四個綠色邊角對應的寬度 */private static final int CORNER_WIDTH = 10;/** * 掃描框中的中間線的寬度 */private static final int MIDDLE_LINE_WIDTH = 6;/** * 掃描框中的中間線的與掃描框左右的間隙 */private static final int MIDDLE_LINE_PADDING = 5;/** * 中間那條線每次重新整理移動的距離 */private static final int SPEEN_DISTANCE = 5;/** * 手機的螢幕密度 */private static float density;/** * 字型大小 */private static final int TEXT_SIZE = 16;/** * 字型距離掃描框下面的距離 */private static final int TEXT_PADDING_TOP = 30;/** * 畫筆對象的引用 */private Paint paint;/** * 中間滑動線的最頂端位置 */private int slideTop;/** * 中間滑動線的最底端位置 */private int slideBottom;private Bitmap resultBitmap;private final int maskColor;private final int resultColor;private final int resultPointColor;private Collection<ResultPoint> possibleResultPoints;private Collection<ResultPoint> lastPossibleResultPoints;boolean isFirst;public ViewfinderView(Context context, AttributeSet attrs) {super(context, attrs);density = context.getResources().getDisplayMetrics().density;//將像素轉換成dpScreenRate = (int)(20 * density);paint = new Paint();Resources resources = getResources();maskColor = resources.getColor(R.color.viewfinder_mask);resultColor = resources.getColor(R.color.result_view);resultPointColor = resources.getColor(R.color.possible_result_points);possibleResultPoints = new HashSet<ResultPoint>(5);}@Overridepublic void onDraw(Canvas canvas) {//中間的掃描框,你要修改掃描框的大小,去CameraManager裡面修改Rect frame = CameraManager.get().getFramingRect();if (frame == null) {return;}//初始化中間線滑動的最上邊和最下邊if(!isFirst){isFirst = true;slideTop = frame.top;slideBottom = frame.bottom;}//擷取螢幕的寬和高int width = canvas.getWidth();int height = canvas.getHeight();paint.setColor(resultBitmap != null ? resultColor : maskColor);//畫出掃描框外面的陰影部分,共四個部分,掃描框的上面到螢幕上面,掃描框的下面到螢幕下面//掃描框的左邊面到螢幕左邊,掃描框的右邊到螢幕右邊canvas.drawRect(0, 0, width, frame.top, paint);canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,paint);canvas.drawRect(0, frame.bottom + 1, width, height, paint);if (resultBitmap != null) {// Draw the opaque result bitmap over the scanning rectanglepaint.setAlpha(OPAQUE);canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);} else {//畫掃描框邊上的角,總共8個部分paint.setColor(Color.GREEN);canvas.drawRect(frame.left, frame.top, frame.left + ScreenRate,frame.top + CORNER_WIDTH, paint);canvas.drawRect(frame.left, frame.top, frame.left + CORNER_WIDTH, frame.top+ ScreenRate, paint);canvas.drawRect(frame.right - ScreenRate, frame.top, frame.right,frame.top + CORNER_WIDTH, paint);canvas.drawRect(frame.right - CORNER_WIDTH, frame.top, frame.right, frame.top+ ScreenRate, paint);canvas.drawRect(frame.left, frame.bottom - CORNER_WIDTH, frame.left+ ScreenRate, frame.bottom, paint);canvas.drawRect(frame.left, frame.bottom - ScreenRate,frame.left + CORNER_WIDTH, frame.bottom, paint);canvas.drawRect(frame.right - ScreenRate, frame.bottom - CORNER_WIDTH,frame.right, frame.bottom, paint);canvas.drawRect(frame.right - CORNER_WIDTH, frame.bottom - ScreenRate,frame.right, frame.bottom, paint);//繪製中間的線,每次重新整理介面,中間的線往下移動SPEEN_DISTANCEslideTop += SPEEN_DISTANCE;if(slideTop >= frame.bottom){slideTop = frame.top;}canvas.drawRect(frame.left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH/2, frame.right - MIDDLE_LINE_PADDING,slideTop + MIDDLE_LINE_WIDTH/2, paint);//畫掃描框下面的字paint.setColor(Color.WHITE);paint.setTextSize(TEXT_SIZE * density);paint.setAlpha(0x40);paint.setTypeface(Typeface.create("System", Typeface.BOLD));canvas.drawText(getResources().getString(R.string.scan_text), frame.left, (float) (frame.bottom + (float)TEXT_PADDING_TOP *density), paint);Collection<ResultPoint> currentPossible = possibleResultPoints;Collection<ResultPoint> currentLast = lastPossibleResultPoints;if (currentPossible.isEmpty()) {lastPossibleResultPoints = null;} else {possibleResultPoints = new HashSet<ResultPoint>(5);lastPossibleResultPoints = currentPossible;paint.setAlpha(OPAQUE);paint.setColor(resultPointColor);for (ResultPoint point : currentPossible) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 6.0f, paint);}}if (currentLast != null) {paint.setAlpha(OPAQUE / 2);paint.setColor(resultPointColor);for (ResultPoint point : currentLast) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 3.0f, paint);}}//只重新整理掃描框的內容,其他地方不重新整理postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,frame.right, frame.bottom);}}public void drawViewfinder() {resultBitmap = null;invalidate();}/** * Draw a bitmap with the result points highlighted instead of the live * scanning display. *  * @param barcode *            An image of the decoded barcode. */public void drawResultBitmap(Bitmap barcode) {resultBitmap = barcode;invalidate();}public void addPossibleResultPoint(ResultPoint point) {possibleResultPoints.add(point);}}

上面的代碼中,中間那根線是用的圖片,我這裡是畫的,如果你想更加模擬點就將下面的代碼

canvas.drawRect(frame.left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH/2, frame.right - MIDDLE_LINE_PADDING,slideTop + MIDDLE_LINE_WIDTH/2, paint);

改成

Rect lineRect = new Rect();lineRect.left = frame.left;lineRect.right = frame.right;lineRect.top = slideTop;lineRect.bottom = slideTop + 18;canvas.drawBitmap(((BitmapDrawable)(getResources().getDrawable(R.drawable.qrcode_scan_line))).getBitmap(), null, lineRect, paint);

那條掃描線自己去裡面找一下,我貼出來的失真了,下載apk,將尾碼名改成zip,然後解壓就行了

畫掃描框下面字型的代碼需要修改下,這樣子能根據字型自動排文在中間,如果字太長我沒有處理,那個要自動換行,你可以自行處理

paint.setColor(Color.WHITE);  paint.setTextSize(TEXT_SIZE * density);  paint.setAlpha(0x40);  paint.setTypeface(Typeface.DEFAULT_BOLD); String text = getResources().getString(R.string.R.string.scan_text);float textWidth = paint.measureText(text);canvas.drawText(text, (width - textWidth)/2, (float) (frame.bottom + (float)TEXT_PADDING_TOP *density), paint)

運行介面,其中中間的那根綠色的線會上下移動,跟的效果差不多,當然運行你還需要相對應的許可權問題,有興趣的朋友可以去下載demo

從8點多寫這篇部落格寫到現在,看起來這麼點字,但實際上還是比較耗時間的,如果你覺得這篇文章對你有協助,你就頂一下,哈哈,洗澡睡覺去了,上面的項目中還有一些資源檔我沒有貼出來,想要看效果可以下載源碼


項目源碼,點擊下載

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.