flutter_deck 0.14.0 copy "flutter_deck: ^0.14.0" to clipboard
flutter_deck: ^0.14.0 copied to clipboard

A lightweight, customizable, and easy-to-use framework to create presentations in Flutter.

flutter_deck #

style: very good analysis License: MIT FlutterDeck Header

Demo: https://mkobuolys.github.io/flutter_deck/

Features ๐Ÿช„ #

  • ๐Ÿ’™ Slide deck is built as any other Flutter app.
  • ๐Ÿงญ Navigator 2.0 support - each slide is rendered as an individual page with a deep link to it.
  • ๐Ÿพ Steps - each slide can have multiple steps that can be navigated through.
  • ๐ŸŽ“ Presenter view - control your presentation from a separate screen or (even) device.
  • โš™๏ธ Define a global configuration once and override it per slide if needed.
  • ๐Ÿš€ Predictable API to access the slide deck state and its methods from anywhere in the app.
  • ๐Ÿ“ฆ Out of the box slide templates, widgets, transitions and controls.
  • ๐ŸŽจ Custom theming and light/dark mode support.
  • ๐ŸŒ Built-in localization support.

Table of contents #

๐Ÿ’ป Installation #

โ— In order to start using flutter_deck you must have the Flutter SDK installed on your machine.

Add flutter_deck to your pubspec.yaml:

dependencies:
  flutter_deck:

Install it:

flutter packages get

๐Ÿง‘โ€๐Ÿ’ป Hello flutter_deck! #

Use FlutterDeckApp as your slide deck's root widget and pass a list of FlutterDeckSlideWidget widgets to it:

void main() {
  runApp(const FlutterDeckExample());
}

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

  @override
  Widget build(BuildContext context) {
    // This is an entry point for the Flutter Deck app.
    return FlutterDeckApp(
      configuration: const FlutterDeckConfiguration(...),
      slides: [
        <...>
      ],
    );
  }
}

Also, you can define a global configuration for your slide deck:

FlutterDeckApp(
  configuration: FlutterDeckConfiguration(
    background: const FlutterDeckBackgroundConfiguration(
      light: FlutterDeckBackground.solid(Color(0xFFB5FFFC)),
      dark: FlutterDeckBackground.solid(Color(0xFF16222A)),
    ),
    controls: const FlutterDeckControlsConfiguration(
      presenterToolbarVisible: true,
      shortcuts: FlutterDeckShortcutsConfiguration(
        enabled: true,
        nextSlide: SingleActivator(LogicalKeyboardKey.arrowRight),
        previousSlide: SingleActivator(LogicalKeyboardKey.arrowLeft),
        toggleMarker: SingleActivator(
          LogicalKeyboardKey.keyM,
          control: true,
          meta: true,
        ),
        toggleNavigationDrawer: SingleActivator(
          LogicalKeyboardKey.period,
          control: true,
          meta: true,
        ),
      ),
    ),
    footer: const FlutterDeckFooterConfiguration(
      showSlideNumbers: true,
      widget: FlutterLogo(),
    ),
    header: const FlutterDeckHeaderConfiguration(
      showHeader: false,
    ),
    marker: const FlutterDeckMarkerConfiguration(
      color: Colors.cyan,
      strokeWidth: 8.0,
    ),
    progressIndicator: const FlutterDeckProgressIndicator.gradient(
      gradient: LinearGradient(
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        colors: [Colors.pink, Colors.purple],
      ),
      backgroundColor: Colors.black,
    ),
    slideSize: FlutterDeckSlideSize.fromAspectRatio(
      aspectRatio: const FlutterDeckAspectRatio.ratio16x10(),
      resolution: const FlutterDeckResolution.fromWidth(1440),
    ),
    transition: const FlutterDeckTransition.fade(),
  ),
  <...>
);

Use any colors you like:

FlutterDeckApp(
  lightTheme: FlutterDeckThemeData.light(),
  darkTheme: FlutterDeckThemeData.dark(),
  themeMode: ThemeMode.system,
  <...>
);

And do not forget to introduce yourself!

FlutterDeckApp(
  speakerInfo: const FlutterDeckSpeakerInfo(
    name: 'John Doe',
    description: 'CEO of flutter_deck',
    socialHandle: '@john_doe',
    imagePath: 'assets/me.png',
  ),
  <...>
);

๐Ÿ“ƒ Slide templates #

