Android开发实现模仿360二维码扫描功能实例详解

本文实例讲述了Android开发实现模仿360二维码扫描功能的方法。分享给大家供大家参考,具体如下:

一、效果图:

二、框架搭建

1、首先,下载最新zxing开源项目。 下载地址:http://code.google.com/p/zxing/

或 点击此处本站下载

2、分析项目结构,明确扫描框架需求。在zxing中,有很多其他的功能,项目结构比较复杂;针对二维码QRCode扫描,我们需要几个包:

(1)com.google.zxing.client.android.Camera 基于Camera调用以及参数配置,核心包
(2)DecodeFormatManager、DecodeThread、DecodeHandler 基于解码格式、解码线程、解码结果处理的解码类
(3)ViewfinderView、ViewfinderResultPointCallBack 基于取景框视图定义的View类
(4)CaptureActivity、CaptureActivityHandler 基于扫描Activity以及扫描结果处理的Capture类
(5)InactivityTimer、BeepManager、FinishListener 基于休眠、声音、退出的辅助管理类
(6)Intents、IntentSource、PrefrencesActivity 基于常量存储的常量类

3、新建工程,添加如下权限permission:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FLASHLIGHT" />

4、 添加core.jar文件,并BuildPath;将上述类或包加入工程后,会报一系列错误,原因有几点:

(1)资源文件缺乏,将zxing下需要的资源文件copy到新工程下
(2)版本兼容问题,zxing下很多技术都是使用4.0版本及以上,集成到低版本之后,须做相应改动,详情参照项目源码
(3)包结构引用问题,需要重新导入包引用

5、最后框架

三、具体实现

1、创建MainActivity用于跳转到扫描页面

/**
 * 二维码扫描
 * @Project  App_ZXing
 * @Package  com.android.scan
 * @author   chenlin
 * @version  1.0
 * @Date    2014年3月6日
 */
public class MainActivity extends Activity {
  private Button mBtnScan;
  private Button mBtnBack;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mBtnBack = (Button) findViewById(R.id.btn_back);
    mBtnBack.setVisibility(View.GONE);
    mBtnScan = (Button) findViewById(R.id.btn_scan);
    mBtnScan.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        startActivity(new Intent(MainActivity.this, ScanActivity.class));
      }
    });
  }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<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" >
  <Button
    android:id="@+id/btn_scan"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:textColor="@color/white"
    android:padding="20dp"
    android:background="@drawable/btn_scan_result"
    android:text="扫一扫" />
  <include
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_alignParentTop="true"
      layout="@layout/activity_scan_title" />
</RelativeLayout>

2、扫描页面

/**
 * 条形码扫描
 *
 * @Project App_ZXing
 * @Package com.android.scan
 * @author chenlin
 * @version 1.0
 * @Date 2014年3月6日
 */
