Boosting Productivity with Build Context Extension in Flutter

Azhar Ali
6 min readMar 16, 2023

--

Before we dive into the details of the BuildContext extension, it’s important to have a clear understanding of what BuildContext is and how it works in Flutter.

BuildContext is a core concept in Flutter, and it is used to represent the location of a widget in the widget tree. It provides access to a wide range of properties and methods that can be used to build and customize widgets.

In general, when you want to build a widget in Flutter, you will use the BuildContext of the parent widget to create the child widget. This is because each widget in the tree is responsible for building its own children.

Introducing BuildContext Extension in Flutter

The BuildContext extension is a powerful feature that can be used to extend the functionality of the BuildContext class in Flutter. With this extension, you can create custom methods and properties that can be used to simplify the process of building widgets.

As an example, let’s take a look at the code snippet that you provided. This extension provides a range of properties and methods that can be used to simplify common tasks, such as checking the device size, getting the theme colors and text styles, and displaying pop-ups like bottom sheets and snack bars.

One of the key benefits of using the BuildContext extension is that it allows you to write less code while still achieving the same result. Instead of writing the same code over and over again to achieve a common task, you can simply use the methods and properties provided by the extension to simplify your code.

Here are some of the key methods and properties that are available in the extension:

Device Size

The extension provides properties that can be used to check the device size, such as isMobile, isTablet, isSmallTablet, isDesktop, and isSmall. These properties are particularly useful when you want to create a responsive user interface that adapts to different screen sizes.

extension BuildContextEntension<T> on BuildContext {

bool get isMobile => MediaQuery.of(this).size.width <= 500.0;

bool get isTablet => MediaQuery.of(this).size.width < 1024.0 && MediaQuery.of(this).size.width >= 650.0;

bool get isSmallTablet => MediaQuery.of(this).size.width < 650.0 && MediaQuery.of(this).size.width > 500.0;

bool get isDesktop => MediaQuery.of(this).size.width >= 1024.0;

bool get isSmall => MediaQuery.of(this).size.width < 850.0 && MediaQuery.of(this).size.width >= 560.0;

double get width => MediaQuery.of(this).size.width;

double get height => MediaQuery.of(this).size.height;

Size get size => MediaQuery.of(this).size;
}

Text Styles

The extension provides properties that can be used to access the text styles defined in the app’s theme, such as displayMedium, displaySmall, headlineLarge, headlineMedium, titleLarge, titleMedium, titleSmall, labelLarge, bodySmall, titleTextStyle.

extension BuildContextEntension<T> on BuildContext {
// text styles

TextStyle? get displayMedium => Theme.of(this).textTheme.displayMedium;

TextStyle? get displaySmall => Theme.of(this).textTheme.displaySmall;

TextStyle? get headlineLarge => Theme.of(this).textTheme.headlineLarge;

TextStyle? get headlineMedium => Theme.of(this).textTheme.headlineMedium;

TextStyle? get titleLarge => Theme.of(this).textTheme.titleLarge;

TextStyle? get titleMedium => Theme.of(this).textTheme.titleMedium;

TextStyle? get titleSmall => Theme.of(this).textTheme.titleSmall;

TextStyle? get labelLarge => Theme.of(this).textTheme.labelLarge;

TextStyle? get bodySmall => Theme.of(this).textTheme.bodySmall;

TextStyle? get titleTextStyle => Theme.of(this).appBarTheme.titleTextStyle;

TextStyle? get bodyExtraSmall => bodySmall?.copyWith(fontSize: 10, height: 1.6, letterSpacing: .5);

TextStyle? get bodyLarge => Theme.of(this).textTheme.bodyLarge;

TextStyle? get dividerTextSmall => bodySmall?.copyWith(letterSpacing: 0.5, fontWeight: FontWeight.w700, fontSize: 12.0);

TextStyle? get dividerTextLarge => bodySmall?.copyWith(letterSpacing: 1.5, fontWeight: FontWeight.w700, fontSize: 13.0, height: 1.23);
}

Theme Colors