To create a slide, extend the FlutterDeckSlideWidget class and override the build method that returns a FlutterDeckSlide widget. FlutterDeckSlide supports a few predefined slide templates that help you to create a slide faster.

// Extend the FlutterDeckSlideWidget class...
class NewSlide extends FlutterDeckSlideWidget {
  const NewSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/new-slide',
            title: 'New slide',
          ),
        );

  // ...override the build method...
  @override
  FlutterDeckSlide build(BuildContext context) {
    // ...and create a new FlutterDeckSlide instance.
  }
}

Title slide #

To create a title slide, use the FlutterDeckSlide.title constructor. It is responsible for rendering the default header and footer of the slide deck, and placing the title and subtitle in the correct places. Also, if the FlutterDeckSpeakerInfo is set, it will render the speaker info below the title and subtitle.

class TitleSlide extends FlutterDeckSlideWidget {
  const TitleSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/title-slide',
            title: 'Title slide',
            footer: FlutterDeckFooterConfiguration(showFooter: false),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.title(
      title: 'Here goes the title of the slide',
      subtitle: 'Here goes the subtitle of the slide (optional)',
    );
  }
}

Title slide example

Blank slide #

To create a title slide, use the FlutterDeckSlide.blank constructor. It is responsible for rendering the default header and footer of the slide deck, and rendering the content of the slide using the provided builder.

class BlankSlide extends FlutterDeckSlideWidget {
  const BlankSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/blank-slide',
            header: FlutterDeckHeaderConfiguration(
              title: 'Blank slide template',
            ),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.blank(
      builder: (context) => const Text('Here goes the content of the slide'),
    );
  }
}

Blank slide example

Big fact slide #

To create a big fact slide, use the FlutterDeckSlide.bigFact constructor. It is responsible for rendering the title (fact) with the description (subtitle) below it.

class BigFactSlide extends FlutterDeckSlideWidget {
  const BigFactSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/big-fact',
            header: FlutterDeckHeaderConfiguration(
              title: 'Big fact slide template',
            ),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.bigFact(
      title: '100%',
      subtitle: 'The test coverage value that flutter_deck will probably never achieve',
      theme: FlutterDeckTheme.of(context).copyWith(
        bigFactSlideTheme: const FlutterDeckBigFactSlideThemeData(
          titleTextStyle: TextStyle(color: Colors.amber),
        ),
      ),
    );
  }
}

Big fact slide example

Image slide #

To create an image slide, use the FlutterDeckSlide.image constructor. It is responsible for rendering the default header and footer of the slide deck, and rendering the image using the provided imageBuilder.

class ImageSlide extends FlutterDeckSlideWidget {
  const ImageSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/image-slide',
            header: FlutterDeckHeaderConfiguration(
              title: 'Image slide template',
            ),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.image(
      imageBuilder: (context) => Image.asset('assets/image.png'),
      label: 'Here goes the label of the image (optional)',
    );
  }
}

Image slide example

Quote slide #

To create a quote slide, use the FlutterDeckSlide.quote constructor. It is responsible for rendering the quote and attribution below it.

class QuoteSlide extends FlutterDeckSlideWidget {
  const QuoteSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/quote',
            header: FlutterDeckHeaderConfiguration(
              title: 'Quote slide template',
            ),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.quote(
      quote: '"If you really look closely, most overnight successes took a long time."',
      attribution: '- Steve Jobs',
      theme: FlutterDeckTheme.of(context).copyWith(
        quoteSlideTheme: const FlutterDeckQuoteSlideThemeData(
          quoteTextStyle: TextStyle(color: Colors.yellowAccent),
        ),
      ),
    );
  }
}

Quote slide example

Split slide #

To create a split slide, use the FlutterDeckSlide.split constructor. It is responsible for rendering the default header and footer of the slide deck, and use the leftBuilder and rightBuilder to create the content of the left and right columns. Make sure to use text styles from Theme or FlutterDeckTheme to apply the correct text styling for specific slide sections.

class SplitSlide extends FlutterDeckSlideWidget {
  const SplitSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/split-slide',
            header: FlutterDeckHeaderConfiguration(
              title: 'Split slide template',
            ),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.split(
      leftBuilder: (context) {
        return Text(
          'Here goes the LEFT section content of the slide',
          style: FlutterDeckTheme.of(context).textTheme.bodyMedium,
        );
      },
      rightBuilder: (context) {
        return Text(
          'Here goes the RIGHT section content of the slide',
          style: FlutterDeckTheme.of(context).textTheme.bodyMedium,
        );
      },
    );
  }
}

