1. 程式人生 > >《打造極致二維碼掃描系列》 -- ZXing開發詳解

《打造極致二維碼掃描系列》 -- ZXing開發詳解

什麼是ZXing?

在Android平臺做過二維碼相關模組的肯定都熟知ZXing開源專案,ZXing是一個開源Java類庫用於解析多種格式的1D/2D條形碼。目標是能夠對QR編碼、Data Matrix、UPC的1D條形碼進行解碼。 其提供了多種平臺下的客戶端包括:J2ME、J2SE和Android。其GitHub地址是:傳送門

ZXing專案裡面程式碼很多,實現的功能也很多,我們的應用只需要剝離其中的掃描模組即可,再多一點也就是生成二維碼的功能;接下來我們就一起來精簡ZXing專案,最終形成一個小的Demo案例,當然江湖上已經有過N多種版本的ZXing精簡專案,什麼橫屏改豎屏,繪製掃描介面,開啟閃光燈等等,並且許多都是基於ZXing2.3.0來做精簡的,後續有許多更新的版本,包括自動對焦,Camera管理,bug修復等等新功能;筆者使用的是ZXing3.1.0版本,這裡需要說明的就是我的這版Demo絕對是江湖上面還沒有出現的,也算是一點點小小的創新把,那就是去除ZXing專案中惱人的ViewFinderView的繪製,使用XML佈局掃描介面,新增掃描動畫,精確計算掃描區域,怎麼樣?是不是很心動,很想繼續往下看呢?那就跟我一起做起來把!!!生氣

克隆ZXing專案到本地

開啟Git Base,敲入命令: git clone https://github.com/zxing/zxing.git

如下圖所示:


當然你也可以直接點選Download ZIP


整理ZXing程式碼

開啟ZXing專案的資料夾,可以看到如下檔案:


其中我們主要關注2個資料夾裡的內容: 

1. core : ZXing專案的核心程式碼,可以新建一個Java工程,然後export成jar來呼叫。如下圖所示:


免打包即可獲得的zxing-3.1.0.jar  猛戳下載 

2. android : Android示例工程程式碼,成功執行之後就是一個專業的掃碼應用了。如下圖所示:


免引入免整理的zxing原始工程 ZXingRawProject  猛戳下載

這麼為你著想,還不感謝我麼??!!偷笑得意

但是這樣就讓你滿足了,那怎麼可以說是極致二維碼掃描呢,有木有感覺ZXing的掃描框的繪製很不爽啊?自定義的View繪製的很醜,多螢幕適配的時候還經常不相容,原始專案還是橫屏模式的,目前大家都習慣豎屏掃描呢。怎麼辦?別怕,我來告訴你,我要將ViewFinderView砍掉,使用xml介面佈局,新增掃描動畫,最終一樣準確無誤的掃描到二維碼資料,只需要對準,是的,毫釐不差的對準就可以了。

精簡ZXing程式碼,打造極致掃描

1. 去掉ZXing中一些和掃描無關的程式碼,最終留下的程式碼結構如下圖所示,最關鍵的是你看不到ViewFinderView 了。爽了把,笑了吧,樂了吧。大笑


2. 佈局掃描介面,xml程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="vertical" >

    <SurfaceView
        android:id="@+id/capture_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:id="@+id/capture_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ImageView
            android:id="@+id/capture_mask_top"
            android:layout_width="match_parent"
            android:layout_height="120dp"
            android:layout_alignParentTop="true"
            android:background="@drawable/shadow" />

        <RelativeLayout
            android:id="@+id/capture_crop_view"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_below="@id/capture_mask_top"
            android:layout_centerHorizontal="true"
            android:background="@drawable/qr_code_bg" >

            <ImageView
                android:id="@+id/capture_scan_line"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_marginBottom="5dp"
                android:layout_marginTop="5dp"
                android:src="@drawable/scan_line" />
        </RelativeLayout>

        <ImageView
            android:id="@+id/capture_mask_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_below="@id/capture_crop_view"
            android:background="@drawable/shadow" />

        <ImageView
            android:id="@+id/capture_mask_left"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_above="@id/capture_mask_bottom"
            android:layout_alignParentLeft="true"
            android:layout_below="@id/capture_mask_top"
            android:layout_toLeftOf="@id/capture_crop_view"
            android:background="@drawable/shadow" />

        <ImageView
            android:id="@+id/capture_mask_right"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_above="@id/capture_mask_bottom"
            android:layout_alignParentRight="true"
            android:layout_below="@id/capture_mask_top"
            android:layout_toRightOf="@id/capture_crop_view"
            android:background="@drawable/shadow" />
    </RelativeLayout>

</RelativeLayout>

3. 計算擷取區域(我認為你已經看了我的貼心註解內容了,否則。。。我不白囉嗦了麼?鄙視

貼心註解: 如果你沒有看上一篇ZBar掃描中關於掃描區域計算的解釋,那趕緊回去,咱不能急,看完再來接上,否則你會不理解的!傳送門

	private void initCrop() {
		int cameraWidth = cameraManager.getCameraResolution().y;
		int cameraHeight = cameraManager.getCameraResolution().x;

		/** 獲取佈局中掃描框的位置資訊 */
		int[] location = new int[2];
		scanCropView.getLocationInWindow(location);

		int cropLeft = location[0];
		int cropTop = location[1] - getStatusBarHeight();

		int cropWidth = scanCropView.getWidth();
		int cropHeight = scanCropView.getHeight();

		/** 獲取佈局容器的寬高 */
		int containerWidth = scanContainer.getWidth();
		int containerHeight = scanContainer.getHeight();

		/** 計算最終擷取的矩形的左上角頂點x座標 */
		int x = cropLeft * cameraWidth / containerWidth;
		/** 計算最終擷取的矩形的左上角頂點y座標 */
		int y = cropTop * cameraHeight / containerHeight;

		/** 計算最終擷取的矩形的寬度 */
		int width = cropWidth * cameraWidth / containerWidth;
		/** 計算最終擷取的矩形的高度 */
		int height = cropHeight * cameraHeight / containerHeight;

		/** 生成最終的擷取的矩形 */
		mCropRect = new Rect(x, y, width + x, height + y);
	}

4. 打完收工,驗收效果


5. 完整專案程式碼: 猛戳下載

下一篇將介紹開篇部落格中所說的一個完整的二維碼一維碼掃描的簡單的APP