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