利用一個小demo來對二維碼進行學習,總共四個界面(主界面,生成二維碼界面,識別二維碼界面,掃描二維碼界面)
一.二維碼的介紹
1.什么是二維碼?
二維條碼/二維碼是用某種特定的幾何圖形按一定規律在平面分布的黑白相間的圖形記錄數據符號信息的
總結: 用圖形記錄標記一些信息,方便通過圖形識別來獲取信息
2 應用場景
信息獲取(名片、地圖、WIFI密碼、資料)
手機電商(用戶掃碼、手機直接購物下單)
手機支付(掃描商品二維碼,通過銀行或第三方支付提供的手機端通道完成支付)
微信添加好友
二.二維碼界面的搭建
1.總共四個界面,可以采用storyBoard來搭建
2.四個storyBoard放在一個界面,看起來不美觀,還很容易搞混,有沒有優化方案?
可以把四個storyBoard分別開來,單獨放到一個界面里面
3.怎么把storyBoard單獨放在一個界面,而且還讓這些界面有聯系(連線)?
可以用storyBoard reference 來解決 就是用一個引用來代替storyBoard,保持storyBoard間的聯系(連線)
4.最終效果

三.二維碼的生成
1.生成二維碼的步驟
1.1 創建濾鏡 CIFilter
濾鏡屬於CoreImage框架,要導入該框架 該框架將常用來處理圖片(生成毛玻璃效果/二維碼)
1.2 給濾鏡設置內容(用kvc方式賦值)
內容必須為NSData類型
1.3 獲取生成的二維碼圖片
獲取的圖片是CIImage類型的,使用的話要進行轉換
2.運行程序發現生成的二維碼圖片很模糊,為什么?
生成為二維碼圖片大小為 27 * 27 被拉伸的太大,所以不清晰
3.怎么顯示清晰的二維碼?
蘋果提供一個api(CIImage的方法)對圖片放大,還不影響清晰度
1 // 1.創建Transform orginalImage的數據類型為CIImage 2 let scale = imageView.bounds.width / orginalImage.extent.width 3 let transform = CGAffineTransformMakeScale(scale, scale) 4 // 2.放大圖片 5 let hdImage = orginalImage.imageByApplyingTransform(transform)
4.設置前景圖片
4.1 為什么要設置前景圖片?
一般二維碼中心都有一張小的圖片,就是前景圖片
生成二維碼沒有前景圖片,需要手動添加前景圖片
4.2 怎么添加前景圖片?
就是把兩張圖片合成為一張圖片,用繪圖就可以輕松搞定
4.3 繪圖的步驟
4.31 開啟圖形上下文
4.32 將二維碼圖片畫到圖形上下文(二維碼的size = 圖形上下文的size)
4.33 將前景圖片畫到圖形上下文(前景圖片的center = 圖形上下文的center)
4.34 從圖形上下文獲取新的圖片
4.35 關閉圖形上下文
四.二維碼的識別
1.獲取相冊中的二維碼
1.1 怎么獲取相冊?
1.11 創建照片選擇控制器
1.12 設置照片的來源類型
1.13 設置代理
1.14 彈出控制器
// 1.創建照片選擇控制器 let ipc = UIImagePickerController() // 2.設置來源的類型 ipc.sourceType = .PhotoLibrary // 3.設置代理 ipc.delegate = self // 4.彈出控制器 presentViewController(ipc, animated: true, completion: nil) 在代理方法中實現 選中圖片dismiss掉控制器 func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { //選中照片 imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage picker.dismissViewControllerAnimated(true, completion: nil) }
2.識別二維碼的步驟
2.1 創建 CIDetector對象(識別器)
2.2 獲取圖片,並將圖片轉成 CIIImage
2.3 識別圖片中的二維碼(得到一個數組,圖片中可能有多個二維碼)
2.4 遍歷數組
// 1.創建識別器 let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: nil) // 2.獲取圖片,並且將圖片轉成CIIImage let image = imageView.image! guard let ciImage = CIImage(image: image) else { return } // 3.識別圖片中二維碼 let features = detector.featuresInImage(ciImage) // 4.遍歷數組中所有的元素 for f in features { // feature類型是CIFeature 要轉換成二維碼類型 CIQRCodeFeature guard let qrCodeF = f as? CIQRCodeFeature else { continue } //打印二維碼的信息 print(qrCodeF.messageString) }
五.掃描二維碼(需要真機操作)
1.掃描二維碼界面搭建
1.1 主要就是掃描框的搭建
掃描框中再加上一個ImageView,給ImageView一個動畫 模擬正在掃描(沖擊波)
1.2 掃描框是一張圖片,沖擊波也是一張圖片,他們的位置和尺寸是一樣的
為了方便以后更改控件的位置,可以用一個view把掃描框和沖擊波封裝在里面
1.3 掃描動畫(沖擊波)動畫怎么做?
1.31 設置沖擊波的底部約束相對於父控件(view)有一個間距
1.32 更改約束的間距,來達到動畫的效果
// 1.改變約束(原來約束為-240) scanViewBottomCons.constant = 240 // 2.執行動畫 UIView.animateWithDuration(1.0) { UIView.setAnimationRepeatCount(MAXFLOAT) self.qrCodeView.layoutIfNeeded() }
2.掃描二維碼
2.1 掃描步驟
2.11 創建捕捉會話(需要導入AVFoundation框架)
2.12 設置輸入(攝像頭)
2.13 設置輸出 Metadata
2.14 添加預覽圖層(可以沒有)
預覽圖層是為了讓用戶知道掃描到哪里了,一般為了用戶體驗,都會添加
2.15 開始掃描
源代碼:建議不要死記,用的時候直接拷貝
// 1.創建捕捉會話 let session = AVCaptureSession() // 2.設置輸入(攝像頭) let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) guard let input = try? AVCaptureDeviceInput(device: device) else { return } session.addInput(input) // 3.設置輸出(Metadata) let output = AVCaptureMetadataOutput() // 設置代理 output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) session.addOutput(output) // 設置output的輸出的類型(該類型的設置必須在添加到session之后) output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] // 4.添加預覽圖層(可以沒有) let previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = view.bounds view.layer.insertSublayer(previewLayer, atIndex: 0) // 5.開始掃描 session.startRunning()
3.獲取掃描結果
3.1設置代理,在代理方法中拿到結果
代理方法
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { guard let objc = metadataObjects.last as? AVMetadataMachineReadableCodeObject else { return } print(objc.stringValue) }
5.設置掃描區域.
5.1 為什么要設置掃描區域?
掃描二維碼,發現只要二維碼進入攝像頭區域,就能直接掃描
要求是進入掃描框,才進行掃描
5.2 怎么設置掃描區域?
通過設置 output.rectOfInterest屬性來設置掃描區域
// 設置掃描的區域 let screenW = UIScreen.mainScreen().bounds.width let screenH = UIScreen.mainScreen().bounds.height let x : CGFloat = qrCodeView.frame.origin.x / screenW let y : CGFloat = qrCodeView.frame.origin.y / screenH let w : CGFloat = qrCodeView.frame.width / screenW let h : CGFloat = qrCodeView.frame.height / screenH output.rectOfInterest = CGRect(x: y, y: x, width: h, height: w)
注意:掃描區域的坐標系與屏幕的坐標系正好相反 ( 掃描區域x = 屏幕坐標系 y)
5.3 設置掃描區域代碼寫到哪里?
掃描區域屬於 輸出的一個屬性,應該寫到創建輸出代碼的后邊
下載源代碼點擊這里:
源代碼鏈接
