black_hole_flutter 0.2.12

  • Readme
  • Changelog
  • Example
  • Installing
  • 91

πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets.

πŸ“„ Bottom Sheet #

Show modal bottom sheets using: context.showModalBottomSheet().

FancyBottomSheet demo

Also, this package adds a custom FancyBottomSheet with a drag indicator at the top. You can create one using context.showFancyModalBottomSheet().

πŸ— BuildContext #

In Flutter, you often see the pattern <Class>.of(context) (e.g., Theme.of(context)). This package adds extension getters on BuildContext for those classes so you can just say:

ExtensionShortcut for
context.scaffoldOrNullScaffold.of(context, nullOk: true)

🎨 Colors #

Handy extensions on Brightness:

brightness.isDark≙ brightness == Brightness.dark
brightness.isLight≙ brightness == Brightness.light
brightness.oppositeopposite Brightness
brightness.colorColor representing this brightness, i.e.:
Β· Colors.white for Brightness.light
Β· for Brightness.dark
brightness.contrastColoropposite of brightness.color (above)

isDark, isLight & contrastColor can also be used on ThemeData directly.

Handy extensions on Color:

color.estimatedBrightnessestimated Brightness based on color's luminance
color.isOpaqueif opacity is 1.0
color.alphaBlendOn(Color background)resulting Color when drawing color on top of background
color.withAdditionalOpacity(double opacity)applies opacity by multiplying it to the existing opacity
color.withAdditionalAlpha(int alpha)like above, but with an integer alpha
color.hsl≙ HSLColor.fromColor(color)
color.hsv≙ HSVColor.fromColor(color)

And if you can't decide on a color, just use random.nextColor(), random.nextColorHsl() or random.nextColorHsv()!

Convert between alpha and opacity with int.alphaToOpacity & double.opacityToAlpha.

🌈 Material Design colors #

Material Design specifies different opacities of white and black colors to use for text of different emphases on colored backgrounds. You can now use the highEmphasisOnColor, mediumEmphasisOnColor and disabledOnColor extension getters on Color to make your text legible!

There are also getters on ThemeData for contrast colors on the primary, accent, background, and error colors.

🧭 Navigation #

Access your navigation-related information via extension methods:

ExtensionShortcut for
context.rootNavigatorNavigator.of(this, rootNavigator: true)

Push a new route and pop all previous routes (e.g., when signing out the user):

navigator.pushAndRemoveAll(/* new route */);
// Or using a named route:
navigator.pushNamedAndRemoveAll(/* route name */);

Log navigation events to the console:

  navigatorObservers: [LoggingNavigatorObserver()],
  // ...
// Prints:
// Navigator: didPush /dashboard β†’ /articles/12345
// Navigator: didPop /dashboard ← /articles/12345

Note: This uses the name of routes, so it only works with named routes. If you want to handle all your routing declaratively with proper deep links, check out my package 🧭 flutter_deep_linking :)

πŸ“± Widgets #

πŸ”³ Buttons #

Did you ever want to show a progress indicator inside a button? Or were annoyed to conditionally set a Button's onPressed to disable it? Fear no more — black_hole_flutter has got you covered!

Button demo

In FancyFab (a FloatingActionButton), FancyFlatButton, FancyOutlineButton & FancyRaisedButton, we introduce some new parameters:

πŸ₯” ChipGroup #

ChipGroup demo

Wraps multiple chips and can optionally show a title above these.

πŸ₯™ FillOrWrap #

FillOrWrap demo

A layout with two different behaviors:

  • By default, all children are positioned next to each other with equal widths. This is comparable to a Row with all children wrapped in Expanded.
  • If the children are too wide to fit in a single line, or one child would become smaller than its reported minimum width, the children get positioned below each other ("wrapped"). This is similar to a Column with MainAxisSize.min.

↔ SeparatedButtons #

SeparatedButtons demo

A container wrapping multiple buttons with an interpunct (Β·) between each one. It's recommended to use FlatButtons as children.

πŸ“š TitleAndSubtitle #

