tutorial_overlay
tutorial_overlay
is a Flutter package for building interactive, step-by-step tutorials that highlight and point to widgets across multiple screens with customizable indicators.
✨ Key Features
- Cross-Screen & Multi-Step Guidance: Guide users through your app’s features across multiple screens.
- Widget Highlighting: Visually emphasize specific UI elements with customizable indicators
- Customizable UI: Match tutorials to your app’s style by customizing tooltips with any widget (text, buttons, images) and indicators like arrows or shapes with your choice of colors and sizes.
🎮 Live Demo
Explore the interactive example:
git clone https://github.com/xinyi-chong/tutorial_overlay.git
cd tutorial_overlay/example
flutter run
📸 Showcase
Here are some examples showcasing the features of tutorial_overlay
:
Tutorial Across Pages | Dynamic Updates | Custom Indicator | Tutorial without Target Widget |
---|---|---|---|
![]() Guides users through multiple app screens. |
![]() Updates content, e.g., for language changes. |
![]() |
![]() |
🚀 Getting started
Installation
Add tutorial_overlay
to your pubspec.yaml
and fetch the package:
dependencies:
tutorial_overlay: ^<latest_version>
flutter pub get
Or install directly:
flutter pub add tutorial_overlay
Import
import 'package:tutorial_overlay/tutorial_overlay.dart';
🛠 How To Use
1. Set Up Tutorial
Create a Tutorial
instance to define steps, using a unique tutorialId
(e.g., 'home'
) to organize tutorials for different app sections (e.g., 'home'
for onboarding, 'profile'
for profile setup). You can customize individual steps with styles (e.g., indicator
) to override defaults set in TutorialOverlay
(next step). Wrap your app with the tutorial provider to enable tutorials.
Highlight a Widget (Optional)
If you want to highlight a specific widget during the tutorial (e.g., a button or text), assign a GlobalKey
to it. This key uniquely identifies the widget for the tutorial to target. Skip this step for steps that don’t highlight a widget:
final widgetToHighlightKey = GlobalKey();
Text(
key: widgetToHighlightKey,
'This text will be highlighted in the tutorial',
)
Set Up Tutorial
Create a Tutorial
with steps for each tutorialId
. Wrap your app with Tutorial.provide
:
void main() {
final tutorial = Tutorial<String>({
'home': [ // Tutorial for the home screen
TutorialStep(
widgetKey: widgetToHighlightKey, // Highlights a specific widget
child: Column(
children: [
const Text('Welcome to the app! This highlights a key feature.'),
ElevatedButton(
onPressed: () => tutorial.nextStep('home'),
child: const Text('Next'),
),
],
),
),
TutorialStep( // No widgetKey: shows general instructions
child: Column(
children: [
const Text('The tutorial has ended.'),
ElevatedButton(
onPressed: () => tutorial.endTutorial('home'),
child: const Text('Close'),
),
],
),
),
],
'profile': [ // Tutorial for the profile screen
TutorialStep(
child: Column(
children: [
Text('Set up your profile.'),
ElevatedButton(
onPressed: () => tutorial.endTutorial('profile'),
child: Text('Close'),
),
],
),
),
],
});
runApp(Tutorial.provide(tutorial: tutorial, child: const MyApp()));
}
2. Wrap Pages with TutorialOverlay
Wrap each page with TutorialOverlay
and specify the tutorialId
that matches the tutorial defined in the Tutorial
instance. Set the required tooltip width
and optionally define default styling (e.g., indicator,
padding), which apply unless overridden in a TutorialStep
:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TutorialOverlay<String>(
tutorialId: 'home', // Matches the `home` key in the tutorial map
// Default styling for all steps in this overlay
width: 320, // Required
dismissOnTap: false,
padding: EdgeInsets.all(20),
indicator: Icon(Icons.star, size: 24), // Default indicator
indicatorHeight: 24, // Required with indicator for tooltip positioning
indicatorWidth: 24, // Required with indicator for tooltip positioning
child: const MyHomePage(),
),
);
}
}
3. Control the Tutorial
Use these methods to manage the tutorial flow:
tutorial.startTutorial('home'); // Start the 'home' tutorial
tutorial.nextStep('home'); // Move to the next step; ends if last step
tutorial.previousStep('home'); // Move to the previous step
tutorial.endTutorial('home'); // End the 'home' tutorial
Handle Navigation
To navigate between pages during the tutorial, provide the context
for routing:
// Navigate to a new route
tutorial.nextStep('home', route: '/your-page', context: context);
// Go back to the previous page
tutorial.previousStep('home', backToPreviousPage: true, context: context);
4. Update Tutorials Dynamically
Modify tutorials after initialization, e.g., for language changes:
// Define a function to build or update tutorials
Map<String, List<TutorialStep>> buildTutorials(String language) {
return {
'home': [
TutorialStep(
child: Column(
children: [
Text(language == 'en' ? 'Welcome!' : '欢迎!'),
ElevatedButton(
onPressed: () => tutorial.endTutorial('home'),
child: const Text('Close'),
),
],
),
),
],
};
}
// Initialize and update the tutorial
void main() {
final tutorial = Tutorial<String>(buildTutorials('en')); // Initial tutorial in English
runApp(Tutorial.provide(tutorial: tutorial, child: const MyApp()));
// Example: Update tutorial for Chinese
tutorial.updateTutorial(buildTutorials('zh'));
}
5. Properties & Styling
Set default styles in TutorialOverlay
to apply to all steps, and override them in TutorialStep
for individual steps.
TutorialOverlay
: Default Styling
Property | Type | Description | Default Value |
---|---|---|---|
child |
Widget |
Screen content to overlay. Required. | None (required) |
tutorialId |
T |
A unique identifier for the tutorial. Required. | None (required) |
width |
double |
Tooltip container width. Required. | None (required) |
height |
double? |
Optional tooltip container height. | null |
decoration |
Decoration? |
Optional tooltip decoration. | null |
padding |
EdgeInsetsGeometry? |
Optional tooltip content padding. | null |
dismissOnTap |
bool |
End tutorial on tap outside tooltip. | true |
indicator |
Widget? |
Default indicator widget to point at the target widget. Set indicatorHeight and indicatorWidth for tooltip positioning. |
null |
indicatorHeight |
double? |
Default indicator height, required if indicator is set. |
null |
indicatorWidth |
double? |
Default indicator width, required if indicator is set. |
null |
overlayColor |
Color |
Overlay color outside the target widget. | Colors.black54 |
radius |
double |
Corner radius of the highlight area around the target widget. | 4 |
focusOverlayPadding |
EdgeInsets? |
Optional padding for the highlighted area around the target widget. | null |
TutorialStep
: Custom Styling for Individual Steps
Property | Type | Description | Default Value |
---|---|---|---|
child |
Widget |
Tooltip content. Required. | None (required) |
widgetKey |
GlobalKey? |
Key of the widget to highlight. | null |
showAbove |
Decoration? |
Show tooltip above (true) or below (false) the target. Auto determined if null. | null |
indicator |
Widget? |
Override TutorialOverlay.indicator . Set indicatorHeight and indicatorWidth for tooltip positioning. |
null |
indicatorHeight |
double? |
Override TutorialOverlay.indicatorHeight , required if indicator is set. |
null |
indicatorWidth |
double? |
Override TutorialOverlay.indicatorWidth , required if indicator is set. |
null |
focusOverlayPadding |
EdgeInsets? |
Optional padding for the highlighted area around the target widget. | null |
For a complete list of all classes' properties and methods, refer to the API documentation on pub.dev.
📋 Additional Notes
- Ensure
GlobalKey
is unique for each widget to avoid conflicts. - Provide
context
for navigation to ensure proper routing in multi-screen tutorials. - Use distinct
tutorialId
values (e.g.,'home'
,'profile'
) to manage multiple tutorials within the same app.
For more details, refer to the example folder in the repository.
Troubleshooting
- Tutorial not showing: Ensure
tutorialId
matches betweenTutorial
andTutorialOverlay
. - Widget not highlighted: Verify the
GlobalKey
is attached to a rendered widget. - Navigation errors: Confirm the
context
is from the correct navigator.
🐛 Report bugs or request features via Issues.