public class ScanActivity extends Activity implements Callback {
  private static final float BEEP_VOLUME = 0.10f;
  protected static final String RESULT_TEXT = "result";
  protected static final String RESULT_BITMAP = "bitmap";
  /** 扫描界面 */
  private SurfaceView mSurfaceView;
  /** 自定义的View,就是我们看见的拍摄时中间的框框了 */
  private ViewfinderView mFindView;
  /** 解码处理类,负责调用另外的线程进行解码。 */
  private CaptureActivityHandler mHandler;
  /** 判断是否创建了SurfaceView */
  private boolean hasSurface;
  /** decodeFormats 条形码,二维码等的集合 */
  private Vector<BarcodeFormat> mDecodeFormats;
  /** 字符编码 */
  private String characterSet;
  /** 定时器 */
  private InactivityTimer inactivityTimer;
  /** 媒体播放器 */
  private MediaPlayer mediaPlayer;
  /** 是否播放声音 */
  private boolean playBeep;
  /** 是否震动 */
  private boolean vibrate;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_scan);
    init();
  }
  /**
   * 初始化
   */
  private void init() {
    mSurfaceView = (SurfaceView) findViewById(R.id.preview_view);
    mFindView = (ViewfinderView) findViewById(R.id.viewfinder_view);
    CameraManager.init(getApplication());
    hasSurface = false;
    inactivityTimer = new InactivityTimer(this);
  }
  /**
   * 暂停后恢复时处理内容
   */
  @SuppressWarnings("all")
  @Override
  protected void onResume() {
    super.onResume();
    // 先重新获得holder
    SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
    if (hasSurface) {
      initCamera(surfaceHolder);
    } else {
      surfaceHolder.addCallback(this);
      surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
    mDecodeFormats = null;
    characterSet = null;
    playBeep = true;
    AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
    // 如果当前是铃音模式,则继续准备下面的 蜂鸣提示音操作,如果是静音或者震动模式。就不要继续了。因为用户选择了无声的模式,我们就也不要出声了。
    if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
      playBeep = false;
    }
    // 初始化播放声音
    initBeepSound();
    //播放
    vibrate = true;
  }
  @Override
  protected void onPause() {
    super.onPause();
    if (mHandler != null) {
      mHandler.quitSynchronously();
      mHandler = null;
    }
    // 关闭摄像头信息
    CameraManager.get().closeDriver();
  }
  @Override
  protected void onDestroy() {
    // 关闭定时器
    inactivityTimer.shutdown();
    super.onDestroy();
  }
  /**
   * 处理扫描结果
   *
   * @param result
   * @param barcode
   */
  public void handleDecode(Result result, Bitmap barcode) {
    // 添加定时器
    inactivityTimer.onActivity();
    // 响铃和震动
    playBeepSoundAndVibrate();
    String resultString = result.getText();
    if (TextUtils.isEmpty(resultString)) {
      ToastUtil.show(this, "扫描失败");
      ScanActivity.this.finish();
    } else {
      //扫描完成后传递结果
      Intent resultIntent = new Intent();
      resultIntent.setClass(ScanActivity.this, ScanResultActivity.class);
      resultIntent.putExtra(RESULT_TEXT, resultString);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      barcode.compress(Bitmap.CompressFormat.PNG, 100, baos);
      byte[] bitmapByte = baos.toByteArray();
      resultIntent.putExtra(RESULT_BITMAP, bitmapByte);
      startActivity(resultIntent);
      overridePendingTransition(R.anim.activity_in_from_rigth, R.anim.activity_out_to_scale);
      ScanActivity.this.finish();
    }
  }
  private void initCamera(SurfaceHolder surfaceHolder) {
    try {
      CameraManager.get().openDriver(surfaceHolder);
    } catch (IOException ioe) {
      return;
    } catch (RuntimeException e) {
      return;
    }
    if (mHandler == null) {
      mHandler = new CaptureActivityHandler(this, mDecodeFormats, characterSet);
    }
  }
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  }
  /**
   * 在视图创建的时候初始化摄像头
   */
  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    if (!hasSurface) {
      hasSurface = true;
      initCamera(holder);
    }
  }
  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    hasSurface = false;
  }
  public ViewfinderView getViewfinderView() {
    return mFindView;
  }
  public Handler getHandler() {
    return mHandler;
  }
  public void drawViewfinder() {
    mFindView.drawViewfinder();
  }
  /**
   * 初始化声音资源
   */
  private void initBeepSound() {
    // 如果要播放声音并且没有播放器时
    if (playBeep && mediaPlayer == null) {
      // 设置声道流格式为音乐
      setVolumeControlStream(AudioManager.STREAM_MUSIC);
      mediaPlayer = new MediaPlayer();
      mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
      // 设置声音完成后监听
      mediaPlayer.setOnCompletionListener(beepListener);
      // 设定数据源,并准备播放
      AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
      try {
        mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
        file.close();
        mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);// 设置音量
        mediaPlayer.prepare();
      } catch (IOException e) {
        mediaPlayer = null;
      }
    }
  }
  private static final long VIBRATE_DURATION = 200L;
  /**
   * 响铃和震动
   */
  private void playBeepSoundAndVibrate() {
    if (playBeep && mediaPlayer != null) {
      mediaPlayer.start();
    }
    if (vibrate) {
      Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
      // 震动一次
      vibrator.vibrate(VIBRATE_DURATION);
      // 第一个参数,指代一个震动的频率数组。每两个为一组,每组的第一个为等待时间,第二个为震动时间。
      // 比如 [2000,500,100,400],会先等待2000毫秒,震动500,再等待100,震动400
      // 第二个参数,repest指代从 第几个索引(第一个数组参数) 的位置开始循环震动。
      // 会一直保持循环,我们需要用 vibrator.cancel()主动终止
      // vibrator.vibrate(new long[]{300,500},0);
    }
  }
  /**
   * 注册事件。当播放完毕一次后,重新指向流文件的开头,以准备下次播放。
   */
  private final MediaPlayer.OnCompletionListener beepListener = new MediaPlayer.OnCompletionListener() {
    public void onCompletion(MediaPlayer mediaPlayer) {
      mediaPlayer.seekTo(0);
    }
  };
}

