Android 使用ZXing生成带logo的二维码
有一段时间没有写博客了,都快忘记怎么写了,最近在赶公司的项目,接近尾声了,写点有意思的东西,好了,进入正题。。。
老规矩,从头开始啊,新建一个名为QGCodeDemo的项目
运行效果如下:
然后这里我们会使用一个框架,二维码框架ZXing 划重点,首先我们在app下的build.gradle下添加依赖
//二维码 implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
添加之后记得 Sync Now 一下,这个通常出现在AS的右上角,现在框架已经添加进来了,然后就是简单的一个布局,一个按钮,一个居中显示图片
<?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中进行初始化控件。
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框架的东西了,首先这是一个比较早的框架了,很多人进行了多次重写与封装,里面内容会很多,但不一定适用于现在的你,所以也重写一下这个。
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; } }