tutorial_overlay_flutter 1.0.1 copy "tutorial_overlay_flutter: ^1.0.1" to clipboard
tutorial_overlay_flutter: ^1.0.1 copied to clipboard

A production-ready Flutter package for creating guided tutorial overlays, onboarding walkthroughs, and step-by-step UI showcases. Highly customizable with support for auto-scroll, persistence, custom [...]

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:tutorial_overlay_flutter/tutorial_overlay_flutter.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tutorial Overlay Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6C63FF)),
        useMaterial3: true,
      ),
      home: const HomeScreen(),
    );
  }
}

// ---------------------------------------------------------------------------
// Basic Usage
// ---------------------------------------------------------------------------

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // 1. Create GlobalKeys for widgets you want to highlight.
  final _menuKey = GlobalKey();
  final _searchKey = GlobalKey();
  final _profileKey = GlobalKey();
  final _fabKey = GlobalKey();
  final _listItemKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    // Start the tutorial after the first frame.
    WidgetsBinding.instance.addPostFrameCallback((_) => _startTutorial());
  }

  void _startTutorial() {
    // 2. Show the tutorial overlay.
    TutorialOverlay.show(
      context,
      steps: [
        TutorialStep(
          targetKey: _menuKey,
          title: 'Navigation Menu',
          description: 'Open the drawer to navigate between sections.',
          shape: HighlightShape.circle,
        ),
        TutorialStep(
          targetKey: _searchKey,
          title: 'Search',
          description: 'Quickly find any item using the search button.',
          shape: HighlightShape.circle,
        ),
        TutorialStep(
          targetKey: _profileKey,
          title: 'Your Profile',
          description: 'View and manage your account settings here.',
          shape: HighlightShape.circle,
        ),
        TutorialStep(
          targetKey: _listItemKey,
          title: 'Items List',
          description: 'Browse through your items. Tap any card for details.',
          padding: 4,
        ),
        TutorialStep(
          targetKey: _fabKey,
          title: 'Create New',
          description: 'Tap here to add a new item to your collection.',
          shape: HighlightShape.circle,
          padding: 12,
        ),
      ],
      config: const TutorialConfig(
        primaryColor: Color(0xFF6C63FF),
        overlayColor: Color(0xCC000000),
        enablePulseAnimation: true,
      ),
      onFinish: () => _showSnackBar('Tutorial completed!'),
      onSkip: () => _showSnackBar('Tutorial skipped.'),
    );
  }

  void _showSnackBar(String message) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message), duration: const Duration(seconds: 2)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          key: _menuKey,
          icon: const Icon(Icons.menu),
          onPressed: () {},
        ),
        title: const Text('Tutorial Demo'),
        actions: [
          IconButton(
            key: _searchKey,
            icon: const Icon(Icons.search),
            onPressed: () {},
          ),
          IconButton(
            key: _profileKey,
            icon: const Icon(Icons.person_outline),
            onPressed: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const AdvancedScreen()),
            ),
          ),
        ],
      ),
      body: ListView.builder(
        padding: const EdgeInsets.all(16),
        itemCount: 20,
        itemBuilder: (context, index) {
          return Card(
            key: index == 0 ? _listItemKey : null,
            margin: const EdgeInsets.only(bottom: 12),
            child: ListTile(
              leading: CircleAvatar(child: Text('${index + 1}')),
              title: Text('Item ${index + 1}'),
              subtitle: const Text('Tap to see details'),
              trailing: const Icon(Icons.chevron_right),
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        key: _fabKey,
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Advanced Customization
// ---------------------------------------------------------------------------

class AdvancedScreen extends StatefulWidget {
  const AdvancedScreen({super.key});

  @override
  State<AdvancedScreen> createState() => _AdvancedScreenState();
}

class _AdvancedScreenState extends State<AdvancedScreen> {
  final _headerKey = GlobalKey();
  final _toggleKey = GlobalKey();
  final _sliderKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => _startTutorial());
  }

  void _startTutorial() {
    TutorialOverlay.show(
      context,
      steps: [
        TutorialStep(
          targetKey: _headerKey,
          title: 'Settings Header',
          description: 'This section contains your key preferences.',
          tooltipPosition: TooltipPosition.bottom,
        ),
        TutorialStep(
          targetKey: _toggleKey,
          title: 'Dark Mode',
          description: 'Toggle between light and dark themes.',
        ),
        // Custom tooltip example.
        TutorialStep(
          targetKey: _sliderKey,
          title: 'Volume',
          tooltipBuilder: (context, info) => Container(
            padding: const EdgeInsets.all(20),
            decoration: BoxDecoration(
              gradient: const LinearGradient(
                colors: [Color(0xFF6C63FF), Color(0xFF3F3D9E)],
              ),
              borderRadius: BorderRadius.circular(16),
              boxShadow: const [
                BoxShadow(
                  color: Color(0x406C63FF),
                  blurRadius: 20,
                  offset: Offset(0, 8),
                ),
              ],
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  children: [
                    const Icon(Icons.volume_up, color: Colors.white, size: 20),
                    const SizedBox(width: 8),
                    Text(
                      info.title ?? '',
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                  ],
                ),
                const SizedBox(height: 8),
                const Text(
                  'Drag the slider to adjust notification volume.',
                  style: TextStyle(
                    fontSize: 14,
                    color: Colors.white70,
                    height: 1.4,
                  ),
                ),
                const SizedBox(height: 16),
                Row(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    GestureDetector(
                      onTap: info.isLast ? info.finish : info.next,
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 20,
                          vertical: 10,
                        ),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Text(
                          info.isLast ? 'Got it!' : 'Next',
                          style: const TextStyle(
                            color: Color(0xFF6C63FF),
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ],
      config: const TutorialConfig(
        primaryColor: Color(0xFF6C63FF),
        dismissOnOverlayTap: false,
        tooltipMaxWidth: 300,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Advanced Example')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              key: _headerKey,
              width: double.infinity,
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.primaryContainer,
                borderRadius: BorderRadius.circular(12),
              ),
              child: const Text(
                'Preferences',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
            const SizedBox(height: 24),
            SwitchListTile(
              key: _toggleKey,
              title: const Text('Dark Mode'),
              subtitle: const Text('Enable dark theme'),
              value: false,
              onChanged: (_) {},
            ),
            const SizedBox(height: 16),
            ListTile(
              key: _sliderKey,
              title: const Text('Volume'),
              subtitle: Slider(value: 0.7, onChanged: (_) {}),
            ),
          ],
        ),
      ),
    );
  }
}
0
likes
150
points
94
downloads

Documentation

API reference

Publisher

verified publisherbrewnbeer.com

Weekly Downloads

A production-ready Flutter package for creating guided tutorial overlays, onboarding walkthroughs, and step-by-step UI showcases. Highly customizable with support for auto-scroll, persistence, custom tooltips, and smooth animations.

Repository (GitHub)
View/report issues

Topics

#tutorial #overlay #onboarding #walkthrough #tooltip

License

MIT (license)

Dependencies

flutter

More

Packages that depend on tutorial_overlay_flutter