The extension provides properties that can be used to access the colors defined in the app’s theme, such as primaryColor, primaryColorDark, primaryColorLight, primary, onPrimary, secondary, onSecondary, cardColor, errorColor, and background.

extension BuildContextEntension<T> on BuildContext {

// colors
Color get primaryColor => Theme.of(this).primaryColor;

Color get primaryColorDark => Theme.of(this).primaryColorDark;

Color get primaryColorLight => Theme.of(this).primaryColorLight;

Color get primary => Theme.of(this).colorScheme.primary;

Color get onPrimary => Theme.of(this).colorScheme.onPrimary;

Color get secondary => Theme.of(this).colorScheme.secondary;

Color get onSecondary => Theme.of(this).colorScheme.onSecondary;

Color get cardColor => Theme.of(this).cardColor;

Color get errorColor => Theme.of(this).colorScheme.error;

Color get background => Theme.of(this).colorScheme.background;

}

Pop-ups

The extension provides methods that can be used to display pop-ups, such as showBottomSheet, showSnackBar, and showToast. These methods make it easy to display common types of pop-ups in your app without having to write the same code over and over again.

You can create custom extensions as short names with some plugins as well.

extension BuildContextEntension<T> on BuildContext {

Future<T?> showBottomSheet(
Widget child, {
bool isScrollControlled = true,
Color? backgroundColor,
Color? barrierColor,
}) {
return showModalBottomSheet(
context: this,
barrierColor: barrierColor,
isScrollControlled: isScrollControlled,
backgroundColor: backgroundColor,
builder: (context) => Wrap(children: [child]),
);
}

ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSnackBar(String message) {
return ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Text(message),
behavior: SnackBarBehavior.floating,
),
);
}

// We can skip this, I've added because, I added a toast plugin
// which colors depends on theme, so, I added as a helping hand.
Future<bool?> showToast(String message) {
// It's a plugin to show toast and we can with extension
return Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: primary,
textColor: onPrimary,
);
}
}

How we can call them in Widgets

class ExperimentOfContext extends StatelessWidget {
const ExperimentOfContext({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Experiment Of Context', style: context.titleTextStyle),
),
body: SingleChildScrollView(
child: SizedBox(
width: context.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('displayMedium', style: context.displayMedium),
Text('displaySmall', style: context.displaySmall),
Text('headlineLarge', style: context.headlineLarge),
Text('headlineMedium', style: context.headlineMedium),
Text('titleLarge', style: context.titleLarge),
Text('titleMedium', style: context.titleMedium),
Text('titleSmall', style: context.titleSmall),
Text('labelLarge', style: context.labelLarge),
Text('bodySmall', style: context.bodySmall),
Text('titleTextStyle', style: context.titleTextStyle),
Text('bodyExtraSmall', style: context.bodyExtraSmall),
Text('bodyLarge', style: context.bodyLarge),
Text('dividerTextSmall', style: context.dividerTextSmall),
Text('dividerTextLarge', style: context.dividerTextLarge),
const SizedBox(height: 8.0),
ElevatedButton(
onPressed: () => context.showToast('Toast'),
child: const Text('Toast'),
),
const SizedBox(height: 8.0),
ElevatedButton(
onPressed: () => context.showSnackBar('SnackBar'),
child: const Text('Show snack bar'),
),
const SizedBox(height: 8.0),
ElevatedButton(
onPressed: () => context.showBottomSheet(const Padding(padding: EdgeInsets.all(16.0), child: Text('Bottom Sheet'))),
child: const Text('Bottom Sheet'),
),
const SizedBox(height: 8.0),
Text('width: ${context.width}'),
Text('height: ${context.height}'),
const SizedBox(height: 8.0),
],
),
),
),
);
}
}

