presentation/responsive/responsive library
Small, self-contained responsive utilities for dreamic — a zero
third-party-dependency replacement for the thin slice of
responsive_framework the app actually used (device-class detection and
"pick a value by breakpoint").
The split: structure vs dimensions
This file exposes two reactivity models. Keeping them straight is the whole point of the API surface, so it is the first thing documented:
-
Breakpoints for structure — which layout (one column vs two, show/hide a panel). Read via ResponsiveContext.deviceSize / ResponsiveContext.responsive. These resolve the ResponsiveScope's whole-window device class and rebuild dependents only when the class flips (segment-only rebuilds), never on every pixel of a resize.
-
Interpolation for dimensions — font size, spacing, gaps, max content width. Read via ResponsiveContext.clampByViewportWidth / ResponsiveContext.responsiveByViewportWidth. These read the nearest MediaQuery width at the call site (the whole window normally, or a sized sub-region under a deliberately nested MediaQuery) and rebuild per-pixel, by design.
The Viewport qualifier on the width helpers marks "tracks the local width
here, not the device class" — so the two models can never be confused at a
call site. A consequence of this split: the width helpers read MediaQuery
directly and therefore need only a MediaQuery ancestor — not a
ResponsiveScope — whereas the class-based accessors throw a FlutterError
without a scope (see ResponsiveScope and _ResponsiveData).
Configuration
Set Breakpoints once at startup before runApp, then wrap the app in a
single ResponsiveScope (top-level, above MaterialApp, is supported).
Usage
void main() {
// Configure once, before runApp (optional — defaults are 600 / 1024).
Breakpoints.tablet = 600;
Breakpoints.desktop = 1024;
runApp(const ResponsiveScope(child: MyApp()));
}
class HomeBody extends StatelessWidget {
const HomeBody({super.key});
@override
Widget build(BuildContext context) {
// Structure: pick a layout by device class (segment-only rebuilds).
final columns = context.responsive<int>(mobile: 1, tablet: 2, desktop: 3);
// Dimensions: interpolate by call-site viewport width (per-pixel).
final gutter = context.clampByViewportWidth(minValue: 12, maxValue: 32);
final maxContentWidth = context.responsiveByViewportWidth<double>(
breakpoints: {0: 480, 600: 720, 1024: 960},
fallback: 480,
);
return GridView.count(
crossAxisCount: columns,
padding: EdgeInsets.all(gutter),
children: [/* ... constrained to maxContentWidth ... */],
);
}
}
Only package:flutter/widgets.dart is imported; the file is intentionally
Flutter-SDK-only.
Classes
- Breakpoints
- Globally configurable device-class breakpoints, in logical pixels.
- ResponsiveScope
- Establishes the responsive device-class context for its subtree.
Enums
- DeviceSize
- The current viewport-width / layout class of the window.
Extensions
- ResponsiveContext on BuildContext
-
BuildContextextension exposing the responsive API.
Functions
-
classify(
double width) → DeviceSize -
Classifies a window
width(logical px) into a DeviceSize.