Split slide example

Template slide #

To create a custom template slide, use the FlutterDeckSlide.template constructor. It is responsible for placing the header, footer, and content of the slide in the correct places. Also, it is responsible for displaying the background of the slide.

class TemplateSlide extends FlutterDeckSlideWidget {
  const TemplateSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/template-slide',
            title: 'Template slide',
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.template(
      backgroundBuilder: (context) => FlutterDeckBackground.solid(
        Theme.of(context).colorScheme.background,
      ),
      contentBuilder: (context) => const ColoredBox(
        color: Colors.red,
        child: Text('Content goes here...'),
      ),
      footerBuilder: (context) => ColoredBox(
        color: Theme.of(context).colorScheme.secondary,
        child: const Text('Footer goes here...'),
      ),
      headerBuilder: (context) => ColoredBox(
        color: Theme.of(context).colorScheme.primary,
        child: const Text('Header goes here...'),
      ),
    );
  }
}

FlutterDeckSlideBase

Custom slide #

To create a custom slide (without any predefined template), use the FlutterDeckSlide.custom constructor and pass a custom builder to it.

class CustomSlide extends FlutterDeckSlideWidget {
  const CustomSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/custom-slide',
            title: 'Custom slide',
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.custom(
      builder: (context) {
        return const Text('Here goes your custom slide content...');
      },
    );
  }
}

๐Ÿช„ Generating slides #

This package comes with a mason template that can be used to generate a new slide for the slide deck.

Ensure you have the mason_cli installed:

dart pub global activate mason_cli

Install the flutter_deck_slide template:

# Install locally
mason add flutter_deck_slide

# Install globally
mason add -g flutter_deck_slide

Generate a new slide:

mason make flutter_deck_slide

๐ŸŽจ Theming #

You can customize the theme of your slide deck by providing a FlutterDeckThemeData to the FlutterDeckApp widget:

return FlutterDeckApp(
  // You can define light...
  lightTheme: FlutterDeckThemeData.fromTheme(
    ThemeData.from(
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFFB5FFFC),
      ),
      useMaterial3: true,
    ),
  ),
  // ...and dark themes.
  darkTheme: FlutterDeckThemeData.fromTheme(
    ThemeData.from(
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFF16222A),
        brightness: Brightness.dark,
      ),
      useMaterial3: true,
    ),
  ),
);

It's also possible to override the theme for a specific slide. The provided theme data will be merged with the global theme. Meaning, only the properties you specify there are overridden:

class ThemingSlide extends FlutterDeckSlideWidget {
  const ThemingSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/theming-slide',
            header: FlutterDeckHeaderConfiguration(title: 'Theming'),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.split(
      theme: FlutterDeckTheme.of(context).copyWith(
        splitSlideTheme: const FlutterDeckSplitSlideThemeData(
          leftBackgroundColor: Colors.blue,
          leftColor: Colors.yellow,
          rightBackgroundColor: Colors.yellow,
          rightColor: Colors.blue,
        ),
      ),
      leftBuilder: (context) => <...>
      rightBuilder: (context) => <...>
    );
  }
}

Also, you can override the theme for a specific flutter deck widget that supports theming (e.g. header, footer, bullet list, code highlight, etc.). Simply, wrap the widget with a corresponding theme widget:

FlutterDeckSlide.template(
  // Wrap header with a theme widget to override the theme.
  headerBuilder: (context) => FlutterDeckHeaderTheme(
    data: FlutterDeckHeaderThemeData(
      color: Colors.red,
      textStyle: FlutterDeckTheme.of(context).textTheme.header,
    ),
    child: const FlutterDeckHeader(title: 'Header'),
  ),
  // Wrap footer with a theme widget to override the theme.
  footerBuilder: (context) => FlutterDeckFooterTheme(
    data: FlutterDeckFooterThemeData(
      socialHandleColor: Colors.blue,
      socialHandleTextStyle:
          FlutterDeckTheme.of(context).textTheme.bodyMedium,
    ),
    child: const FlutterDeckFooter(showSlideNumber: false),
  ),
  contentBuilder: (context) => Center(
    // Wrap code highlight with a theme widget to override the theme.
    child: FlutterDeckCodeHighlightTheme(
      data: FlutterDeckCodeHighlightThemeData(
        backgroundColor: Colors.green,
        textStyle: FlutterDeckTheme.of(context).textTheme.bodyLarge,
      ),
      child: const FlutterDeckCodeHighlight(code: '<...>'),
    ),
  ),
);