布局文件

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

3、结果页面

/**
 *
 * @Project App_ZXing
 * @Package com.android.scan
 * @author chenlin
 * @version 1.0
 * @Date 2014年3月6日
 * @Note TODO
 */
public class ScanResultActivity extends Activity {
  private EditText mEtScan;
  private Button mBtnBack;
  private Button mBtnCopy;
  private ImageView mImageView;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_scan_result);
    initViews();
    init();
  }
  private void init() {
    final String result = getIntent().getStringExtra(ScanActivity.RESULT_TEXT);
    mEtScan.setText(result);
    final ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
    mBtnBack.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ScanResultActivity.this.finish();
      }
    });
    mBtnCopy.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        if (result!=null) {
          ClipData myClip = ClipData.newPlainText("text", result);
          cm.setPrimaryClip(myClip);
        }
      }
    });
    //设置图片信息
    byte[] imgByte = getIntent().getByteArrayExtra(ScanActivity.RESULT_BITMAP);
    if (imgByte != null) {
      Drawable drawable = BitmapUtil.byte2Drawable(imgByte);
      if (drawable != null) {
        mImageView.setImageDrawable(drawable);
      }
    }
  }
  // public void paste(View view){
  // ClipData abc = myClipboard.getPrimaryClip();
  // ClipData.Item item = abc.getItemAt(0);
  // String text = item.getText().toString();
  // pasteField.setText(text);
  // Toast.makeText(getApplicationContext(), "Text Pasted",
  // Toast.LENGTH_SHORT).show();
  // }
  private void initViews() {
    mEtScan = (EditText) findViewById(R.id.et_scan_result);
    mBtnBack = (Button) findViewById(R.id.btn_back);
    mBtnCopy = (Button) findViewById(R.id.btn_copy);
  }
}

四、代码下载

完整实例代码点击此处本站下载

PS:这里再为大家推荐一款二维码在线生成工具供大家参考使用:

在线生成二维码工具(加强版)
http://tools.jb51.net/transcoding/jb51qrcode

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android开发入门与进阶教程》、《Android数据库操作技巧总结》、《Android编程之activity操作技巧总结》、《Android文件操作技巧汇总》、《Android资源操作技巧汇总》、《Android视图View技巧总结》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

(0)

