Interactive tutorials for flutter apps, without messing up your code.
Using this package enables you to:
- 📜 Separate your tutorial logic and code from the rest of your application
- 🧙♀️ Create complex interactive tutorials, that go beyond highlighting important widgets of your app (although that is possible as well, of course!)
- ⏫ Add more than one tutorial to your app
Find extensive information on how to use this package in the example and documentation.
These are the basic steps to get you started:
- Create the enum that provides your tutorial IDs:
enum ExampleTutorialID implements TutorialID {
// Keys
floatingButtonKey,
// Conditions
counterWasIncreased,
// Contexts
}
- Create your tutorial class that extends or implements
TutorialContainer
and define the tutorial steps:
class ExampleTutorial extends TutorialContainer {
@override
String getName() => "Example tutorial";
@override
List<TutorialStep> get tutorialSteps => [
WidgetHighlightTutorialStep(
tutorialText: "Click here to increase the counter",
tutorialID: ExampleTutorialID.floatingButtonKey),
WaitForConditionTutorialStep(tutorialID: ExampleTutorialID.counterWasIncreased),
PlainTextTutorialStep(tutorialText: "You successfully pressed the button! Tutorial finished..")
];
}
- Create a tutorial key repository and add a global navigator key:
class MyApp extends StatelessWidget {
final GlobalKey<NavigatorState> _globalNavigatorKey = GlobalKey<NavigatorState>();
MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (_) => tutorialRepository(_globalNavigatorKey),
child: MaterialApp(
navigatorKey: _globalNavigatorKey,
title: 'Flutter Demo',
theme: ThemeData(...)));
- In the
MyHomePage
widget, add a floatingActionButton key:
final GlobalKey _floatingActionButtonKey = GlobalKey();
(...)
floatingActionButton: FloatingActionButton(
key: _floatingActionButtonKey,
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
- Create an extension for the
_MyHomePageState
to separate the tutorial registration:
extension _ExampleTutorialExt on _MyHomePageState {
void registerExampleTutorial() {
final tutorialRepository tutorialRepository = context.read<tutorialRepository>();
tutorialRepository.registerKey(ExampleTutorialID.floatingButtonKey, _floatingActionButtonKey);
tutorialRepository.registerCondition(ExampleTutorialID.counterWasIncreased, (timeout) {
return TutorialStepWithWaiting.conditionWithTimeout(timeout, () => _counter > 0);
});
}
}
- Call the extension method in the
initState
function of_MyHomePageState
:
@override
void initState() {
super.initState();
registerExampleTutorial();
}
- Add a
TutorialStartButton
in the build method to start the tutorial:
final ExampleTutorial exampleTutorial = ExampleTutorial();
(...)
TutorialStartButton(
buttonBuilder: (onPressed) =>
ElevatedButton(onPressed: onPressed, child: Text("Start Tutorial: ${exampleTutorial.getName()}")),
tutorial: exampleTutorial,
)