Did you ever want to show a subtitle (in addition to a main title) in your AppBar? Use TitleAndSubtitle (very creative name, I know):

  title: TitleAndSubtitle(
    title: Text('My title'),
    subtitle: Text('My optional subtitle'),

πŸ–Ό RenderObject #

When writing a custom layout, you might find this extension on ContainerRenderObjectMixin useful:

containerRenderObjectMixin.childrenReturns all children using firstChild and childAfter

↕ Size #

size.diagonallength of the diagonal of a rectangle with this Size
size.squaredDiagonal≙ size.diagonal * size.diagonal
size.coerceAtLeast(Size minimum)Ensures size is not smaller than minimum in any axis
size.coerceAtMost(Size maximum)Ensures size is not larger than minimum in any axis

Changelog #

All notable changes to this project will be documented in this file.

This project adheres to Semantic Versioning.

Unreleased #

0.2.12 Β· 2020-06-11 #

πŸŽ‰ New Features #

  • context: add BuildContext.focusScope

πŸ“¦ Build & CI #

  • update dartx to v0.4.0
  • update Flutter to v1.17.0

0.2.11 Β· 2020-05-18 #

πŸŽ‰ New Features #

  • async: add AsyncSnapshot.hasNoData, AsyncSnapshot.hasNoError
  • color: add Random.nextColorHsl(), Random.nextColorHsv()
  • context: add BuildContext.overlay

πŸ“¦ Build & CI #

  • example: update packages

0.2.10 Β· 2020-04-30 #

πŸŽ‰ New Features #

  • widgets: add TitleAndSubtitle

πŸ“¦ Build & CI #

  • update dartx to ^0.3.0

0.2.9 Β· 2020-04-29 #

πŸŽ‰ New Features #

  • color: add Color.isOpaque
  • color: add int.alphaToOpacity, double.opacityToAlpha
  • context: add BuildContext.materialLocalizations
  • context: add BuildContext.scaffoldOrNull
  • size: add Size.coerceAtLeast, Size.coerceAtMost

0.2.8 Β· 2020-04-20 #

πŸŽ‰ New Features #

  • context: add BuildContext.locale
  • render_object: add ContainerRenderObjectMixin.children

0.2.7 Β· 2020-04-08 #

πŸŽ‰ New Features #

  • color: add Color.isDark, Color.isLight

πŸ“œ Documentation updates #

  • fill README with missing extensions and widgets

0.2.6 Β· 2020-04-07 #

πŸŽ‰ New Features #

  • color: allow fixed red, green or blue values in Random.nextColor()
  • fillOrWrap: create FillOrWrap widget
  • navigation: add LoggingNavigatorObserver

0.2.5 Β· 2020-04-02 #

πŸŽ‰ New Features #

  • color: add Color.alphaBlendOn()
  • color: add Random.nextColor()

0.2.4 Β· 2020-04-02 #

πŸ› Bug Fixes #

  • buttons: use default child for extended buttons while not loading

0.2.3 Β· 2020-03-28 #

πŸŽ‰ New Features #

  • buttons: add icon-variants to FancyFlatButton, FancyOutlineButton & FancyRaisedButton
  • buttons: add textColor to all fancy buttons
  • buttons: add FancyOutlineButton.borderSide, FancyOutlineButton.highlightedBorderColor
  • color: add Color.withAdditionalOpacity, Color.withAdditionalAlpha
  • color: add contrastSystemUiOverlayStyle getters to Brightness, Color

0.2.2 Β· 2020-03-26 #

πŸŽ‰ New Features #

  • add Color.hsl, Color.hsv extensions

0.2.1 Β· 2020-03-25 #

πŸ› Bug Fixes #

  • correctly display FancyFab.extended

0.2.0 Β· 2020-03-24 #


  • fix naming: FancyFab.icon is now called FancyFab.child

πŸ› Bug Fixes #

  • FancyFab's background color is now the same as that of other buttons

πŸ“œ Documentation updates #

  • add button demo to README

πŸ— Refactoring #

  • FancyButton logic is now handled in their base _FancyButton

0.1.3 Β· 2020-03-22 #

⚑ Changes #

  • remove unused parameter from NavigatorState.pushNamedAndRemoveAll

0.1.2 Β· 2020-03-22 #

πŸ› Bug Fixes #

  • add missing export

0.1.1 Β· 2020-03-22 #

πŸŽ‰ New Features #

  • add NavigatorState.pushAndRemoveAll, NavigatorState.pushNamedAndRemoveAll
  • example: add example app showcasing new widgets

0.1.0 Β· 2020-03-13 #

πŸŽ‰ New Features #

  • add Size.diagonal, Size.squaredDiagonal
  • allow loading buttons without a loadingChild

⚑ Changes #

  • rename LoadingRaisedButton to FancyRaisedButton
  • make FancyFab.isExtended private

πŸ“œ Documentation updates #

  • fill the README with a package overview

0.0.1 Β· 2020-03-12 #

Initial release πŸŽ‰


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

import 'buttons.dart';

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

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'πŸ›  black_hole_flutter example',
      home: Scaffold(
        appBar: AppBar(title: Text('πŸ›  black_hole_flutter example')),
        body: ListView(children: <Widget>[

class BottomSheetExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Section(
      title: 'FancyBottomSheet',
      children: <Widget>[
          onPressed: () {
              builder: (_) => Padding(
                padding: EdgeInsets.symmetric(vertical: 128, horizontal: 16),
                child: Text("I'm fancy!"),
          child: Text('Open FancyBottomSheet'),

class ChipGroupExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Section(
      title: 'ChipGroup',
      children: <Widget>[
          children: <Widget>[
            Chip(label: Text('Lorem')),
            Chip(label: Text('ipsum')),
            Chip(label: Text('dolor')),
            Chip(label: Text('sit')),
            Chip(label: Text('amet')),
            Chip(label: Text('consectetur')),
            Chip(label: Text('adipiscing')),
            Chip(label: Text('elit')),
            Chip(label: Text('sed')),
            Chip(label: Text('do')),
            Chip(label: Text('eiusmod')),
            Chip(label: Text('tempor')),
            Chip(label: Text('incididunt')),

class SeparatedButtonsExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Section(
      title: 'SeparatedButtons',
      children: <Widget>[
          children: <Widget>[
            FlatButton(onPressed: () {}, child: Text('Imprint')),
            FlatButton(onPressed: () {}, child: Text('Privacy Policy')),
            FlatButton(onPressed: () {}, child: Text('Licenses')),

class FillOrWrapExample extends StatelessWidget {
  Widget build(BuildContext context) {
    return Section(
      title: 'FillOrWrap',
      children: <Widget>[
        Text('Enough horizontal space β†’ no wrapping'),
        _buildExample(isConstrained: false),
        SizedBox(height: 16),
        Text('Constrained horizontal space β†’ wrapping'),
        _buildExample(isConstrained: true),

  Widget _buildExample({bool isConstrained}) {
    return Center(
      child: Container(
        constraints: isConstrained ? BoxConstraints(maxWidth: 200) : null,
        decoration: BoxDecoration(border: Border.all()),
        child: FillOrWrap(
          spacing: 8,
          wrappedSpacing: 8,
          children: <Widget>[
            RaisedButton(onPressed: () {}, child: Text('Short')),
            RaisedButton(onPressed: () {}, child: Text('Loooooooooong')),
            RaisedButton(onPressed: () {}, child: Text('Short')),

class Section extends StatelessWidget {
  const Section({Key key, @required this.title, @required this.children})
      : assert(title != null),
        assert(children != null),
        super(key: key);

  final String title;
  final List<Widget> children;

  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(title, style: context.textTheme.subtitle1),
          SizedBox(height: 8),

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  black_hole_flutter: ^0.2.12

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:black_hole_flutter/black_hole_flutter.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Jul 11, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.15
  • Flutter: 1.17.5

Analysis suggestions

Package not compatible with SDK dart


  • black_hole_flutter that is a package requiring null.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
dartx ^0.4.0 0.4.2
flutter 0.0.0
meta ^1.1.8 1.1.8 1.2.2
Transitive dependencies
characters 1.0.0 1.1.0-nullsafety
charcode 1.1.3
collection 1.14.12 1.14.13
convert 2.1.1
crypto 2.1.5
path 1.7.0
sky_engine 0.0.99
time 1.3.0
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
pedantic ^1.8.0
test ^1.6.0