๐Ÿ™ˆ Slide visibility #

By default, all slides are visible and available in the slide deck. However, you can hide a slide by setting the hidden property to true for the slide configuration:

class HiddenSlide extends FlutterDeckSlideWidget {
  const HiddenSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/hidden',
            hidden: true, // Sets the slide to be hidden
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.blank(
      builder: (context) => const Center(
        child: Text("This slide is hidden. Oh, but you can't see it..."),
      ),
    );
  }
}

๐Ÿงฑ Widgets #

This package comes with a few predefined widgets that could be used in your slide deck.

FlutterDeckBulletList #

A widget that renders a list of bullet points. Bullet point items are rendered as a row with a bullet point and the text. The bullet point is rendered as a dot by default, but can be customized by providing a bulletPointWidget. The text is rendered as an AutoSizeText widget and is automatically resized to fit the available space.

If useSteps is true for the slide configuration, the bullet points will be rendered one by one as the user steps through the slide.

You can use stepOffset to offset the step number for the first item in the list. For instance, if you set stepOffset to 1, the first item will only be visible when the user steps to the second step. Remember to increase the number of steps for the slide configuration if you use stepOffset.

class FlutterDeckBulletListDemoSlide extends FlutterDeckSlideWidget {
  const FlutterDeckBulletListDemoSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/bullet-list-demo',
            title: 'Bullet list demo',
            steps: 3, // Define the number of steps for the slide
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.split(
      leftBuilder: (context) => FlutterDeckBulletList(
        useSteps: true, // Enable steps for the bullet list
        items: const [
          'This is a step',
          'This is another step',
          'This is a third step',
        ],
      ),
      rightBuilder: (context) => const Text('FlutterDeckBulletList demo'),
    );
  }
}

FlutterDeckCodeHighlight #

Provides a widget that gives you customizable syntax highlighting for many languages.

class CodeHighlightSlide extends FlutterDeckSlideWidget {
  const CodeHighlightSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/code-highlight',
            header: FlutterDeckHeaderConfiguration(title: 'Code Highlighting'),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.blank(
      builder: (context) => const Center(
        child: FlutterDeckCodeHighlight(
          code: '''
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';

class CodeHighlightSlide extends FlutterDeckSlideWidget {
  const CodeHighlightSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/code-highlight',
            header: FlutterDeckHeaderConfiguration(title: 'Code Highlighting'),
          ),
        );

  @override
  FlutterDeckSlide build(BuildContext context) {
    return FlutterDeckSlide.blank(
      builder: (context) => const Center(
        child: Text('Use FlutterDeckCodeHighlight widget to highlight code!'),
      ),
    );
  }
}''',
          fileName: 'code_highlight_slide.dart',
          language: 'dart',
        ),
      ),
    );
  }
}

FlutterDeckCodeHighlight

๐Ÿ“ฆ Accessing slide deck state from the code #

By using the FlutterDeck extensions, you can access the slide deck state and its methods from anywhere in the app:

@override
Widget build(BuildContext context) {
  // Retrieve the FlutterDeck instance from the context.
  // Or by using the extension method: context.flutterDeck
  final flutterDeck = FlutterDeck.of(context);

  // Retrieve the FlutterDeckRouter instance for this slide deck.
  final router = flutterDeck.router;
  // Retrieve the current slide configuration.
  final configuration = flutterDeck.configuration;
  // Retrieve the global slide deck configuration.
  final globalConfiguration = flutterDeck.globalConfiguration;
  // Retrieve the speaker info.
  final speakerInfo = flutterDeck.speakerInfo;

  // Go to the next slide.
  flutterDeck.next();
  // Go to the previous slide.
  flutterDeck.previous();

  // Retrieve the current slide number.
  final slideNumber = flutterDeck.slideNumber;
  // Go to the first slide.
  flutterDeck.goToSlide(1);

  // Retrieve the current step number.
  final stepNumber = flutterDeck.stepNumber;
  // Go to the first step.
  flutterDeck.goToStep(1);

  <...>
}

๐Ÿ”€ Transitions #

This package comes with a few predefined transitions that can be used for your slides:

  • FlutterDeckTransition.none (default)
  • FlutterDeckTransition.fade
  • FlutterDeckTransition.scale
  • FlutterDeckTransition.slide
  • FlutterDeckTransition.rotation
  • FlutterDeckTransition.custom

You can specify a transition for the whole slide deck:

