使用CAShapeLayer实现扫描二维码界面

这篇博客介绍了如何利用CAShapeLayer实现扫描二维码界面,包括CAShapeLayer的基本概念、扫描界面的创建、awakeFromNib中的代码说明、ROI区域的设置以及最终效果的展示。通过设置扫描框图形和调整ROI区域,可以实现对准中间框才能识别二维码的效果。
摘要由CSDN通过智能技术生成

之前写过一篇利用AVCaptureSession扫描二维码的博客,但是那个页面是全屏的,在实际应用中,一般都是中间有一个框,然后二维码对准中间框的时候才能识别。这是怎么实现的呢,经过查找资料,现将方法纪录,供日后查阅。

CAShapeLayer简介

关于CAShapeLayer的介绍网上有很多,我就引用一段吧。原文链接

CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。你指定诸如颜色和线宽等属性,用CGPath来定义想要绘制的图形,最后CAShapeLayer就自动渲染出来了。当然,你也可以用Core Graphics直接向原始的CALyer的内容中绘制一个路径,相比直下,使用CAShapeLayer有以下一些优点:

  • 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  • 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存
  • 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉
  • 不会出现像素化。当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化

实现扫描界面

首先当然是需要配备一张有扫描框的图片:
扫描框
我们定义一个ScanView,用来展示整个扫描界面,使用XIB或其他合适方式将图片添加到该View中,我这里使用XIB方式,并设置好约束。

@interface CMQRCodeScanView : UIView {
    __weak IBOutlet UIImageView *scanImageView;
}
@end

首先定义两个与屏幕相关的宏,并定义图片的大小(扫描区域的大小),一般来说要比图片大小要稍小一点,不然看起来效果有点差强人意,这里我图片设置的大小是240。

#define UI_IOS_WINDOW_WIDTH  CGRectGetWidth([UIScreen mainScreen].bounds)
#define UI_IOS_WINDOW_HEIGHT CGRectGetHeight([UIScreen mainScreen].bounds)
#define kScanRegionSize 232

awakeFromNib代码说明

定义一个CAShapeLayer类变量,并在-awakeFromNib方法中编写相关代码

-(void)awakeFromNib {
    [super awakeFromNib];

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(0, 0, UI_IOS_WINDOW_WIDTH, UI_IOS_WINDOW_HEIGHT));
    CGPathAddRect(path, NULL, CGRectMake((UI_IOS_WINDOW_WIDTH - kScanRegionSize) / 2, (UI_IOS_WINDOW_HEIGHT - kScanRegionSize) / 2, kScanRegionSize, kScanRegionSize));

    _shapeLayer = [[CAShapeLayer alloc] init];
    _shapeLayer.fillColor = [UIColor colorWithWhite:0.0f alpha:0.7f].CGColor;
    _shapeLayer.fillRule = kCAFillRuleEvenOdd;
    _shapeLayer.path = path;
    [self.layer insertSublayer:_shapeLayer atIndex:0];

    return ;
}

因为除了中间的扫描区域之外,其他的全部要置灰,所以要添加两条路径,一条是屏幕大小,还有一条是扫描区域大小。然后将路径赋给CAShapeLayer的path属性。

CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(0, 0, UI_IOS_WINDOW_WIDTH, UI_IOS_WINDOW_HEIGHT));
    CGPathAddRect(path, NULL, CGRectMake((UI_IOS_WINDOW_WIDTH - kScanRegionSize) / 2, (UI_IOS_WINDOW_HEIGHT - kScanRegionSize) / 2, kScanRegionSize, kScanRegionSize));
_shapeLayer.path = path;

然后设置其他区域的相关属性,如填充颜色、填充规则。主要是填充规则,需要设置为kCAFillRuleEvenOdd,关于这个属性的介绍也有很多文章介绍(其实我自己也不太明白,不过我的目的是实现)

_shapeLayer.fillColor = [UIColor colorWithWhite:0.0f alpha:0.7f].CGColor;
_shapeLayer.fillRule = kCAFillRuleEvenOdd;

最后将该CAShapeLayer插入到最底层即可实现。如果需要显示摄像头的拍摄页面,只需要将AVCaptureVideoPreviewLayer预览层插入到CAShapeLayer之下,并设置ROI区域为扫描框区域即可。

ROI区域的说明

虽然知道要设置ROI区域,但是当我自己设置的时候还是会出了点问题,刚开始,我设置的是扫描框的矩形区域,但是发现扫描不到二维码,于是查看文档得知道,ROI区域的默认值是(0.0, 0.0, 1.0, 1.0),原来ROI区域用的是比例,所以设置代码应该如下:

[outPut setRectOfInterest:CGRectMake((UI_IOS_WINDOW_WIDTH - kScanRegionSize) / (2 * UI_IOS_WINDOW_WIDTH), (UI_IOS_WINDOW_HEIGHT - kScanRegionSize) / (2 * UI_IOS_WINDOW_HEIGHT), (UI_IOS_WINDOW_WIDTH + kScanRegionSize) / (2 * UI_IOS_WINDOW_WIDTH), (kScanRegionSize + UI_IOS_WINDOW_HEIGHT) / (2 *UI_IOS_WINDOW_HEIGHT))];

效果展示

Demo

要在Android应用中使用ZXing库来实现扫描二维码功能,您可以按照以下步骤操作: 1. 在您的项目中添加ZXing库的依赖。您可以在build.gradle文件中添加以下依赖: ```gradle implementation 'com.google.zxing:core:3.4.0' implementation 'com.journeyapps:zxing-android-embedded:3.6.0' ``` 2. 在您的布局文件中添加一个用于显示摄像头预览的SurfaceView: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在您的代码中创建一个ZXing库的核心对象和一个用于处理扫描结果的回调函数: ```java private CaptureManager capture; private ZXingScannerView scannerView; private void initScanner() { scannerView = new ZXingScannerView(this); setContentView(scannerView); capture = new CaptureManager(this, scannerView); capture.initializeFromIntent(getIntent(), null); capture.decode(); scannerView.setResultHandler(new ResultHandler()); } private class ResultHandler implements ZXingScannerView.ResultHandler { @Override public void handleResult(Result rawResult) { // 处理扫描结果 String result = rawResult.getText(); // 在此处添加您的处理逻辑 // ... // 重新开始扫描 scannerView.resumeCameraPreview(this); } } ``` 4. 在您的Activity的onCreate方法中调用initScanner()方法来初始化扫描器: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initScanner(); } ``` 5. 在您的Activity的onResume方法中调用capture.onResume()和scannerView.onResume()方法来恢复扫描器: ```java @Override protected void onResume() { super.onResume(); capture.onResume(); scannerView.onResume(); } ``` 6. 在您的Activity的onPause方法中调用capture.onPause()和scannerView.onPause()方法来暂停扫描器: ```java @Override protected void onPause() { super.onPause(); capture.onPause(); scannerView.onPause(); } ``` 7. (可选)您可以在您的Activity的onDestroy方法中调用capture.onDestroy()方法来释放扫描器: ```java @Override protected void onDestroy() { super.onDestroy(); capture.onDestroy(); } ``` 现在您的应用已经可以使用ZXing库来扫描二维码了。在您的应用中启动这个Activity,您将看到一个用于扫描二维码的摄像头预览界面。当您扫描一个二维码时,它的内容将会传递给您在第3步中创建的ResultHandler对象的handleResult方法中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值