現在很多項目中都會用到掃碼這個功能,現在開源架構被大家熟知的有Zbar以及ZXIng,Zbar底層是C語言來實作的,掃碼速度比ZXing要快很多,是以我在項目中選擇的是Zbar掃碼。
對應代碼csdn的下載下傳位址:ZBar仿微信條形碼二維碼掃描界面
先上我寫好的界面:

ZBar為我們提供了兩種使用方式,一種是直接使用ZBar提供的ZBarReaderViewController打開一個掃描界面,另一種方式是使用ZBar提供的可以嵌在其他視圖中的ZBarReaderView,實際項目中我們更可能會使用第二種方式,這可以讓我們對界面做更多的定制。這裡我詳細說一下使用ZBarReaderView這種方式實作掃碼功能:
1、引入頭檔案
将git上下載下傳的ZBarSDK頭檔案拖入項目中,勾選copy選項
2、導入要用到的framework
選中自己建好的項目,然後切換到General->Linked Frameworks and Libraries點選小+号添加需要的架構,假如項目中已經有的framework無需重複添加
3、ZBarReaderView添加掃碼框
首先我們自定義掃碼框為頁面的一部分,代碼如下:
- (void) init_camera
{
ZBarReaderView * reader = [ZBarReaderView new];
ZBarImageScanner * scanner = [ZBarImageScanner new];
[scanner setSymbology:ZBAR_PARTIAL config:0 to:0];
[reader initWithImageScanner:scanner];
[scanner release];
reader.readerDelegate = self;
const float h = [UIScreen mainScreen].bounds.size.height;
const float w = [UIScreen mainScreen].bounds.size.width;
const float h_padding = w / 10.0;
const float v_padding = h / 10.0;
CGRect reader_rect = CGRectMake(h_padding, v_padding,
w - h_padding * 2.0, h / 3.0);//視圖中的一小塊
reader.frame = reader_rect;
reader.backgroundColor = [UIColor redColor];
[reader start];
[self.view addSubview: reader];
[reader release];
}
代理方法實作:
- (void) readerView:(ZBarReaderView *)readerView didReadSymbols: (ZBarSymbolSet *)symbols fromImage:(UIImage *)image
{
ZBarSymbol * s = nil;
for (s in symbols)
{
text.text = s.data;
image_view.image = image;
break;
}
}
Zbar在掃描的時候會自動出現訓示框,一個綠色的正方形,是以我覺根本沒必要添加掃描線之類的,當然如果你需要我下面的代碼裡面也有寫,界面如下:
左下角是掃描是截獲的圖檔,右邊是掃描到的字元串(可掃二維碼以及條形碼,二維碼掃碼速度更快)
這個界面是用xib直接拖出來的
除了readerView其他視圖都是用xib直接拖出來的,大家自由發揮,隻是一個例子
4、設定全屏模式的掃碼框-如微信掃描的效果
我自定義了一個ZbarOverlayView,這個類做的就是蓋在Zbar的掃描框上的顯示效果:
/**
* 透明掃描框的區域
*/
@property (nonatomic, assign) CGSize transparentArea;
@property (nonatomic, assign) CGFloat tansparentY;
-(void)startAnimation;
-(void)stopAnimation;
上面是傳入參數,中間透明框的大小,掃描框的起始高度,然後就是綠色閃爍線的開始結束動畫方法,使用如下,在掃描界面添加如下代碼:
_overLayView = [[ZbarOverlayView alloc]initWithFrame:reader.frame];//添加覆寫視圖
// [_overLayView startAnimation];
_overLayView.transparentArea = reader_rect.size;//設定中間可選框大小
[reader addSubview:_overLayView];
reader.scanCrop = [self getScanCrop:reader_rect readerViewBounds:reader_rect1];//CGRectMake(100 / h,0.1, 1/3.0,1.8)
5、綠色線條移動動畫
設定staticNSTimeInterval kLineAnimateDuration = 0.02;
- (void)lineDrop
{
[UIView animateWithDuration:kLineAnimateDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
CGRect rect = _imgLine.frame;
rect.origin.y = _lineH;
_imgLine.frame = rect;
}completion:^(BOOL complite){
CGFloat maxBorder = _rectY + self.transparentArea.height - 4;
if (_lineH > maxBorder) {
_lineH = _rectY + 4;
}
_lineH ++;
}];
}
線條高度是2,讓線條在方框内活動是以起始高度+4,最大高度-4
6、實作邊緣透明遮罩,中間挖空的二維碼掃描框
- (void)drawRect:(CGRect)rect {//viewDidLoad之後調用
//整個二維碼掃描界面的顔色
CGRect screenDrawRect = self.frame;
//中間清空的矩形框
CGRect clearDrawRect = CGRectMake(screenDrawRect.size.width / 2 - self.transparentArea.width / 2,
_rectY,
self.transparentArea.width,self.transparentArea.height);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self addScreenFillRect:ctx rect:screenDrawRect];
[self addCenterClearRect:ctx rect:clearDrawRect];
[self addWhiteRect:ctx rect:clearDrawRect];
[self addCornerLineWithContext:ctx rect:clearDrawRect];
}
上面調用的四個方法都是自定義的,添加覆寫頁面全屏的半透明效果,清空要留白的區域,添加白色矩形框,添加四個尖角綠色線條
7、設定ZBar的掃描焦點scanCrop
很多人可能會忽略這個屬性,其實這個屬性不設定也可以掃描出來,假如設定錯誤的使用者可能會覺得不設定掃描還快一點,當然在我搞清楚這個屬性之前我也不想使用這個屬性,但是使用全屏掃描的使用者可能都會有一個尴尬的地方,當有幾個二維碼在掃描範圍内,明明掃描框在中間,可是卻掃到了左下角的二維碼,中間的确不掃描,這個明顯是不合邏輯的。Zbar就給我們提供了這麼一個屬性。
scanCrop在Zbar的函數說明上要傳入參數是 (0, 0, 1, 1),defaults to the full image (0, 0, 1, 1),也就是說預設是全屏掃描的。
ios開發者都知道蘋果螢幕的坐标系是從左上角作為(0,0)點開始的,如下紅色區域大小為(0,0,200,100)
但是Zbar的scanCrop就要參照下面的坐标系,整個螢幕區域就是(0,0,螢幕高度,螢幕寬度),紅色區域為(0,螢幕寬度 - 0 - 200,100,200)
計算出來scanCrop為(0/螢幕高度,螢幕寬度 - 0 - 200/螢幕寬度,100/螢幕高度,200/螢幕寬度)
以下是我寫的擷取scanCrop的函數,rect傳入空白框的區域大小,readerViewBounds傳入全部掃描區域的大小:
-(CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)readerViewBounds
{
CGFloat fullWidth = readerViewBounds.size.width;
CGFloat fullHeight = readerViewBounds.size.height;
CGFloat x,y,width,height;
x = rect.origin.x;
y = rect.origin.y;
width = rect.size.width;
height = rect.size.height;
if (x + width > fullWidth) {
if (width > fullWidth) {
width = fullWidth;
}else{
x = 0;
}
}
if (y + height > fullHeight) {
if (height > fullHeight) {
height = fullHeight;
}else{
y = 0;
}
}
CGFloat x1,y1,width1,height1;
x1 = (fullWidth - width - x) / fullWidth;
y1 = y / fullHeight;
width1 = width / fullWidth;
height1 = rect.size.height / readerViewBounds.size.height;
NSLog(@"frame:%@",NSStringFromCGRect(CGRectMake(y1, x1,height1, width1)));
return CGRectMake(y1, x1,height1, width1);
}
另外我對比過Zbar大片掃描區域與一塊掃描區域,發現一小塊的聚焦效果更好,更清晰,掃描速度更快,我對比過微信跟淘寶的掃描,發現都非常清晰,當然我也不知道他們用什麼技術實作的