FlutterDeckApp(
  configuration: const FlutterDeckConfiguration(
    transition: FlutterDeckTransition.fade(),
  ),
  <...>
);

Or you can specify a transition for a specific slide:

class TransitionsSlide extends FlutterDeckSlideWidget {
  const TransitionsSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/transitions',
            title: 'Transitions',
            transition: FlutterDeckTransition.rotation(), // Specify the transition for the slide
          ),
        );

  <...>
}

FlutterDeckTransition.custom accepts a FlutterDeckTransitionBuilder that can be extended to create a custom transition:

class VerticalTransitionBuilder extends FlutterDeckTransitionBuilder {
  const VerticalTransitionBuilder();

  @override
  Widget build(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    return SlideTransition(
      position: animation.drive(
        Tween<Offset>(
          begin: const Offset(0, 1),
          end: Offset.zero,
        ).chain(CurveTween(curve: Curves.easeIn)),
      ),
      child: child,
    );
  }
}

class CustomTransitionSlide extends FlutterDeckSlideWidget {
  const CustomTransitionSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/custom-transition',
            title: 'Custom transition',
            transition: FlutterDeckTransition.custom(
              transitionBuilder: VerticalTransitionBuilder(),
            ),
          ),
        );

  <...>
}

๐Ÿพ Steps #

Steps is a feature that allows you to navigate through a slide, well, step by step. You can access the current step from any widget. This way, you can reveal or hide content, run animations, etc.

To enable steps for a slide, you need to set the steps property for the slide configuration:

class StepsDemoSlide extends FlutterDeckSlideWidget {
  const StepsDemoSlide()
      : super(
          configuration: const FlutterDeckSlideConfiguration(
            route: '/steps-demo',
            title: 'Steps demo',
            steps: 2,
          ),
        );

  <...>
}

To trigger a rebuild of the widget when the step changes, you can use the FlutterDeckSlideStepsBuilder widget:

@override
Widget build(BuildContext context) {
  return FlutterDeckSlideStepsBuilder(
    builder: (context, stepNumber) => stepNumber == 1
        ? const Text('This is the first step.')
        : const Text('This is the second step.'),
  );
}

Or you can use the FlutterDeckSlideStepsListener to trigger side effects when the step changes:

@override
Widget build(BuildContext context) {
  return FlutterDeckSlideStepsListener(
    listener: (context, stepNumber) {
      print('Current step: $stepNumber');
    },
    child: const Text('Steps demo slide'),
  );
}

Steps demo

๐ŸŒ Localization #

This package comes with a built-in localization support. You can change the locale of the slide deck at runtime (see controls). The updated locale will be applied to the whole slide deck.

To localize the slide deck, follow the instructions provided in the official Flutter documentation.

Then, provide AppLocalizations when creating the slide deck:

FlutterDeckApp(
  <...>
  locale: const Locale('en'), // The initial locale of the slide deck
  localizationsDelegates: AppLocalizations.localizationsDelegates,
  supportedLocales: AppLocalizations.supportedLocales,
);

๐ŸŽฎ Controls #

By default, every slide deck comes with a presenter toolbar that can be used to control the slide deck. Also, some of the controls can be accessed by using keyboard shortcuts.

To disable all the controls (e.g. you use your own UI to control the slide deck), set the controls property for the slide deck configuration to FlutterDeckControlsConfiguration.disabled():

FlutterDeckConfiguration(
  controls: FlutterDeckControlsConfiguration.disabled(),
  <...>
)

To disable the presenter toolbar, set the presenterToolbarVisible property to false:

FlutterDeckConfiguration(
  controls: const FlutterDeckControlsConfiguration(
    presenterToolbarVisible: false,
  ),
  <...>
)

To disable the keyboard shortcuts, set the shortcuts property to FlutterDeckShortcutsConfiguration(enabled: false):

FlutterDeckConfiguration(
  controls: const FlutterDeckControlsConfiguration(
    shortcuts: FlutterDeckShortcutsConfiguration(enabled: false),
  ),
  <...>
)

Every slide deck comes with a navigation drawer that can be used to navigate through the slide deck. The navigation drawer is automatically generated based on the slide deck configuration.

The navigation drawer item title is generated based on the following rules:

  • The slide title is used if it is set in the slide configuration (FlutterDeckSlideConfiguration.title).
  • If the slide title is not set, the header title is used if it is set in the slide header configuration (FlutterDeckHeaderConfiguration.title).
  • The slide route is used otherwise.

