์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
- BFS
- Swfit
- BOJ
- swift
- designpattern
- tableView
- reactorkit
- Flutter
- TCA
- Xcode
- XCTest
- node.js
- ํจ์คํธ์บ ํผ์ค
- raywenderlich
- rxcocoa
- ํ๋ก๊ทธ๋๋จธ์ค
- RxSwift
- combine
- SwiftUI
- ๋ฐฑ์ค
- ios
- SnapKit
- CollectionView
- arkit
- visionOS
- UIKit
- realm
- MVVM
- Lv2
- Kuring
- Today
- Total
lgvv98
[SwiftUI] QRcodeReader ๋ณธ๋ฌธ
QRcodeReader
โ QRcodeReader๋ฅผ ์์๋ณด์.
์ฝ๋๋ ์ด๋ ต์ง ์๋ค.
๋์ฌ๊ฒจ ๋ณผ ์ ์ ํ๋์ ํ์ผ์์ ์ฌ๋ฌ๊ฐ์ ๋ทฐ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ณผ ์ ์๊ฒ ๋ค
๐ ์๋๋ ์คํ์์ค !_!
https://github.com/twostraws/CodeScanner
GitHub - twostraws/CodeScanner: A SwiftUI view that is able to scan barcodes, QR codes, and more, and send back what was found.
A SwiftUI view that is able to scan barcodes, QR codes, and more, and send back what was found. - GitHub - twostraws/CodeScanner: A SwiftUI view that is able to scan barcodes, QR codes, and more, a...
github.com
โ QRCodeScannerExampleView
import SwiftUI
struct QRCodeScannerExampleView: View {
@State var isPresentingScanner = false // sheet ๋์์ฃผ๊ธฐ ์ํ ๋ณ์
@State var scannedCode: String?
var body: some View {
ZStack{
if self.scannedCode != nil {
MyWebview(urlToLoad: self.scannedCode!)
} else {
MyWebview(urlToLoad: "https://www.naver.com")
}
VStack{
Spacer()
Button(action: {
self.isPresentingScanner = true
}){
Text("๋ก๋๋ฒํธํ์ธ")
.font(.system(size: 20))
.fontWeight(.bold)
.padding()
.background(Color.yellow)
.cornerRadius(12)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(lineWidth: 5)
)
}
.sheet(isPresented: $isPresentingScanner) {
self.scannerSheet
}
Spacer().frame(height: 30) // spacer์๋ frame์ง์ ๊ฐ๋ฅ
}
}
}
// ํ๋์ ํ์ผ์์ view๋ฅผ ์ฌ์ฉํ ๋์ ๊ตฌ์กฐ
var scannerSheet: some View {
ZStack {
CodeScannerView(
codeTypes: [.qr],
completion: { result in
if case let .success(code) = result {
self.scannedCode = code
self.isPresentingScanner = false
}
}
)
QRCodeGuideLineView() // ZStack์ผ๋ก ๊ฐ์ด๋๋ผ์ธ ๋ทฐ๋ฅผ ๋ง๋ค๊ธฐ
}
}
}
โ QRCodeGuideLineView
import SwiftUI
struct QRCodeGuideLineView: View {
var body: some View {
GeometryReader{ geometryProxy in
RoundedRectangle(cornerRadius: 20)
// stroke๋ฅผ ํตํด ๋ด๋ถ๋ฅผ ๋น๊ฒ ๋ง๋ญ๋๋ค, dash: ์ ์ ์ผ๋ก ๋ง๋ญ๋๋ค.
.stroke(style: StrokeStyle(lineWidth: 10, dash: [11]))
.frame(
width: geometryProxy.size.width / 2,
height: geometryProxy.size.height / 3
)
// geometry ํ๋ก์๋ก ํฌ์ง์
์ ์ฃผ๋ฉด ๋๋ค.
.position(
x: geometryProxy.size.width / 2,
y: geometryProxy.size.height / 2
)
.foregroundColor(Color.yellow)
}
}
}
1. ์ค์บ๋๋ฅผ ์ฐ๊ธฐ์ ์ ๊ธฐ๋ณธ url์ ๋ค์ด๋ฒ๋ก ์ธํ
2. ์ค์บ๋ ๊ฐ์ด๋๋ผ์ธ๊ณผ ์นด๋ฉ๋ผ๋ก ์ฐ๋๋ค.
3. ์ธ์๋๋ฉด ํด๋น url๋ก ์ด๋
๐ ์ฃผ์์ฌํญ
์นด๋ฉ๋ผ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด info.plist์ ํด๋น ๊ถํ์ ๋ฃ์ด์ฃผ์ด์ผ ํ๋ค.
โ ์คํ์์ค์์ ์ ๊ณตํ๋ ์ฝ๋!
//
// CodeScannerView.swift
//
// Created by Paul Hudson on 10/12/2019.
// Copyright © 2019 Paul Hudson. All rights reserved.
//
import AVFoundation
import SwiftUI
/// A SwiftUI view that is able to scan barcodes, QR codes, and more, and send back what was found.
/// To use, set `codeTypes` to be an array of things to scan for, e.g. `[.qr]`, and set `completion` to
/// a closure that will be called when scanning has finished. This will be sent the string that was detected or a `ScanError`.
/// For testing inside the simulator, set the `simulatedData` property to some test data you want to send back.
public struct CodeScannerView: UIViewControllerRepresentable {
public enum ScanError: Error {
case badInput, badOutput
}
public class ScannerCoordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
var parent: CodeScannerView
var codeFound = false
init(parent: CodeScannerView) {
self.parent = parent
}
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if let metadataObject = metadataObjects.first {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
guard let stringValue = readableObject.stringValue else { return }
guard codeFound == false else { return }
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: stringValue)
// make sure we only trigger scans once per use
codeFound = true
}
}
func found(code: String) {
parent.completion(.success(code))
}
func didFail(reason: ScanError) {
parent.completion(.failure(reason))
}
}
#if targetEnvironment(simulator)
public class ScannerViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
var delegate: ScannerCoordinator?
override public func loadView() {
view = UIView()
view.isUserInteractionEnabled = true
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.text = "์๋ฎฌ๋ ์ดํฐ๋ก ๋๋ฆฌ์
จ๊ตฐ์ - ์ค์ ๊ธฐ๊ธฐ๋ก ํ
์คํธ ๋ถํ๋ฐ๋๋๋ค."
label.textAlignment = .center
// let button = UIButton()
// button.translatesAutoresizingMaskIntoConstraints = false
// button.setTitle("Or tap here to select a custom image", for: .normal)
// button.setTitleColor(UIColor.systemBlue, for: .normal)
// button.setTitleColor(UIColor.gray, for: .highlighted)
// button.addTarget(self, action: #selector(self.openGallery), for: .touchUpInside)
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 50
stackView.addArrangedSubview(label)
// stackView.addArrangedSubview(button)
view.addSubview(stackView)
NSLayoutConstraint.activate([
// button.heightAnchor.constraint(equalToConstant: 50),
stackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let simulatedData = delegate?.parent.simulatedData else {
print("Simulated Data Not Provided!")
return
}
delegate?.found(code: simulatedData)
}
@objc func openGallery(_ sender: UIButton){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
if let qrcodeImg = info[.originalImage] as? UIImage {
let detector:CIDetector=CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])!
let ciImage:CIImage=CIImage(image:qrcodeImg)!
var qrCodeLink=""
let features=detector.features(in: ciImage)
for feature in features as! [CIQRCodeFeature] {
qrCodeLink += feature.messageString!
}
if qrCodeLink=="" {
delegate?.didFail(reason: .badOutput)
}else{
delegate?.found(code: qrCodeLink)
}
}
else{
print("Something went wrong")
}
self.dismiss(animated: true, completion: nil)
}
}
#else
public class ScannerViewController: UIViewController {
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!
var delegate: ScannerCoordinator?
override public func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(updateOrientation),
name: Notification.Name("UIDeviceOrientationDidChangeNotification"),
object: nil)
view.backgroundColor = UIColor.black
captureSession = AVCaptureSession()
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
} catch {
return
}
if (captureSession.canAddInput(videoInput)) {
captureSession.addInput(videoInput)
} else {
delegate?.didFail(reason: .badInput)
return
}
let metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(delegate, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = delegate?.parent.codeTypes
} else {
delegate?.didFail(reason: .badOutput)
return
}
}
override public func viewWillLayoutSubviews() {
previewLayer?.frame = view.layer.bounds
}
@objc func updateOrientation() {
guard let orientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation else { return }
guard let connection = captureSession.connections.last, connection.isVideoOrientationSupported else { return }
connection.videoOrientation = AVCaptureVideoOrientation(rawValue: orientation.rawValue) ?? .portrait
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.layer.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
updateOrientation()
captureSession.startRunning()
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (captureSession?.isRunning == false) {
captureSession.startRunning()
}
}
override public func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (captureSession?.isRunning == true) {
captureSession.stopRunning()
}
NotificationCenter.default.removeObserver(self)
}
override public var prefersStatusBarHidden: Bool {
return true
}
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
}
#endif
public let codeTypes: [AVMetadataObject.ObjectType]
public var simulatedData = ""
public var completion: (Result<String, ScanError>) -> Void
public init(codeTypes: [AVMetadataObject.ObjectType], simulatedData: String = "", completion: @escaping (Result<String, ScanError>) -> Void) {
self.codeTypes = codeTypes
self.simulatedData = simulatedData
self.completion = completion
}
public func makeCoordinator() -> ScannerCoordinator {
return ScannerCoordinator(parent: self)
}
public func makeUIViewController(context: Context) -> ScannerViewController {
let viewController = ScannerViewController()
viewController.delegate = context.coordinator
return viewController
}
public func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {
}
}
struct CodeScannerView_Previews: PreviewProvider {
static var previews: some View {
CodeScannerView(codeTypes: [.qr]) { result in
// do nothing
}
}
}
'apple > ๐ SwiftUI & Combine' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SwiftUI] TextField, SecureField (0) | 2022.05.23 |
---|---|
[SwiftUI] ButtonStyle (0) | 2022.05.23 |
[SwiftUI 3.0] State/ Binding / EnvironmentObject (0) | 2022.05.19 |
[SwiftUI] TabView + CustomTabView (0) | 2022.05.19 |
[SwiftUI] GeometryReader (0) | 2022.05.19 |