最近做了一个二维码扫描与生成的一个项目,现在记录一下老师给想要的需求,管理员通过二维码扫描然后获取到学生端的信息然后将这段信息记录进数据库中,于是我就查看蛮多的资料的最后做出来了一个二维码的扫描识别功能的一个app试玩版,当然本体还是不能公布的。
本项目适合想快速学习二维码扫描技术的新人可能会有些错误毕竟我也刚学。
我们先来看图
这个图比较low不过是测试页面,没有拿实体机来截图因为自己的手机也给搞坏了虚拟机也开不了电脑暂时被当成服务器。暂时拿android stduio的图来给大家尝尝。
具体的功能页面就是这个UI图还有些错误如果你需要更改的话就自己改改吧毕竟这个我拿来测试用的,
我们需要点击从哪个Editext的输入框中输入内容我们全部输入完以后我们在下方点击我要还书,
然后生成二维码,出现二维码以后我们长按二维码就可以出现一个按钮我们就可以保存到本地SD卡中,点击扫描我们可以通过扫描来识别二维码里面的内容。
首先我们第一步·:添加zxing的jar包
https://github.com/zxing/zxing这个可以从GitHub官网下载
具体的什么compile我就不多说了蛮多如果想看的话就去参考这位仁兄的
http://blog.csdn.net/yuzhiqiang_1993/article/details/52805057
这个是主界面
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.dtr.zxing.activity.CaptureActivity;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Hashtable;
import base.BaseInterFace;
import view.MyLayout;
/**
* 用于生成二维码和扫描二维码的主页
*/
public class MainActivity extends AppCompatActivity implements BaseInterFace{
private static final int QR_WIDTH = 100;
private static final int QR_HEIGHT = 100;
private MyLayout name; // 姓名
private MyLayout phone; // 手机号
private MyLayout bookname; // 借阅书名
private MyLayout studentname; // 学生号
private MyLayout returnbookdata; // 还书日期
// 显示生成的二维码
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Button clickscan = (Button)findViewById( R.id.button );
clickscan.setOnClickListener( new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent intentj = new Intent( MainActivity.this,CaptureActivity.class );//执行页面跳转到扫描页面
startActivity( intentj );
}
} );
init();
initData();
initOper();
}
@Override
public void init() {
name = (MyLayout) findViewById(R.id.name_layout);
phone =(MyLayout)findViewById( R.id.phone_layout);
bookname = (MyLayout) findViewById(R.id.bookname_layout);
studentname = (MyLayout) findViewById(R.id.studentname_layout);
returnbookdata = (MyLayout) findViewById(R.id.returnbookdata_layout);
iv = (ImageView) findViewById(R.id.iv);
}
@Override
public void initData() {
name.setTv( getString( R.string.name ) );
phone.setTv( getString( R.string.phone ) );
bookname.setTv( getString( R.string.bookname ) );
studentname.setTv( getString( R.string.studentname ) );
returnbookdata.setTv( getString( R.string.returnbookdata ) );
}
@Override
public void initOper() {
// 长按保存二维码图片到本地
iv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// 判断是否有SD卡
boolean flag = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
String path = null;
if (flag){
path = Environment.getExternalStorageDirectory().toString();
}else{
path = Environment.getDataDirectory().toString();
}
// 创建文件
final File file = new File(path+"/二维码名片.jpg");
// 弹出对话框,确定是否保存
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setCancelable(true);
builder.setTitle("是否保存?");
builder.setMessage("路径:"+path);
builder.setNegativeButton("保存", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) iv.getDrawable();
Bitmap bitmap = bitmapDrawable.getBitmap();
try {
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
fos.flush();
fos.close();
toastStr("保存成功!");
} catch (Exception e) {
toastStr("保存失败");
e.printStackTrace();
}
}
});
builder.setPositiveButton("取消", null);
builder.show();
return true;
}
});
}
/**
* 生成二维码
* @param view
*/
public void clickedCreate(View view)
{
// 进行显示
iv.setVisibility( View.VISIBLE );
// 判断名字
if (name.getEtText().equals( "" ))
{
toastStr( "请输入姓名" );
return;
}
// 判断手机号
if (phone.getEtText().equals( "" ))
{
toastStr( "请输入手机号" );
return;
}
if(bookname.getEtText().equals( "" ))
{
toastStr( "请输入借阅的书名" );
return;
}
if(studentname.getEtText().equals( "" ))
{
toastStr( "请输入学生号" );
return;
}
if(returnbookdata.getEtText().equals( "" ))
{
toastStr( "请输入还书的日期格式x年x月x日" );
return;
}
// 生成二维码
String url = name.getEtText() + "," + phone.getEtText() + "," + bookname.getEtText() + "," + studentname.getEtText() + "," + returnbookdata.getEtText();
//将URL生成输入到二维码中
这个activity_main layout
createQRImage( url );
}
public void toastStr(String s){
Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
}
// 生成二维码
// QR_WIDTH, QR_HEIGHT, 需要自己指定大小
public void createQRImage(String url)
{
try
{
//判断URL合法性
if (url == null || "".equals(url) || url.length() < 1)
{
Toast.makeText(this,"请填写个人还书信息!",Toast.LENGTH_SHORT).show();
return;
}
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);
int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
//下面这里按照二维码的算法,逐个生成二维码的图片,
//两个for循环是图片横列扫描的结果
for (int y = 0; y < QR_HEIGHT; y++)
{
for (int x = 0; x < QR_WIDTH; x++)
{
if (bitMatrix.get(x, y))
{
pixels[y * QR_WIDTH + x] = 0xff000000;
}
else
{
pixels[y * QR_WIDTH + x] = 0xffffffff;
}
}
}
这个是CaptureActivity的页面
这个我们直接拿zxing的demo进行修改即可
/*
* 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.dtr.zxing.activity;
import java.io.IOException;
import java.lang.reflect.Field;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.dtr.zxing.camera.CameraManager;
import com.dtr.zxing.decode.DecodeThread;
import com.dtr.zxing.utils.BeepManager;
import com.dtr.zxing.utils.CaptureActivityHandler;
import com.dtr.zxing.utils.InactivityTimer;
import com.google.zxing.Result;
import myview.dxp.com.qrcodecard.R;
import myview.dxp.com.qrcodecard.ResultActivity;
/**
* This activity opens the camera and does the actual scanning on a background
* thread. It draws a viewfinder to help the user place the barcode correctly,
* shows feedback as the image processing is happening, and then overlays the
* results when a scan is successful.
*
* @author [email protected] (Daniel Switkin)
* @author Sean Owen
*/
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = CaptureActivity.class.getSimpleName();
private CameraManager cameraManager;
private CaptureActivityHandler handler;
private InactivityTimer inactivityTimer;
private BeepManager beepManager;
private SurfaceView scanPreview = null;
private RelativeLayout scanContainer;
private RelativeLayout scanCropView;
private ImageView scanLine;
private Rect mCropRect = null;
public Handler getHandler() {
return handler;
}
public CameraManager getCameraManager() {
return cameraManager;
}
private boolean isHasSurface = false;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_capture);
scanPreview = (SurfaceView) findViewById(R.id.capture_preview);
scanContainer = (RelativeLayout) findViewById(R.id.capture_container);
scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view);
scanLine = (ImageView) findViewById(R.id.capture_scan_line);
inactivityTimer = new InactivityTimer(this);
beepManager = new BeepManager(this);
TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT,
0.9f);
animation.setDuration(4500);
animation.setRepeatCount(-1);
animation.setRepeatMode(Animation.RESTART);
scanLine.startAnimation(animation);
}
@Override
protected void onResume() {
super.onResume();
// CameraManager must be initialized here, not in onCreate(). This is
// necessary because we don't
// want to open the camera driver and measure the screen size if we're
// going to show the help on
// first launch. That led to bugs where the scanning rectangle was the
// wrong size and partially
// off screen.
cameraManager = new CameraManager(getApplication());
handler = null;
if (isHasSurface) {
// The activity was paused but not stopped, so the surface still
// exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(scanPreview.getHolder());
} else {
// Install the callback and wait for surfaceCreated() to init the
// camera.
scanPreview.getHolder().addCallback(this);
}
inactivityTimer.onResume();
}
@Override
protected void onPause() {
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
inactivityTimer.onPause();
beepManager.close();
cameraManager.closeDriver();
if (!isHasSurface) {
scanPreview.getHolder().removeCallback(this);
}
super.onPause();
}
@Override
protected void onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (holder == null) {
Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
}
if (!isHasSurface) {
isHasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isHasSurface = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* A valid barcode has been found, so give an indication of success and show
* the results.
*
* @param rawResult
* The contents of the barcode.
*
* @param bundle
* The extras
*/
public void handleDecode(Result rawResult, Bundle bundle) {
inactivityTimer.onActivity();
beepManager.playBeepSoundAndVibrate();
bundle.putInt("width", mCropRect.width());
bundle.putInt("height", mCropRect.height());
bundle.putString("result", rawResult.getText());
// setResult(1,new Intent(CaptureActivity.this, ResultActivity.class).putExtras(bundle));
setResult(1);
startActivityForResult(new Intent(CaptureActivity.this, ResultActivity.class).putExtras(bundle),1);
//扫描以后跳转到结果页面然后显示内容
}
private void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
throw new IllegalStateException("No SurfaceHolder provided");
}
if (cameraManager.isOpen()) {
Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
return;
}
try {
cameraManager.openDriver(surfaceHolder);
// Creating the handler starts the preview, which can also throw a
// RuntimeException.
if (handler == null) {
handler = new CaptureActivityHandler(this, cameraManager, DecodeThread.ALL_MODE);
}
initCrop();
} catch (IOException ioe) {
Log.w(TAG, ioe);
displayFrameworkBugMessageAndExit();
} catch (RuntimeException e) {
// Barcode Scanner has seen crashes in the wild of this variety:
// java.?lang.?RuntimeException: Fail to connect to camera service
Log.w(TAG, "Unexpected error initializing camera", e);
displayFrameworkBugMessageAndExit();
}
}
private void displayFrameworkBugMessageAndExit() {
// camera error
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.app_name));
builder.setMessage("相机打开出错,请稍后重试");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
});
builder.show();
}
public void restartPreviewAfterDelay(long delayMS) {
if (handler != null) {
handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS);
}
}
public Rect getCropRect() {
return mCropRect;
}
/**
* 初始化截取的矩形区域
*/
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);
}
private int getStatusBarHeight() {
try {
Class> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
activity_capture的layout页面
最后一个结果Activity
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
import com.dtr.zxing.decode.DecodeThread;
/**
* 二维码扫描后的信息显示页面
*/
public class ResultActivity extends AppCompatActivity {
// 显示图片
private ImageView iv_result;
// 显示文本信息
private TextView tv_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_result);
iv_result = (ImageView) findViewById(R.id.iv_result);
tv_result = (TextView) findViewById(R.id.tv_result);
Intent data = getIntent();
Bundle bundle = data.getExtras();
// 扫码获得一个字符串内容
String str = bundle.getString("result");
tv_result.setText(str);
// 扫码获得一张图片
Bitmap barcode = null;
byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
if (compressedBitmap != null) {
barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
// Mutable copy:
barcode = barcode.copy(Bitmap.Config.RGB_565, true);
}
iv_result.setImageBitmap(barcode);
}
}
一个自定义的view
import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.TextView; import myview.dxp.com.qrcodecard.R; /** * 自定义框架布局 */ public class MyLayout extends FrameLayout { private TextView tv; private EditText et; public MyLayout(Context context, AttributeSet attrs) { super(context, attrs); // 获取自定义布局和组件 View view = LayoutInflater.from(context).inflate(R.layout.my_view,this); tv = (TextView) view.findViewById(R.id.tv); et = (EditText) view.findViewById(R.id.et); } /** * 设置TextView的内容 * @param string */ public void setTv(String string){ tv.setText(string); } public void setEt(String string) { et.setWidth( 100 ); } /** * 设置EditText的提示内容 * @param string */ public void setEtHint(String string){ et.setHint(string); } /** * 得到输入的内容 */ public String getEtText(){ return et.getText().toString(); } }
这个view的layout
xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="姓名" android:textSize="@dimen/tv" android:layout_margin="@dimen/distance" /> <EditText android:id="@+id/et" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:hint="请输入" android:textSize="@dimen/tv" android:background="@drawable/et_bg" android:layout_margin="@dimen/distance"/> LinearLayout>BaselnterFace规范的接口这个我是看别人写的也跟着写了一个
/** * 规范接口 */ public interface BaseInterFace { public void init(); public void initData(); public void initOper(); }
好了就这么多了还有一些drawable和values没贴出来太多了时间不够写完需要接着赶项目
如有问题可以提问本人,将会在我能力范围内帮助解答。
需要的可以下载http://download.csdn.net/download/qq_16519957/10272984