search
HomeJavajavaTutorialAndroid implements various QR code scanning effects based on google Zxing

With the arrival of WeChat, QR codes are becoming more and more popular. You can see QR codes everywhere, such as in shopping malls, KFC, restaurants, etc. For QR code scanning we use Google’s open source framework Zxing. We can go to http://code.google.com/p/zxing/ to download the source code and Jar package. Before, the QR code scanning function in my project only implemented the scanning function, and its UI was really ugly. A good The UI interface of an application software must be accepted by the public, otherwise people will not use your software. Therefore, application software functions are as important as the interface. For example, WeChat, I believe that the WeChat UI has been imitated by many application software. I also imitated the effect of scanning the QR code on WeChat. Although it is not as refined as WeChat does, the effect is still good, so I will share with you the code for modifying the UI and the code for scanning the QR code. First, I will encounter problems in future projects. Directly copy and use the same function. The second is to give a reference to those who have not added the QR code function. Standing on the shoulders of giants, haha. I also stood on the shoulders of giants before adding this function. Next, follow I implemented this function step by step, removing many unnecessary files

Let’s look at the structure of the project first

Android基于google Zxing实现各类二维码扫描效果

If you want to do the same for your project To add this function, you directly copy the three packages com.mining.app.zxing.camera, com.mining.app.zxing.decoding, and com.mining.app.zxing.view to your project, and then introduce the relevant When entering the corresponding resources, I quoted them directly from my project. The package name has not been changed. Of course, I also need to quote Zxing.jar

com.example.qr_codescan package, which contains a MipcaActivityCapture , it also directly introduces the code of my previous project. This Activity mainly handles the scanning interface classes. For example, if the scan is successful, there will be sounds and vibrations, etc. It mainly focuses on the handleDecode (Result result, Bitmap barcode) method inside. After the scan is completed, the scan will The initial parameters of the result and the bitmap of the QR code are passed to handleDecode (Result result, Bitmap barcode). We only need to write the corresponding processing code in it. There is no need to change other places. I will handle the scanning here. Results and photos taken by scanning

