tutorial_coach_mark
tutorial_coach_mark copied to clipboard
Launching tutorial from service without a context
I'm trying to decouple the logic of my app from the widget-side. In order to do so, I've created a TutorialService which launches the tutorial from the business logic-side. However, a BuildContext is needed in order to start the tutorial. In other situations like this (e.g. opening dialogs), getting a reference to the BuildContext using a navigator key and the navigatorKey.currentContext does the trick, bit it does not seem to work for this use case.
The problem is in the call to Overlay.of(...). I've tried following calls, and all of them return a null OverlayState:
Overlay.of(navigatorKey.currentContext, rootOverlay: false);
Overlay.of(navigatorKey.currentState!.context, rootOverlay: false);
Overlay.of(navigatorKey.currentState!.overlay!.context, rootOverlay: false);
Can this be done?
Hi @Pitazzo ! Do you tried create the TutorialCoachMark with navigatorKey.currentContext ?
Something like this:
TutorialCoachMark(navigatorKey.currentContext);
hi @RafaelBarbosatec
yes, that was exactly what I tried. That isn't working because of Overlay.of(...) being unable to get the OverlayState object
Now you don't need create a Tutorial with context. Just need context to show. You can use the navigator context to do this.
@pitazzo hey! Have you found a solution? I'm facing the same issue.
A quick workaround is to add Overlay to MaterialApp but it doesn't feel right
return MaterialApp(
navigatorKey: navKey,
builder: (context, child) =>
Overlay(initialEntries: [OverlayEntry(builder: (context) => child!)]),
...
)
Btw @RafaelBarbosatec yes indeed, we need the context just to show, but the navigator context throws the mentioned error No Overlay widget found.
Here's the full error
flutter: No Overlay widget found.
Some widgets require an Overlay widget ancestor for correct operation.
The most common way to add an Overlay to an application is to include a MaterialApp, CupertinoApp or Navigator widget in the runApp() call.
The context from which that widget was searching for an overlay was:
Navigator-[LabeledGlobalKey<NavigatorState>#9d9d4 Key Created by default]
flutter:
#0 Overlay.of.<anonymous closure> (package:flutter/src/widgets/overlay.dart:384:9)
#1 Overlay.of (package:flutter/src/widgets/overlay.dart:387:6)
#2 TutorialCoachMark.show.<anonymous closure> (package:tutorial_coach_mark/tutorial_coach_mark.dart:95:17)
#3 new Future.delayed.<anonymous closure> (dart:async/future.dart:424:39)
#4 _rootRun (dart:async/zone.dart:1390:47)
#5 _CustomZone.run (dart:async/zone.dart:1300:19)
#6 _CustomZone.runGuarded (dart:async/zone.dart:1208:7)
#7 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1248:23)
#8 _rootRun (dart:async/zone.dart:1398:13)
#9 _CustomZone.run (dart:async/zone.dart:1300:19)
#10 _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1232:23)
#11 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#12 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#13 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#14 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
@RafaelBarbosatec
here is minimal reproducible example for this issue:
import 'package:flutter/material.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
TargetFocus target = TargetFocus(
identify: "Target 1",
keyTarget: GlobalKey(),
contents: [TargetContent()],
);
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(
MaterialApp(
navigatorKey: navigatorKey,
home: const MyAppView(),
),
);
}
class MyAppView extends StatelessWidget {
const MyAppView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('tutorial_coach_mark_issue_demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'target',
key: target.keyTarget,
),
const SizedBox(height: 100),
ElevatedButton(
onPressed: () {
// Doesn't work
// Throws: No Overlay widget found.
TutorialCoachMark(targets: [target]).show(context: navigatorKey.currentContext!);
},
child: const Text('show tutorial'),
),
],
),
),
);
}
}
I've made pull request #158 to fix this