# Conflicts: # example/ios/Runner.xcodeproj/project.pbxprojflutter-beta
| @@ -3,6 +3,14 @@ | |||||
| A QR code scanner that works on both iOS and Android by natively embedding the platform view within Flutter. The integration with Flutter is seamless, much better than jumping into a native Activity or a ViewController to perform the scan. | A QR code scanner that works on both iOS and Android by natively embedding the platform view within Flutter. The integration with Flutter is seamless, much better than jumping into a native Activity or a ViewController to perform the scan. | ||||
| # *Warning* | |||||
| If you are using Flutter Beta or Dev channel (1.25 or 1.26) you can get the following error: | |||||
| `java.lang.AbstractMethodError: abstract method "void io.flutter.plugin.platform.PlatformView.onFlutterViewAttached(android.view.View)"` | |||||
| This is a bug in Flutter which is being tracked here: https://github.com/flutter/flutter/issues/72185 | |||||
| There is a workaround by adding `android.enableDexingArtifactTransform=false` to your `gradle.properties` file. | |||||
| ## Screenshots | ## Screenshots | ||||
| <table> | <table> | ||||
| @@ -56,12 +64,16 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| Barcode result; | Barcode result; | ||||
| QRViewController controller; | QRViewController controller; | ||||
| /// Overriding reassemble and pausing the camera | |||||
| /// ensures us that hot reload won't give a black screen | |||||
| // In order to get hot reload to work we need to pause the camera if the platform | |||||
| // is android, or resume the camera if the platform is iOS. | |||||
| @override | @override | ||||
| void reassemble() { | void reassemble() { | ||||
| super.reassemble(); | super.reassemble(); | ||||
| controller.pauseCamera(); | |||||
| if (Platform.isAndroid) { | |||||
| controller.pauseCamera(); | |||||
| } else if (Platform.isIOS) { | |||||
| controller.resumeCamera(); | |||||
| } | |||||
| } | } | ||||
| @override | @override | ||||
| @@ -47,12 +47,16 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| QRViewController controller; | QRViewController controller; | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | ||||
| /// Overriding reassemble and pausing the camera | |||||
| /// ensures us that hot reload won't give a black screen | |||||
| // In order to get hot reload to work we need to pause the camera if the platform | |||||
| // is android, or resume the camera if the platform is iOS. | |||||
| @override | @override | ||||
| void reassemble() { | void reassemble() { | ||||
| super.reassemble(); | super.reassemble(); | ||||
| controller.pauseCamera(); | |||||
| if (Platform.isAndroid) { | |||||
| controller.pauseCamera(); | |||||
| } else if (Platform.isIOS) { | |||||
| controller.resumeCamera(); | |||||
| } | |||||
| } | } | ||||
| @override | @override | ||||
| @@ -69,7 +73,8 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| if (result != null) | if (result != null) | ||||
| Text('Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') | |||||
| Text( | |||||
| 'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}') | |||||
| else | else | ||||
| Text('Scan a code'), | Text('Scan a code'), | ||||
| Row( | Row( | ||||
| @@ -162,11 +167,17 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| } | } | ||||
| Widget _buildQrView(BuildContext context) { | Widget _buildQrView(BuildContext context) { | ||||
| // For this example we check how width or tall the device is and change the scanArea and overlay accordingly. | |||||
| var scanArea = (MediaQuery.of(context).size.width < 400 || | |||||
| MediaQuery.of(context).size.height < 400) | |||||
| ? 150.0 | |||||
| : 300.0; | |||||
| // To ensure the Scanner view is properly sizes after rotation | // To ensure the Scanner view is properly sizes after rotation | ||||
| // we need to listen for Flutter SizeChanged notification and update controller | // we need to listen for Flutter SizeChanged notification and update controller | ||||
| return NotificationListener<SizeChangedLayoutNotification>( | return NotificationListener<SizeChangedLayoutNotification>( | ||||
| onNotification: (notification) { | onNotification: (notification) { | ||||
| Future.microtask(() => controller?.updateDimensions(qrKey)); | |||||
| Future.microtask( | |||||
| () => controller?.updateDimensions(qrKey, scanArea: scanArea)); | |||||
| return false; | return false; | ||||
| }, | }, | ||||
| child: SizeChangedLayoutNotifier( | child: SizeChangedLayoutNotifier( | ||||
| @@ -179,7 +190,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| borderRadius: 10, | borderRadius: 10, | ||||
| borderLength: 30, | borderLength: 30, | ||||
| borderWidth: 10, | borderWidth: 10, | ||||
| cutOutSize: 300, | |||||
| cutOutSize: scanArea, | |||||
| ), | ), | ||||
| ))); | ))); | ||||
| } | } | ||||
| @@ -201,6 +212,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| } | } | ||||
| ``` | ``` | ||||
| @@ -148,7 +148,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| Widget _buildQrView(BuildContext context) { | Widget _buildQrView(BuildContext context) { | ||||
| // For this example we check how width or tall the device is and change the scanArea and overlay accordingly. | // For this example we check how width or tall the device is and change the scanArea and overlay accordingly. | ||||
| var scanArea = (MediaQuery.of(context).size.width < 500 || | |||||
| var scanArea = (MediaQuery.of(context).size.width < 400 || | |||||
| MediaQuery.of(context).size.height < 400) | MediaQuery.of(context).size.height < 400) | ||||
| ? 150.0 | ? 150.0 | ||||
| : 300.0; | : 300.0; | ||||
| @@ -13,18 +13,15 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| var scanner: MTBBarcodeScanner? | var scanner: MTBBarcodeScanner? | ||||
| var registrar: FlutterPluginRegistrar | var registrar: FlutterPluginRegistrar | ||||
| var channel: FlutterMethodChannel | var channel: FlutterMethodChannel | ||||
| var frame: CGRect | |||||
| public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){ | public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){ | ||||
| self.registrar = registrar | self.registrar = registrar | ||||
| self.frame = frame | |||||
| previewView = UIView(frame: frame) | previewView = UIView(frame: frame) | ||||
| channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | ||||
| } | } | ||||
| func isCameraAvailable(success: Bool) -> Void { | func isCameraAvailable(success: Bool) -> Void { | ||||
| if success { | if success { | ||||
| do { | do { | ||||
| try scanner?.startScanning(resultBlock: { [weak self] codes in | try scanner?.startScanning(resultBlock: { [weak self] codes in | ||||
| if let codes = codes { | if let codes = codes { | ||||
| @@ -56,7 +53,6 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| default: | default: | ||||
| return | return | ||||
| } | } | ||||
| guard let stringValue = code.stringValue else { continue } | guard let stringValue = code.stringValue else { continue } | ||||
| let result = ["code": stringValue, "type": typeString] | let result = ["code": stringValue, "type": typeString] | ||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | self?.channel.invokeMethod("onRecognizeQR", arguments: result) | ||||