效果图:
首先添加依赖:
implementation 'com.google.zxing:core:3.3.3'MainActivity代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_create_qr; private ImageView iv_qr; private AlertDialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_create_qr = findViewById(R.id.btn_create_qr_code); iv_qr = findViewById(R.id.iv_code); btn_create_qr.setOnClickListener(this); iv_qr.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { parseQRCode(); return true; } }); } private void parseQRCode() { dialog = new AlertDialog.Builder(this).create(); View view = LayoutInflater.from(this).inflate(R.layout.dialog_qr_code, null); dialog.setView(view); LinearLayout linearLayout1 = view.findViewById(R.id.dialog_ll1); LinearLayout linearLayout2 = view.findViewById(R.id.dialog_ll2); // 对话框中的识别二维码 linearLayout1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View view = getWindow().getDecorView().getRootView(); //找到当前页面的根布局 view.setDrawingCacheEnabled(true); //禁用绘图缓存 view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); String string = parse(bitmap); // parse()作用是解析二维码 Toast.makeText(MainActivity.this, "解析成功,内容为:" + string, Toast.LENGTH_SHORT).show(); //禁用DrawingCache否则会影响性能 ,而且不禁止会导致每次截图到保存的是缓存的位图 view.setDrawingCacheEnabled(false); //识别完成之后开启绘图缓存 dialog.dismiss(); } }); // 对话框中的保存二维码 linearLayout2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "暂未实现", Toast.LENGTH_SHORT).show(); dialog.dismiss(); } }); dialog.show(); } private String parse(Bitmap bitmap) { int height = bitmap.getHeight(); //图片宽度 int width = bitmap.getWidth(); //图片高度 int pixels[] = new int[height * width]; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); QRCodeReader reader = new QRCodeReader(); // 这个对象可以检测和解码图像中的二维码 Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class); hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); //优化精度 hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); //解码设置编码方式为:utf-8 try { Result result = reader.decode(new BinaryBitmap(new HybridBinarizer(new RGBLuminanceSource(width, height, pixels))), hints); return result.getText(); } catch (NotFoundException e) { e.printStackTrace(); } catch (ChecksumException e) { e.printStackTrace(); } catch (FormatException e) { e.printStackTrace(); } return null; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_create_qr_code: Bitmap bitmap = createQRCode(); if (bitmap != null) { iv_qr.setImageBitmap(bitmap); } break; } } private Bitmap createQRCode() { // 用于设置二维码参数 Hashtable<EncodeHintType, Object> qrParam = new Hashtable<>(); // 设置二维码的纠错级别 qrParam.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置二维码的编码方式 qrParam.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 生成二维码--这里得到一个由true和false组成的数组 // 参数顺序为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数 try { BitMatrix bitMatrix = new MultiFormatWriter().encode("你好啊,我是内容", BarcodeFormat.QR_CODE, 250, 250, qrParam); // 利用二维码数据创建Bitmap图片,分别设为黑白两色 int w = bitMatrix.getWidth(); // 得到矩阵的列数 int h = bitMatrix.getHeight(); // 得到矩阵的行数 int[] data = new int[w * h]; // 根据矩阵的元素内容来创建与之对应的数组,也就是说矩阵中有几个元素,这个数组就有几个元素 //通过循环对data数组进行填值,此处的data数组我们是用来存储颜色值的,颜色值为黑和白 for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (bitMatrix.get(x, y)) //传入列和行, 获取请求的位,其中true表示黑色 data[y * w + x] = 0xff000000; // 黑色 ,y*w+x是索引当前矩阵的元素是第几个和相应数组元素对应,y表示当前行数,w表示每列的总数,x表示当前列数 else data[y * w + x] = 0x00ffffff; } } // 创建一张bitmap图片,采用最高的图片效果ARGB_8888 Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); // 将上面的颜色数组传入,生成图片颜色 bitmap.setPixels(data, 0, w, 0, 0, w, h); return bitmap; } catch (WriterException e) { e.printStackTrace(); } return null; } }此处要注意几点:
1、如果要动态的更新二维码,请传入不同的内容,在MultiFormatWriter().encode()方法中的第一个参数中,比如开个线程,把系统时间放进去在加入你想要的内容。
2、上面的那个dialog的布局是我自己写的,写的比较丑,你可以写的好看一点,在加入一些动画。
3、 识别二维码的时候,图片的大小我没有进行压缩。