欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-16 11:23:16
本文实例讲述了android开发实现模仿360二维码扫描功能的方法。分享给大家供大家参考,具体如下: 一、效果图: 二、框架搭建 1、首先,下载最新zxing...

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

一、效果图:

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

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

二、框架搭建

1、首先,下载最新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、最后框架

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

三、具体实现

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:这里再为大家推荐一款二维码在线生成工具供大家参考使用:

在线生成二维码工具(加强版)

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

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

上一篇:

下一篇: