adaptive_foreground 0.0.1 copy "adaptive_foreground: ^0.0.1" to clipboard
adaptive_foreground: ^0.0.1 copied to clipboard

Adaptive foreground color (black/white) for Flutter. Automatically adjusts status-bar style and widget foreground based on background luminance, with optional live backdrop sampling via RepaintBoundary.

adaptive_foreground #

pub.dev License: MIT Flutter

Adaptive foreground color for Flutter. AppAdaptiveForeground automatically selects the highest-contrast foreground color — black or white — based on the luminance of the rendered background, and optionally keeps the system status-bar icons in sync.

[adaptive_foreground demo]


Features #

Feature Details
Luminance-based selection Computes background brightness and returns the highest-contrast foreground.
Live backdrop sampling Periodically captures a low-resolution snapshot of a RepaintBoundary to sample the actual rendered pixels — works with gradients, images, and animated backgrounds.
Status-bar sync Optionally keeps SystemUiOverlayStyle in sync with the resolved color via AnnotatedRegion.
Smooth transitions Color changes animate with a 300 ms ColorTween.
InheritedWidget propagation Every descendant can read the resolved foreground color with a single AppAdaptiveForeground.of(context) call.
Cross-platform button AppButtonIosAndroid renders a native iOS CNButton on iOS and a Material circular button on Android.
Zero heavy dependencies Core widget has no external deps. iOS button uses cupertino_native.

Installation #

dependencies:
  adaptive_foreground: ^0.0.1
import 'package:adaptive_foreground/adaptive_foreground.dart';

Quick start #

Wrap your app root inside a RepaintBoundary with a GlobalKey, then pass that key to AppAdaptiveForeground for live pixel sampling:

final GlobalKey rootRepaintKey = GlobalKey();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await _configureSystemUI();

  runApp(
    RepaintBoundary(
      key: rootRepaintKey,
      child: AppAdaptiveForeground(
        updateStatusBar: true,
        enableBackdropSampling: true,
        samplingKey: rootRepaintKey,
        child: const MyApp(),
      ),
    ),
  );
}

Read the resolved color anywhere below in the tree:

final foreground = AppAdaptiveForeground.of(context);        // Color
final background = AppAdaptiveForeground.backgroundColorOf(context); // Color
final style      = AppAdaptiveForeground.systemStyleOf(context);     // SystemUiOverlayStyle

Strategies #

1 — backgroundColorHint (instant) #

Best when you know the background color at build time (e.g. a solid Scaffold background):

AppAdaptiveForeground(
  backgroundColorHint: Colors.deepPurple,
  child: const MyPage(),
)

2 — samplingKey + enableBackdropSampling (live) #

Best for dynamic backgrounds (images, gradients, hero animations). Wrap the outermost widget in a RepaintBoundary and pass its key:

final GlobalKey rootRepaintKey = GlobalKey();

RepaintBoundary(
  key: rootRepaintKey,
  child: AppAdaptiveForeground(
    enableBackdropSampling: true,
    samplingKey: rootRepaintKey,
    updateStatusBar: true,
    child: const MyApp(),
  ),
)

API reference #

AppAdaptiveForeground #

Parameter Type Default Description
child Widget required Widget subtree to wrap.
backgroundColorHint Color? null Known background color for instant luminance calculation.
samplingKey GlobalKey? null Key of a RepaintBoundary to sample pixels from.
enableBackdropSampling bool false Enables periodic pixel sampling.
samplingInterval Duration 150 ms Sampling frequency.
darkColor Color Colors.black Foreground for bright backgrounds.
lightColor Color Colors.white Foreground for dark backgrounds.
threshold double 0.5 Luminance threshold for dark/light switching.
hysteresis double 0.08 Dead zone around threshold that prevents oscillation. Switch to bright only when luminance > threshold + hysteresis; switch to dark only when luminance < threshold - hysteresis.
sampleLocalArea bool true Sample only the widget's own area vs. the top strip (status-bar region).
updateStatusBar bool false Write the resolved style to SystemUiOverlayStyle.
systemOverlayStyle SystemUiOverlayStyle? null Manual override for the resolved overlay style.

Static accessors

// Resolved foreground color (black or white)
Color color = AppAdaptiveForeground.of(context);

// Resolved semi-transparent background tint
Color bg = AppAdaptiveForeground.backgroundColorOf(context);

// Resolved SystemUiOverlayStyle
SystemUiOverlayStyle style = AppAdaptiveForeground.systemStyleOf(context);

AppButtonIosAndroid #

A circular action button that adapts to the current platform.

AppButtonIosAndroid(
  symbol: 'square.and.arrow.up',   // SF Symbol — iOS only
  icon: Icons.share_outlined,       // Material icon — Android
  color: AppAdaptiveForeground.of(context),
  onPressed: _share,
)
Parameter Type Description
symbol String? SF Symbol name (required on iOS).
icon IconData? Material icon (used on Android & other platforms).
onPressed VoidCallback? Tap callback. Pass null to disable.
color Color? Tint / foreground color.
isOutline bool Renders an outline variant on Android.
buttonSize double? Custom size (defaults to AppDimensions.iconXL - 6).

System UI configuration #

A recommended _configureSystemUI for apps using this package:

Future<void> _configureSystemUI() async {
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
  ]);

  final overlays = defaultTargetPlatform == TargetPlatform.android
      ? const <SystemUiOverlay>[SystemUiOverlay.top]
      : SystemUiOverlay.values;

  await SystemChrome.setEnabledSystemUIMode(
    SystemUiMode.manual,
    overlays: overlays,
  );
}

Example app #

See the fully-worked example in example/lib/main.dart.

To run it:

cd example
flutter create --project-name adaptive_foreground_example . # adds platform folders
flutter run

License #

MIT © 2026 Mohammed Jaber


Author #

Mohammed Jaber

GitHub LinkedIn Email

3
likes
0
points
127
downloads

Publisher

verified publishermojaber.me

Weekly Downloads

Adaptive foreground color (black/white) for Flutter. Automatically adjusts status-bar style and widget foreground based on background luminance, with optional live backdrop sampling via RepaintBoundary.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

cupertino_native, flutter

More

Packages that depend on adaptive_foreground