Skip to content

Commit b5ebf1e

Browse files
Merge pull request #3 from miquido/feature/detected_image_tapping
iOS - handle tapping on detected image
2 parents cf4e47c + b1ac507 commit b5ebf1e

File tree

7 files changed

+64
-16
lines changed

7 files changed

+64
-16
lines changed

example/lib/main.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ class _MyAppState extends State<MyApp> {
3232
});
3333
}
3434

35+
void _onDetectedImageTapped(BuildContext context, String? imageName) {
36+
if (imageName != null) {
37+
ScaffoldMessenger.of(context).showSnackBar(
38+
SnackBar(
39+
content: Text('Tapped on image: $imageName'),
40+
duration: const Duration(milliseconds: 1500),
41+
),
42+
);
43+
}
44+
}
45+
3546
@override
3647
Widget build(BuildContext context) {
3748
return MaterialApp(
@@ -46,6 +57,7 @@ class _MyAppState extends State<MyApp> {
4657
ARQuidoView(
4758
referenceImageNames: const ['applandroid'],
4859
onImageDetected: (imageName) => _onImageDetected(context, imageName),
60+
onDetectedImageTapped: (imageName) => _onDetectedImageTapped(context, imageName),
4961
),
5062
],
5163
);

ios/Classes/ARImageScannerView/ARQuidoViewController.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ protocol ImageRecognitionDelegate: AnyObject {
88
func onRecognitionPaused()
99
func onRecognitionResumed()
1010
func onDetect(imageKey: String)
11+
func onDetectedImageTapped(imageKey: String)
1112
}
1213

1314
class ARQuidoViewController: UIViewController {
@@ -47,6 +48,8 @@ class ARQuidoViewController: UIViewController {
4748
sceneView = ARSCNView(frame: CGRect.zero)
4849
sceneView.delegate = self
4950
sceneView.session.delegate = self
51+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
52+
sceneView.addGestureRecognizer(tapGesture)
5053
view = sceneView
5154
}
5255

@@ -62,6 +65,16 @@ class ARQuidoViewController: UIViewController {
6265
onRecognitionPaused()
6366
}
6467

68+
@objc
69+
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
70+
let location = gestureRecognize.location(in: sceneView)
71+
let hitResults = sceneView.hitTest(location, options: [:])
72+
if hitResults.count > 0, let tappedImageName = hitResults[0].node.name {
73+
onDetectedImageTapped(imageKey: tappedImageName)
74+
}
75+
76+
}
77+
6578
// MARK: - Session management (Image detection setup)
6679

6780
/// Prevents restarting the session while a restart is in progress.
@@ -107,9 +120,11 @@ extension ARQuidoViewController: ARSCNViewDelegate {
107120
}
108121

109122
let referenceImage = imageAnchor.referenceImage
123+
let imageName = referenceImage.name ?? ""
110124
updateQueue.async {
111125
let plane = SCNBox(width: referenceImage.physicalSize.width, height: referenceImage.physicalSize.height, length: 0.3, chamferRadius: 0.01)
112126
let planeNode = SCNNode(geometry: plane)
127+
planeNode.name = imageName
113128
planeNode.opacity = 0.75
114129
planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 205 / 255, green: 207 / 255, blue: 1.0, alpha: 1.0)
115130
//rotate plane to match assumed image orientation
@@ -120,7 +135,6 @@ extension ARQuidoViewController: ARSCNViewDelegate {
120135
}
121136

122137
DispatchQueue.main.async {
123-
let imageName = referenceImage.name ?? ""
124138
self.onDetect(imageKey: imageName)
125139
}
126140
}
@@ -234,4 +248,8 @@ extension ARQuidoViewController: ImageRecognitionDelegate {
234248
func onDetect(imageKey: String) {
235249
methodChannel.invokeMethod("scanner#onImageDetected", arguments: ["imageName": imageKey])
236250
}
251+
252+
func onDetectedImageTapped(imageKey: String) {
253+
methodChannel.invokeMethod("scanner#onDetectedImageTapped", arguments: ["imageName": imageKey])
254+
}
237255
}