/** 
 * 处理扫描结果 
 * @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(); 
}

I made my own changes to the layout of the MipcaActivityCapture interface. Let’s take a look at the renderings first. I mainly use FrameLayout, with RelativeLayout nested inside.

The layout code is as follows

<?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>

In it, I wrote the upper part of the interface in another layout, and then included it, because this activity_title is also used by other activities in my project, and I do the same Directly copied

<?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>

In my demo, there is a main interface MainActivity with a Button, an ImageView and a TextView. Click the Button to enter the QR code scanning interface. When the scan is OK, return Go to the main interface, display the scan results in TextView, and display the picture in ImageView. Then you don’t need to process the picture. I will add the picture here. The layout of the main interface is very simple as follows

<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>

In MainActivity The code is as follows. The functions inside have been mentioned above.

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; 
    
  
  @Override
  protected 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() { 
        
      @Override
      public 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; 
    } 
  }   
  
}

The above code is relatively simple, but if you want to make a scanning box like WeChat, the above code will not have that effect. , we must rewrite the ViewfinderView class under the com.mining.app.zxing.view package. The pictures in WeChat are all used. I drew them myself. The code comments are relatively clear. You can just look at the code. I believe you It's understandable. If you want to modify the size of the scanning frame, go to the CameraManager class and modify

/* 
 * 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 
 * 
 *   * 
 * 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; 
    //将像素转换成dp 
    ScreenRate = (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); 
  } 
  
  @Override 
  public 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 rectangle 
      paint.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_DISTANCE 
      slideTop += 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); 
  } 
  
}

In the above code, the middle line is the picture used by WeChat. I drew it here. If you want to make it more For the simulation point, change the following code

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

to

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);

Go to WeChat to find the scan line yourself After a while, the picture I posted is distorted. Download the WeChat apk, change the suffix name to zip, and then unzip it.
The code for the font under the drawing scanning box needs to be modified, so that it can be automatically arranged in the middle according to the font. If the words It’s too long and I haven’t processed it. It requires automatic line wrapping. You can handle it by yourself

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)

Take a screenshot of the running interface. The green line in the middle will move up and down, which is similar to the effect of WeChat. Of course, you still need the corresponding permissions to run it.

Android基于google Zxing实现各类二维码扫描效果

#The above is the entire content of this article. I hope it will be helpful for everyone to learn Android software programming.

For more Android-based articles on realizing various QR code scanning effects based on google Zxing, please pay attention to the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
JVM performance vs other languagesJVM performance vs other languagesMay 14, 2025 am 12:16 AM

JVM'sperformanceiscompetitivewithotherruntimes,offeringabalanceofspeed,safety,andproductivity.1)JVMusesJITcompilationfordynamicoptimizations.2)C offersnativeperformancebutlacksJVM'ssafetyfeatures.3)Pythonisslowerbuteasiertouse.4)JavaScript'sJITisles

Java Platform Independence: Examples of useJava Platform Independence: Examples of useMay 14, 2025 am 12:14 AM

JavaachievesplatformindependencethroughtheJavaVirtualMachine(JVM),allowingcodetorunonanyplatformwithaJVM.1)Codeiscompiledintobytecode,notmachine-specificcode.2)BytecodeisinterpretedbytheJVM,enablingcross-platformexecution.3)Developersshouldtestacross

JVM Architecture: A Deep Dive into the Java Virtual MachineJVM Architecture: A Deep Dive into the Java Virtual MachineMay 14, 2025 am 12:12 AM

TheJVMisanabstractcomputingmachinecrucialforrunningJavaprogramsduetoitsplatform-independentarchitecture.Itincludes:1)ClassLoaderforloadingclasses,2)RuntimeDataAreafordatastorage,3)ExecutionEnginewithInterpreter,JITCompiler,andGarbageCollectorforbytec

JVM: Is JVM related to the OS?JVM: Is JVM related to the OS?May 14, 2025 am 12:11 AM

JVMhasacloserelationshipwiththeOSasittranslatesJavabytecodeintomachine-specificinstructions,managesmemory,andhandlesgarbagecollection.ThisrelationshipallowsJavatorunonvariousOSenvironments,butitalsopresentschallengeslikedifferentJVMbehaviorsandOS-spe

Java: Write Once, Run Anywhere (WORA) - A Deep Dive into Platform IndependenceJava: Write Once, Run Anywhere (WORA) - A Deep Dive into Platform IndependenceMay 14, 2025 am 12:05 AM

Java implementation "write once, run everywhere" is compiled into bytecode and run on a Java virtual machine (JVM). 1) Write Java code and compile it into bytecode. 2) Bytecode runs on any platform with JVM installed. 3) Use Java native interface (JNI) to handle platform-specific functions. Despite challenges such as JVM consistency and the use of platform-specific libraries, WORA greatly improves development efficiency and deployment flexibility.

Java Platform Independence: Compatibility with different OSJava Platform Independence: Compatibility with different OSMay 13, 2025 am 12:11 AM

JavaachievesplatformindependencethroughtheJavaVirtualMachine(JVM),allowingcodetorunondifferentoperatingsystemswithoutmodification.TheJVMcompilesJavacodeintoplatform-independentbytecode,whichittheninterpretsandexecutesonthespecificOS,abstractingawayOS

What features make java still powerfulWhat features make java still powerfulMay 13, 2025 am 12:05 AM

Javaispowerfulduetoitsplatformindependence,object-orientednature,richstandardlibrary,performancecapabilities,andstrongsecurityfeatures.1)PlatformindependenceallowsapplicationstorunonanydevicesupportingJava.2)Object-orientedprogrammingpromotesmodulara

Top Java Features: A Comprehensive Guide for DevelopersTop Java Features: A Comprehensive Guide for DevelopersMay 13, 2025 am 12:04 AM

The top Java functions include: 1) object-oriented programming, supporting polymorphism, improving code flexibility and maintainability; 2) exception handling mechanism, improving code robustness through try-catch-finally blocks; 3) garbage collection, simplifying memory management; 4) generics, enhancing type safety; 5) ambda expressions and functional programming to make the code more concise and expressive; 6) rich standard libraries, providing optimized data structures and algorithms.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Atom editor mac version download

Atom editor mac version download

The most popular open source editor