showMaterialBanner method

Shows a MaterialBanner across all registered Scaffolds. Scaffolds register to receive material banners from their closest ScaffoldMessenger ancestor. If there are several registered scaffolds the material banner is shown simultaneously on all of them.

A scaffold can show at most one material banner at a time. If this function is called while another material banner is already visible, the given material banner will be added to a queue and displayed after the earlier material banners have closed.

To remove the MaterialBanner with an exit animation, use hideCurrentMaterialBanner or call ScaffoldFeatureController.close on the returned ScaffoldFeatureController. To remove a MaterialBanner suddenly (without an animation), use removeCurrentMaterialBanner.

See ScaffoldMessenger.of for information about how to obtain the ScaffoldMessengerState.

Here is an example of showing a MaterialBanner when the user presses a button.

To see it in action, copy and run this code snippet on DartPad.

import 'package:material_ui/material_ui.dart';

/// Flutter code sample for [ScaffoldMessengerState.showMaterialBanner].

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ScaffoldMessengerState Sample')),
        body: const Center(child: ShowMaterialBannerExample()),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return OutlinedButton(
      onPressed: () {
        ScaffoldMessenger.of(context).showMaterialBanner(
          const MaterialBanner(
            content: Text('This is a MaterialBanner'),
            actions: <Widget>[
              TextButton(onPressed: null, child: Text('DISMISS')),
            ],
          ),
        );
      },
      child: const Text('Show MaterialBanner'),
    );
  }
}

Implementation

// TODO(framework): Replace the following block with a @dartpad directive
// when it's supported. https://github.com/dart-lang/dartdoc/issues/4123
/// {@macro material_ui.dartpad_guide}
///
/// {@example /example/lib/scaffold/scaffold_messenger_state.show_material_banner.0.dart#body}
///
/// </callout-box>
ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason> showMaterialBanner(
  MaterialBanner materialBanner,
) {
  assert(
    _scaffolds.isNotEmpty,
    'ScaffoldMessenger.showMaterialBanner was called, but there are currently no '
    'descendant Scaffolds to present to.',
  );
  _materialBannerController ??= MaterialBanner.createAnimationController(vsync: this)
    ..addStatusListener(_handleMaterialBannerStatusChanged);
  if (_materialBanners.isEmpty) {
    assert(_materialBannerController!.isDismissed);
    _materialBannerController!.forward();
  }
  late ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason> controller;
  controller = ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason>._(
    // We provide a fallback key so that if back-to-back material banners happen to
    // match in structure, material ink splashes and highlights don't survive
    // from one to the next.
    materialBanner.withAnimation(_materialBannerController!, fallbackKey: UniqueKey()),
    Completer<MaterialBannerClosedReason>(),
    () {
      assert(_materialBanners.first == controller);
      hideCurrentMaterialBanner();
    },
    null, // MaterialBanner doesn't use a builder function so setState() wouldn't rebuild it
  );
  setState(() {
    _materialBanners.addLast(controller);
  });
  _updateScaffolds();
  return controller;
}