Show custom widget with ScaffoldMessenger

Viewed 110

I’d like to have a widget in my application that operates much in the same way as a MaterialBanner with ScaffoldMessenger. But I’d like to customize the appearance of banner.

Is there a way that I can customize the appearance of MaterialBanner? In my initial experimentation I thought of extending it, but in the end I found that wasn’t really going to work. Also for a brief second I thought thought type casting a custom widget in my call to showMaterialBanner might work, but quickly ruled that out.

There's a few things I'm struggling to figure out how to address through the MaterialBanner widget, if it's still possible:

  • I don't like (for lack of a better term) the grey overlay to the banner area that's applied. I'm not sure where to adjust that. I've tried setting the background color to white and transparent and it still shows up ultimately as an off white.
  • Actions. I intend to make the actions within the banner content. currently I'm passing a SizedBox.shrink() per another SO question
3 Answers

Edit: Here is an example showing what I believe you are looking for.

A MaterialBanner is already customizable. Place your desired widget in the content param or actions list.

ScaffoldMessenger.of(context).showMaterialBanner(
  MaterialBanner(
    content: const Text('This is a MaterialBanner'), // <- This can be whatever you want
    actions: <Widget>[
      TextButton(
        onPressed: () => ScaffoldMessenger.of(context).hideCurrentMaterialBanner(),
        child: const Text('DISMISS'), 
      ), // <- So can these
    ],
  ),
);

you can change styles of MaterialBanner ( outer widget ) in your app theme :

MaterialApp(
  .
  .
  theme: ThemeData(
    .
    .
    .
    bannerTheme: MaterialBannerThemeData(
      backgroundColor: ,
      contentTextStyle: ,
      elevation: ,
      leadingPadding: ,
    ),
  ),
);

and if you want change structure of inner widget you can pass any widget to content :

MaterialBanner(
  content: Row(
    children: const[
      Icon(Icons.check),
      Expanded(
        child: Text('This is a MaterialBanner'),
      ),
    ],
  ),
  actions: [
    TextButton(
      onPressed: () => ScaffoldMessenger.of(context).hideCurrentMaterialBanner(),
      child: const Text('DISMISS'),
    ),
  ],
);

I wanted to do something similar for standardization / reuse. Creating a custom widget seemed more trouble than it was worth so I used a function instead.

MaterialBanner materialBannerException(BuildContext ctx, String msg) {
  return MaterialBanner(
    actions: [
      IconButton(
        onPressed: () {
          ScaffoldMessenger.of(ctx).hideCurrentMaterialBanner();
        },
        icon: Icon(
          Icons.close,
          color: Theme.of(ctx).colorScheme.onErrorContainer,
        ),
      ),
    ],
    backgroundColor: Theme.of(ctx).colorScheme.errorContainer,
    content: Text(
      msg,
      style: TextStyle(color: Theme.of(ctx).colorScheme.onErrorContainer),       
    ),
    leading: Icon(
      Icons.error,
      color: Theme.of(ctx).colorScheme.onErrorContainer,
    ),
  );
}
Related