extension BuildContextEntension<T> on BuildContext {

bool get isMobile => MediaQuery.of(this).size.width <= 500.0;

bool get isTablet => MediaQuery.of(this).size.width < 1024.0 && MediaQuery.of(this).size.width >= 650.0;

bool get isSmallTablet => MediaQuery.of(this).size.width < 650.0 && MediaQuery.of(this).size.width > 500.0;

bool get isDesktop => MediaQuery.of(this).size.width >= 1024.0;

bool get isSmall => MediaQuery.of(this).size.width < 850.0 && MediaQuery.of(this).size.width >= 560.0;

double get width => MediaQuery.of(this).size.width;

double get height => MediaQuery.of(this).size.height;

Size get size => MediaQuery.of(this).size;

// text styles

TextStyle? get displayMedium => Theme.of(this).textTheme.displayMedium;

TextStyle? get displaySmall => Theme.of(this).textTheme.displaySmall;

TextStyle? get headlineLarge => Theme.of(this).textTheme.headlineLarge;

TextStyle? get headlineMedium => Theme.of(this).textTheme.headlineMedium;

TextStyle? get titleLarge => Theme.of(this).textTheme.titleLarge;

TextStyle? get titleMedium => Theme.of(this).textTheme.titleMedium;

TextStyle? get titleSmall => Theme.of(this).textTheme.titleSmall;

TextStyle? get labelLarge => Theme.of(this).textTheme.labelLarge;

TextStyle? get bodySmall => Theme.of(this).textTheme.bodySmall;

TextStyle? get titleTextStyle => Theme.of(this).appBarTheme.titleTextStyle;

TextStyle? get bodyExtraSmall => bodySmall?.copyWith(fontSize: 10, height: 1.6, letterSpacing: .5);

TextStyle? get bodyLarge => Theme.of(this).textTheme.bodyLarge;

TextStyle? get dividerTextSmall => bodySmall?.copyWith(letterSpacing: 0.5, fontWeight: FontWeight.w700, fontSize: 12.0);

TextStyle? get dividerTextLarge => bodySmall?.copyWith(letterSpacing: 1.5, fontWeight: FontWeight.w700, fontSize: 13.0, height: 1.23);

// colors

Color get primaryColor => Theme.of(this).primaryColor;

Color get primaryColorDark => Theme.of(this).primaryColorDark;

Color get primaryColorLight => Theme.of(this).primaryColorLight;

Color get primary => Theme.of(this).colorScheme.primary;

Color get onPrimary => Theme.of(this).colorScheme.onPrimary;

Color get secondary => Theme.of(this).colorScheme.secondary;

Color get onSecondary => Theme.of(this).colorScheme.onSecondary;

Color get cardColor => Theme.of(this).cardColor;

Color get errorColor => Theme.of(this).colorScheme.error;

Color get background => Theme.of(this).colorScheme.background;

// custome theme extensions, You must have to create theme extensions first
// you can use them with shortcuts as well
Gradient get vertical => Theme.of(this).extension<AppThemeExtension>()!.vertical;

Gradient get horizontal => Theme.of(this).extension<AppThemeExtension>()!.horizontal;

Color get extraLightGrey => Theme.of(this).extension<AppThemeExtension>()!.extraLightGrey;

Color get lightGrey => Theme.of(this).extension<AppThemeExtension>()!.lightGrey;

Future<T?> showBottomSheet(
Widget child, {
bool isScrollControlled = true,
Color? backgroundColor,
Color? barrierColor,
}) {
return showModalBottomSheet(
context: this,
barrierColor: barrierColor,
isScrollControlled: isScrollControlled,
backgroundColor: backgroundColor,
builder: (context) => Wrap(children: [child]),
);
}

ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSnackBar(String message) {
return ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Text(message),
behavior: SnackBarBehavior.floating,
// backgroundColor: primary,
),
);
}

// We can skip this, I've added because, I added a toast plugin
// which colors depends on theme, so, I added as a helping hand.
Future<bool?> showToast(String message) {
return Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: primary,
textColor: onPrimary,
);
}
}

Conclusion

In conclusion, the BuildContext extension is a powerful feature in Flutter that can be used to simplify the process of building widgets. With this extension, you can create custom methods and properties that can be used to simplify everyday tasks, such as checking the device size, getting the theme colors and text styles, and displaying pop-ups like bottom sheets and snack bars.

If you’re interested in using the BuildContext extension in your Flutter app, you can simply copy the code snippet provided and add it to your project. With this extension, you can write less code while still achieving the same result, saving you a lot of time and effort in the long run.

--

--