Android 使用ZXing生成带logo的二维码
有一段时间没有写博客了,都快忘记怎么写了,最近在赶公司的项目,接近尾声了,写点有意思的东西,好了,进入正题。。。
老规矩,从头开始啊,新建一个名为QGCodeDemo的项目
运行效果如下:
然后这里我们会使用一个框架,二维码框架ZXing 划重点,首先我们在app下的build.gradle下添加依赖
代码语言:javascript复制//二维码
api 'com.journeyapps:zxing-android-embedded:3.6.0'
添加之后记得 Sync Now 一下,这个通常出现在AS的右上角,现在框架已经添加进来了,然后就是简单的一个布局,一个按钮,一个居中显示图片
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lanjing.qgcodedemo.MainActivity">
<ImageView
android:id="@ id/code"
android:layout_centerInParent="true"
android:layout_width="300dp"
android:layout_height="300dp" />
<Button
android:id="@ id/showBtn"
android:text="SHOW CODE"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
可以看到布局非常简单,然后在MainActivity中进行初始化控件。
代码语言:javascript复制package com.lanjing.qgcodedemo;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ImageView codeImageView;
private Button showBtn;
//创建两个Bitmap,一个放二维码,一个放logo
Bitmap codeBmp, logoBmp;
private String url;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
showBtn.setOnClickListener(this);
//给图片添加长按点击事件
codeImageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
/*
* 给button添加长按事件,触发时调用openCode()方法打开二维码,如果是文本则显示文本,是可访问地址,则会弹出提示问你是否继续访问
* */
openCode();
return true;
}
});
}
//初始化控件
private void initView() {
codeImageView = (ImageView) findViewById(R.id.code);
showBtn = (Button) findViewById(R.id.showBtn);
}
@Override
public void onClick(View v) {
/*
* 按钮点击显示二维码
* */
//加一个测试地址,之后我们的二维码就是用这个地址来生成。扫描后直接进入百度,这个地址也可以用于动态,或者是你从服务器中得到的地址
url = "https://www.baidu.com";
//这里的logo是系统自带的,通过BitmapFactory加载进来
logoBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.demo);
//通过ZXing框架将地址和logo图片加到里面,生成二维码之后赋值给codeBmp;
codeBmp = ZXingUtilsTest.createQRImage(this, url, logoBmp);
//最后将得到的codeBmp设置为ImageView的ImageBitmap这样图片就会显示出来了
codeImageView.setImageBitmap(codeBmp);
}
private void openCode() {//这个方法其实和我们之前的页面跳转比较像 intent携带信息访问权限,这时活动产生一个新的任务,然后开始执行这个任务
Intent intent = new Intent(Intent.ACTION_VIEW,
(Uri.parse(url))
).addCategory(Intent.CATEGORY_BROWSABLE)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
应该是一目了然吧,接下来就需要用到ZXing框架的东西了,首先这是一个比较早的框架了,很多人进行了多次重写与封装,里面内容会很多,但不一定适用于现在的你,所以也重写一下这个。
代码语言:javascript复制package com.lanjing.qgcodedemo;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Administrator on 2019/4/3 0001.
*/
public class ZXingUtilsTest {
/**
* 生成二维码Bitmap
*
* @param context 文本内容
* @param logoBm 二维码中心的Logo图标(可以为null)
* @return 合成后的bitmap
*/
public static Bitmap createQRImage(Context context, String data, Bitmap logoBm) {
try {
if (data == null || "".equals(data)) {
return null;
}
int widthPix = ((Activity) context).getWindowManager().getDefaultDisplay()
.getWidth();
widthPix = widthPix / 5 * 3;
int heightPix = widthPix;
//配置参数
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//容错级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度
hints.put(EncodeHintType.MARGIN, 3); //default is 4
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, widthPix, heightPix, hints);
int[] pixels = new int[widthPix * heightPix];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < heightPix; y ) {
for (int x = 0; x < widthPix; x ) {
if (bitMatrix.get(x, y)) {
pixels[y * widthPix x] = 0xff000000;
} else {
pixels[y * widthPix x] = 0xffffffff;
}
}
}
// 生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
if (logoBm != null) {
bitmap = addLogo(bitmap, logoBm);
}
return bitmap;
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
//return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 在二维码中间添加Logo图案
*/
private static Bitmap addLogo(Bitmap src, Bitmap logo) {
if (src == null) {
return null;
}
if (logo == null) {
return src;
}
//获取图片的宽高
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int logoWidth = logo.getWidth();
int logoHeight = logo.getHeight();
if (srcWidth == 0 || srcHeight == 0) {
return null;
}
if (logoWidth == 0 || logoHeight == 0) {
return src;
}
//logo大小为二维码整体大小的1/5
float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;
Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
try {
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(src, 0, 0,null);
canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);
canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
} catch (Exception e) {
bitmap = null;
e.getStackTrace();
}
return bitmap;
}
}
这个就是一个重写的工具类,可以复制过去直接用。里面也有相关的注释,我就不做过多解释了
GitHub地址