lib/src/ar_quido_method_channel.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class ARQuidoMethodChannel extends ARQuidoPlatform {
3636
@override
3737
Stream<ImageDetectedEvent> onImageDetected() => _scannerEventStreamController.stream.whereType<ImageDetectedEvent>();
3838

39+
@override
40+
Stream<ImageTappedEvent> onDetectedImageTapped() =>
41+
_scannerEventStreamController.stream.whereType<ImageTappedEvent>();
42+
3943
@override
4044
Stream<RecognitionStartedEvent> onRecognitionStarted() =>
4145
_scannerEventStreamController.stream.whereType<RecognitionStartedEvent>();
@@ -67,6 +71,11 @@ class ARQuidoMethodChannel extends ARQuidoPlatform {
6771
final imageName = arguments['imageName'];
6872
_scannerEventStreamController.add(ImageDetectedEvent(imageName));
6973
break;
74+
case 'scanner#onDetectedImageTapped':
75+
final arguments = (call.arguments as Map).cast<String, String?>();
76+
final imageName = arguments['imageName'];
77+
_scannerEventStreamController.add(ImageTappedEvent(imageName));
78+
break;
7079
case 'scanner#error':
7180
final arguments = (call.arguments as Map).cast<String, String?>();
7281
final error = arguments['errorCode'];

lib/src/ar_quido_platform.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ abstract class ARQuidoPlatform extends PlatformInterface {
3636
throw UnimplementedError('onImageDetected() has not been implemented.');
3737
}
3838

39+
Stream<ImageTappedEvent> onDetectedImageTapped() {
40+
throw UnimplementedError('onImageDetected() has not been implemented.');
41+
}
42+
3943
Stream<RecognitionStartedEvent> onRecognitionStarted() {
4044
throw UnimplementedError(
4145
'onRecognitionStarted() has not been implemented.',

lib/src/types/scanner_event.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ class ImageDetectedEvent extends ScannerEvent {
66
final String? imageName;
77
}
88

9+
class ImageTappedEvent extends ScannerEvent {
10+
ImageTappedEvent(this.imageName);
11+
12+
final String? imageName;
13+
}
14+
915
class RecognitionStartedEvent extends ScannerEvent {}
1016

1117
class RecognitionResumedEvent extends ScannerEvent {}

lib/src/view/ar_quido_view.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class ARQuidoView extends StatefulWidget {
1111
const ARQuidoView({
1212
required this.referenceImageNames,
1313
required this.onImageDetected,
14+
this.onDetectedImageTapped,
1415
this.onViewCreated,
1516
this.onRecognitionStarted,
1617
this.onRecognitionPaused,
@@ -22,6 +23,7 @@ class ARQuidoView extends StatefulWidget {
2223
final List<String> referenceImageNames;
2324
final void Function(ARQuidoViewController controller)? onViewCreated;
2425
final void Function(String? imageName) onImageDetected;
26+
final void Function(String? imageName)? onDetectedImageTapped;
2527
final VoidCallback? onRecognitionStarted;
2628
final VoidCallback? onRecognitionPaused;
2729
final VoidCallback? onRecognitionResumed;

lib/src/view/ar_quido_view_controller.dart

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,37 +28,34 @@ class ARQuidoViewController {
2828
final scannerViewWidget = _scannerViewState.widget;
2929
if (scannerViewWidget.onRecognitionStarted != null) {
3030
_subscriptions.add(
31-
platformInstance.onRecognitionStarted().listen(
32-
(event) => _scannerViewState.widget.onRecognitionStarted!(),
33-
),
31+
platformInstance.onRecognitionStarted().listen((event) => _scannerViewState.widget.onRecognitionStarted!()),
3432
);
3533
}
3634
if (scannerViewWidget.onRecognitionResumed != null) {
3735
_subscriptions.add(
38-
platformInstance.onRecognitionResumed().listen(
39-
(event) => _scannerViewState.widget.onRecognitionResumed!(),
40-
),
36+
platformInstance.onRecognitionResumed().listen((event) => _scannerViewState.widget.onRecognitionResumed!()),
4137
);
4238
}
4339
if (scannerViewWidget.onRecognitionPaused != null) {
4440
_subscriptions.add(
45-
platformInstance.onRecognitionPaused().listen(
46-
(event) => _scannerViewState.widget.onRecognitionPaused!(),
47-
),
41+
platformInstance.onRecognitionPaused().listen((event) => _scannerViewState.widget.onRecognitionPaused!()),
4842
);
4943
}
5044
if (scannerViewWidget.onError != null) {
5145
_subscriptions.add(
52-
platformInstance.onError().listen(
53-
(event) => _scannerViewState.widget.onError!(event.error),
54-
),
46+
platformInstance.onError().listen((event) => _scannerViewState.widget.onError!(event.error)),
47+
);
48+
}
49+
if (scannerViewWidget.onDetectedImageTapped != null) {
50+
_subscriptions.add(
51+
platformInstance
52+
.onDetectedImageTapped()
53+
.listen((event) => scannerViewWidget.onDetectedImageTapped!(event.imageName)),
5554
);
5655
}
5756

5857
_subscriptions.add(
59-
platformInstance.onImageDetected().listen(
60-
(event) => scannerViewWidget.onImageDetected(event.imageName),
61-
),
58+
platformInstance.onImageDetected().listen((event) => scannerViewWidget.onImageDetected(event.imageName)),
6259
);
6360
}
6461
}

0 commit comments

Comments
 (0)