Navigation demo

Marker tool #

The marker tool allows you to draw on top of the slide. It can be used to highlight specific parts of the slide, or to draw anything you want. The tool is available in the presenter toolbar, or just press "M" on your keyboard (it's also possible to specify a custom key binding for the toggleMarker shortcut in FlutterDeckShortcutsConfiguration).

Marker demo

Auto-play #

The auto-play feature allows you to automatically navigate through the slide deck. It can be used to create a presentation that runs on its own. The auto-play feature is available in the presenter toolbar.

Auto-play demo

Changing locale #

You can change the locale of the slide deck at runtime. The updated locale will be applied to the whole slide deck. The locale can be changed using the presenter toolbar.

Localization demo

๐ŸŽ“ Presenter view #

The presenter view allows you to control your presentation from a separate screen or (even) device. It displays the current slide, speaker notes, and a timer.

Presenter view demo

To enable the presenter view, you to use one of the flutter_deck_client implementations. The client synchronizes the state of the slide deck with the presenter view and vice versa.

(Web only) flutter_deck_web_client #

If you plan to run your slide deck on the web, it is recommended to use the flutter_deck_web_client package. This client does not require any server-side code to run and works out of the box on any Web browser.

All you need to do is to add the package to your pubspec.yaml:

dependencies:
  flutter_deck_web_client: any

And pass the FlutterDeckWebClient to the FlutterDeckApp widget:

FlutterDeckApp(
  client: const FlutterDeckWebClient(), // Use the Web client
  configuration: const FlutterDeckConfiguration(...),
  slides: [
    <...>
  ],
);

flutter_deck_ws_client #

This client is a WebSocket-based implementation that requires a server-side code to run. The server-side code is responsible for synchronizing the state of the slide deck with the presenter view and vice versa. However, this implementation can be used on any platform. E.g., you can control your slide deck from your mobile device.

To use the client, add the flutter_deck_ws_client package to your pubspec.yaml:

dependencies:
  flutter_deck_ws_client: any

Extract your FlutterDeckApp widget to a separate file:

/// flutter_deck_example.dart
class FlutterDeckExample extends StatelessWidget {
  const FlutterDeckExample({
    required this.isPresenterView,
    super.key,
  });

  final bool isPresenterView;

  @override
  Widget build(BuildContext context) {
    return FlutterDeckApp(
      client: FlutterDeckWsClient(uri: Uri.parse('ws://localhost:8080')), // Use the WebSocket client
      isPresenterView: isPresenterView,
      <...>
    );
  }
}

Then, create two entry points for your slide deck: one for the presenter view and one for the slide deck itself:

/// main.dart
void main() {
  runApp(const FlutterDeckExample(isPresenterView: false));
}
/// main_presenter.dart
void main() {
  runApp(const FlutterDeckExample(isPresenterView: true));
}

Launch the WebSocket server, e.g., flutter_deck_ws_server:

# Install the dart_frog cli from source
dart pub global activate dart_frog_cli

# Start the dev server
dart_frog dev

Launch your presentation as two separate Flutter applications:

# Run the slide deck
flutter run -t main.dart

# Run the presenter view
flutter run -t main_presenter.dart

๐Ÿš€ Presentations built with flutter_deck #

Title Language Author
Let me introduce you to Flutter English Mangirdas Kazlauskas
Control your Flutter application on the fly with Firebase Remote Config English Mangirdas Kazlauskas
Introduction to Flutter Web Portuguese Arthur Fรผcher
Make smarter decisions faster with Firebase Remote Config English Mangirdas Kazlauskas & Darja Orlova
Flutter for the win: Cross-platform development at maximum power Italian Alberto Bonacina
ReArch: A Reactive Approach to Application Architecture Supporting Side Effects English Gregory Conrad
Flutter demo Dutch Thijs Pirmez
Build Dynamic Slide Decks with Flutter English / Japanese Tsuyoshi Chujo
147
likes
140
pub points
75%
popularity

Publisher

verified publisherkazlauskas.dev

A lightweight, customizable, and easy-to-use framework to create presentations in Flutter.

Homepage
Repository (GitHub)
View/report issues

Topics

#flutterdeck #presentation #slides

Documentation

API reference

Funding

Consider supporting this project:

github.com

License

MIT (LICENSE)

Dependencies

auto_size_text, flutter, flutter_deck_client, flutter_highlight, go_router, url_launcher

More

Packages that depend on flutter_deck