相关推荐

  • Android基于zxing的二维码(网格)扫描 仿支付宝网格扫描

    前言:对于二维码扫描我们使用的是开源框架Zxing或者Zbar,这里使用基于zxing的二维码扫描,类似支付宝网格扫描. 二维码原理介绍: 二维码是用某种特定的几何图形按一定的规律在平面上分布的黑白相间的图形记录数据符号信息的,在代码编制上巧妙的利用构成计算机内部逻辑基础的0/1比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图像输入设备或光电扫描设备自动识读以实现信息自动处理:二维码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息. 效果: 真机

  • Android实现二维码扫描并登陆网页

    之前写过一个二维码扫描demo,用的Zxing的框架,点击下载,后续扫描二维码中出现一些问题,比如解决压缩图片,调整扫描窗口大小等等.后续单位要求做扫描登录实现,发现难点就是怎么知道你扫描的是这台电脑,后台必须获取到(后台技术的问题)然后把这个参数给我,再传递到后台,后台判断登录即可.这样自己扫描后直接传递个参数就可以实现登录了. 效果如下: 大概代码实现:扫描跳转: //扫描登录a case R.id.tv_more_qr: if (PventQuickClick.isFastDoubleCl

  • Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题

    先给大家展示下效果图: 扫描内容是下面这张,二维码是用zxing库生成的 由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java package com.zxing.activity; import java.io.IOException; import java.util.Vector; import android.app.Activity; import android.content.Intent; import

  • Android实现二维码扫描和生成的简单方法

    这里简单介绍一下ZXing库.ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.该项目可实现的条形码编码和解码.目前支持以下格式:UPC-A,UPC-E.EAN-8,EAN-13.39码.93码.ZXing是个很经典的条码/二维码识别的开源类库,以前在功能机上,就有开发者使用J2ME运用ZXing了,不过要支持JSR-234规范(自动对焦)的手机才能发挥其威力. ZXing

  • Android利用ZXing扫描二维码的实例代码解析

    相关阅读: Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题 此项目源码地址:请点击这里 看一下zxing的项目结构,我这里直接拿过来用的 看一下扫码的activity: package com.fanyafeng.barcode.activity; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle

  • Android-Zxing实现二维码的扫描与生成

    Zxing: Zxing是一个开放源码,用java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.可以实现使用手机内置摄像头完成条形码的扫描以及解码. github: https://github.com/zxing/zxing 首先在写项目的时候,我们需要导入一个moduel,主要是从Zxing中提取的主要功能代码.其地址是: http://pan.baidu.com/s/1sk9pGmT 扫描二维码: 在点击扫描二维码的页面: startActivityForResu

  • Android中的二维码生成与扫描功能

    0. 前言 今天这篇文章主要描述二维码的生成与扫描,使用目前流行的Zxing,为什么要讲二维码,因为二维码太普遍了,随便一个Android APP都会有二维码扫描.本篇旨在帮助有需求的同学快速完成二维码生成和扫描的功能. 1.    Zxing的使用 从github上下载项目后,可以看到整体代码结构如下: 我们只需将Zxing包下的所有代码copy一份到我们的项目中去,除了这些还需要zxing的jar包,最后相应的资源文件,包括values文件下的ids文件.raw文件中的资源文件(可以替换).

  • Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果(推荐)

    了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现很多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了二维码扫描功能,跟着人家的帖子,很快我的项目就加入了扫描二维码的功能,然后自己还很开心. 随着微信的到来,二维码越来越火爆,随处能看到二维码,比如商城里面,肯德基,餐厅等等,对于二维码

  • Android平台生成二维码并实现扫描 & 识别功能

    1.二维码的前世今生 "二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的:在代码编制上巧妙地利用构成计算机内部逻辑基础的"0"."1"比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集:每个字符占有一定的宽度:具有一定的校验功能

  • Android实现基于ZXing快速集成二维码扫描功能

    二维码扫描现在是一直比较多的应用场景,android的开源项目ZXing提供了完整.成熟的解决方案,如果仅仅是出于快速开发的目的,可以根据自己的项目需要,把ZXing官方提供的项目稍加裁剪,就可以快速的集成到自己的项目中.下面详细演示和介绍如何实现基于ZXing官方提供的源码,快速集成二维码扫描功能到自己项目中的解决方案. (第1步):到ZXing官方主页下载最新的项目代码包,ZXing在github的官方主页:https://github.com/zxing,下载后解压.解压后根目录下有若干项

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

    随着微信的到来,二维码越来越火爆,随处能看到二维码,比如商城里面,肯德基,餐厅等等,对于二维码扫描我们使用的是google的开源框架Zxing,我们可以去http://code.google.com/p/zxing/下载源码和Jar包,之前我项目中的二维码扫描功能只实现了扫描功能,其UI真的是其丑无比,一个好的应用软件,其UI界面也要被大众所接纳,不然人家就不会用你的软件啦,所以说应用软件功能和界面一样都很重要,例如微信,相信微信UI被很多应用软件所模仿,我也仿照微信扫描二维码效果进行模仿,虽然

  • Android中二维码的生成方法(普通二维码、中心Logo 二维码、及扫描解析二维码)

    首先声明我们通篇用的都是Google开源框架Zxing,要实现的功能有三个 ,生成普通二维码.生成带有中心图片Logo 的二维码,扫描解析二维码,直接上效果图吧 首先我们需要一个这样的 Zxing 的包类似于这样 接下来需要引入资源 1.drawable 中引入图片 navbar.png 2.layout中引入camera.xml.main.xml.qrcode_capture_page.xml 3.创建raw文件夹并添加beep.ogg 扫描声音 4.合并color.xml,copy ids.

随机推荐