dynamic_glass_glmv 0.2.4 copy "dynamic_glass_glmv: ^0.2.4" to clipboard
dynamic_glass_glmv: ^0.2.4 copied to clipboard

A Flutter package for reusable dynamic glass UI surfaces and adaptive platform bottom navigation.

dynamic_glass_glmv #

Reusable frosted-glass surfaces and a fully adaptive bottom navigation bar for Flutter.

  • iOS 26+ → real UITabBarController / UITab liquid-glass bar via cupertino_native.
  • Every other platform (Android, iOS < 26, macOS, web, …) → GlassPillNavBar: a blurred floating pill bar with an animated sliding selection indicator, styled after modern Telegram Android.

Installation #

Add to your pubspec.yaml:

dependencies:
  dynamic_glass_glmv: ^0.2.0

Then run:

flutter pub get

Minimum iOS deployment target: 14.0 (set by cupertino_native_glmv).
Dart SDK: ^3.10.4 · Flutter: >=3.3.0


Platform behaviour #

Platform What you get
iOS 26+ (useNativeBottomBar: true, default) Native UITabBarController → system liquid-glass material
iOS 26+ (useNativeBottomBar: false) GlassPillNavBar (frosted pill)
iOS < 26 GlassPillNavBar (frosted pill)
Android GlassPillNavBar (frosted pill)
macOS / Windows / Linux / Web GlassPillNavBar (frosted pill)

The scaffold on iOS (all versions) wraps content in a CupertinoPageScaffold and overlays the bar in a Stack so the blur bleeds to the screen edge. On Android and other platforms it uses a Scaffold with extendBody: true so the body scrolls behind the floating pill.


Quick start #

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: const Color(0xFF0A84FF)),
      home: DynamicGlassNavigationScaffold(
        selectedItemColor: const Color(0xFF0A84FF),
        items: const [
          AdaptiveNavigationDestination(icon: 'house.fill',   label: 'Home'),
          AdaptiveNavigationDestination(icon: 'bell.fill',    label: 'Inbox', badgeCount: 3),
          AdaptiveNavigationDestination(icon: 'person.fill',  label: 'Profile'),
        ],
        screens: const [HomeScreen(), InboxScreen(), ProfileScreen()],
      ),
    );
  }
}

That single widget gives you:

  • Animated sliding glass pill on Android / all non-iOS-26 platforms.
  • Native liquid-glass UITabBarController on iOS 26.
  • Badge drawn as UITabBarItem.badgeValue on iOS 26, or as a red overlay bubble everywhere else.

Icon types #

AdaptiveNavigationDestination.icon accepts several forms:

Value iOS 26 native iOS fallback Android / other
'house.fill' — SF Symbol name (no /) ✅ native symbol mapped CupertinoIcon mapped Material icon
'assets/icons/logo.png' — asset path (contains /) ✅ asset image ImageIcon ImageIcon
AssetImage('assets/...') ✅ asset image ImageIcon ImageIcon
Icons.home / CupertinoIcons.* (IconData) ❌ silently dropped Icon widget Icon widget
Any Widget ❌ silently dropped used as-is used as-is

For best cross-platform parity use SF Symbol names — they are mapped to the nearest CupertinoIcons on older iOS and the nearest Icons on Android automatically.


GlassPillNavBar #

The default non-iOS-26 renderer is GlassPillNavBar — a floating rounded bar with a gradient sliding pill inspired by Telegram Android's current bottom navigation.

Standalone usage #

GlassPillNavBar(
  items: destinations,
  selectedIndex: _index,
  onTap: (i) => setState(() => _index = i),
)

Customising the style #

Pass a GlassPillNavBarStyle to glassPillStyle on the scaffold (or directly to GlassPillNavBar):

DynamicGlassNavigationScaffold(
  glassPillStyle: const GlassPillNavBarStyle(
    blurSigma: 32,
    borderRadius: 32,
    pillHeightFactor: 0.70,
    tapFeedback: GlassPillTapFeedback.ripple,
    showLabels: false,          // icon-only mode
  ),
  ...
)

Key GlassPillNavBarStyle properties

Property Default What it does
blurSigma 28 Backdrop blur strength
borderRadius 28 Pill corners of the outer bar
height 64 Bar content height (dp, before safe-area)
horizontalPadding 12 Side margin so the bar floats
bottomPadding 8 Gap above the home indicator
pillHeightFactor 0.78 Selection pill height as a fraction of bar height
pillHorizontalInset 8 Extra shrink on each side of a slot for the pill
pillColors frosted white gradient Custom gradient stop colors for the pill
pillShineEnabled true Renders a hairline shine at the top of the pill
showPill true Set to false for a pill-less icon-highlight style
showLabels true false for icon-only mode
tapFeedback none none · ripple · scale
animationDuration 320ms Pill slide speed
animationCurve easeOutCubic Pill slide easing
borderColor white hairline Solid border around the bar (null disables)
borderGradient null Gradient border ring; takes precedence over borderColor
borderWidth 1 Border / gradient-ring thickness
shadows subtle List<BoxShadow> under the bar
pillShadows glow + inner List<BoxShadow> under the pill

Preset examples

// Telegram dark (AMOLED-friendly)
const GlassPillNavBarStyle(
  backgroundColor: Color(0xCC1C1C1E),
  borderColor: Color(0x33FFFFFF),
  pillColors: [Color(0xFF2C2C2E), Color(0xFF1C1C1E)],
  pillBorderColor: Color(0x40FFFFFF),
)

// Accent pill (tinted glass pill instead of white)
GlassPillNavBarStyle(
  pillColors: [
    accentColor.withValues(alpha: 0.25),
    accentColor.withValues(alpha: 0.10),
  ],
  pillBorderColor: accentColor.withValues(alpha: 0.35),
)

// Minimal icon-only, no pill
const GlassPillNavBarStyle(
  showLabels: false,
  showPill: false,
  tapFeedback: GlassPillTapFeedback.scale,
)

// Gradient border ring (takes precedence over borderColor)
const GlassPillNavBarStyle(
  borderWidth: 1.5,
  borderGradient: LinearGradient(
    begin: Alignment.topLeft,
    end: Alignment.bottomRight,
    colors: [Color(0x80FFFFFF), Color(0x1AFFFFFF)],
  ),
)

Custom icon / label renderers #

GlassPillNavBar(
  items: items,
  selectedIndex: _index,
  onTap: (i) => setState(() => _index = i),
  // Return any widget — Lottie, SVG, custom painter, …
  iconBuilder: (context, item, selected, color, size) {
    return LottieBuilder.asset(
      selected ? item.selectedIcon : item.icon,
      width: size, height: size,
    );
  },
  labelBuilder: (context, item, selected, color) {
    return Text(
      item.label.toUpperCase(),
      style: TextStyle(fontSize: 9, letterSpacing: 0.8, color: color),
    );
  },
)

iOS 26 exclusive features #

These only take effect when useNativeBottomBar: true (the default) and the app runs on iOS 26+. They are silently ignored on every other platform.

DynamicGlassNavigationScaffold(
  // Minimize the bar when the user scrolls down.
  minimizeBehavior: TabBarMinimizeBehavior.onScrollDown,

  // Split: trailing item rendered as a separate side pill (Apple News style).
  split: true,
  rightCount: 1,          // number of items in the side pill
  splitSpacing: 8.0,

  items: [
    const AdaptiveNavigationDestination(icon: 'house.fill',        label: 'Home'),
    const AdaptiveNavigationDestination(icon: 'bell.fill',         label: 'Inbox', badgeCount: 2),
    const AdaptiveNavigationDestination(icon: 'person.fill',       label: 'Profile'),
    const AdaptiveNavigationDestination(
      icon: 'magnifyingglass',
      label: 'Search',
      isSearch: true,       // → UISearchTab on iOS 26
      hideLabel: true,      // icon-only in the GlassPillNavBar on other platforms
    ),
  ],
  screens: const [...],
)
Feature Property iOS 26 Other
Liquid-glass native bar useNativeBottomBar: true
Scroll-minimize minimizeBehavior ignored
Search tab isSearch: true ✅ UISearchTab ignored
Split / side pill split: true ignored
Badge value badgeCount ✅ native badge ✅ bubble overlay
Hide label hideLabel: true best-effort

DynamicGlass surface #

A standalone frosted-glass surface you can wrap around any content:

DynamicGlass(
  blur: 24,
  opacity: 0.18,
  tint: Colors.white,
  borderRadius: BorderRadius.circular(20),
  border: Border.all(color: Colors.white38),
  padding: const EdgeInsets.all(16),
  child: const Text('Content behind this is blurred.'),
)
Property Default
blur 20 ImageFilter sigma
tint 0xFFFFFFFF Color blended over the blurred area
opacity 0.16 Alpha applied to tint
borderRadius zero Clip + decoration radius
border null Optional BoxBorder
padding / margin null Inner / outer spacing

Adaptive native controls #

A set of thin wrappers around cupertino_native_glmv that embed the real platform control on iOS/macOS — picking up the system look, including the iOS 26 liquid-glass treatment, automatically — and fall back to a Flutter rendering everywhere else. They are safe to instantiate on any platform.

Each control re-exports its native parameters 1:1 under the Dynamic* namespace, so you never need to import cupertino_native_glmv directly.

Widget Wraps Notes
DynamicSwitch UISwitch / NSSwitch On/off toggle. DynamicSwitchController for imperative updates.
DynamicSlider UISlider / NSSlider min / max / step, track & thumb colors. DynamicSliderController.
DynamicSegmentedControl UISegmentedControl Labels and/or SF Symbols per segment.
DynamicButton UIButton / NSButton Text or round .icon variant; DynamicButtonStyle (incl. glass).
DynamicPopupMenuButton native popup button Text or .icon trigger; DynamicPopupMenuItem / DynamicPopupMenuDivider.
DynamicIcon SF Symbol Native symbol rendering (monochrome / hierarchical / palette / multicolor).
DynamicSymbol CNSymbol SF Symbol descriptor: name, size, color, palette, rendering mode, gradient.

Disabled semantics #

Mirroring Material's APIs, the value controls treat a null change callback as disabled:

DynamicSwitch(value: on, onChanged: null)                   // disabled
DynamicSlider(value: v, onChanged: locked ? null : (x) {…}) // disabled while locked
DynamicSegmentedControl(..., onValueChanged: null)          // disabled

You can also pass enabled: false explicitly. A control is disabled when either enabled is false or its callback is null.

Examples #

// Switch with a tint and a controller.
final switchController = DynamicSwitchController();
DynamicSwitch(
  value: _on,
  color: const Color(0xFF0A84FF),
  controller: switchController,
  onChanged: (v) => setState(() => _on = v),
);

// Slider 0–100 in steps of 5.
DynamicSlider(
  value: _volume,
  min: 0, max: 100, step: 5,
  onChanged: (v) => setState(() => _volume = v),
);

// Segmented control with SF Symbols.
DynamicSegmentedControl(
  labels: const ['Day', 'Week', 'Month'],
  selectedIndex: _segment,
  onValueChanged: (i) => setState(() => _segment = i),
);

// Glass text button + round icon button.
DynamicButton(
  label: 'Continue',
  style: DynamicButtonStyle.glass,
  onPressed: _submit,
);
DynamicButton.icon(
  icon: const DynamicSymbol('heart.fill'),
  tint: const Color(0xFFFF375F),
  onPressed: _like,
);

// Popup menu button (icon trigger).
DynamicPopupMenuButton.icon(
  buttonIcon: const DynamicSymbol('ellipsis.circle'),
  items: const [
    DynamicPopupMenuItem(label: 'Share',  icon: DynamicSymbol('square.and.arrow.up')),
    DynamicPopupMenuDivider(),
    DynamicPopupMenuItem(label: 'Delete', icon: DynamicSymbol('trash')),
  ],
  onSelected: (i) => _handleMenu(i),
);

// Native SF Symbol icon.
DynamicIcon(
  symbol: const DynamicSymbol('sparkles', size: 28, color: Color(0xFF0A84FF)),
);

iOS-only parameters (e.g. SF Symbol names, DynamicButtonStyle.glass) degrade gracefully on other platforms — the Flutter fallback renders a sensible equivalent.


AdaptiveBottomNavigationBar (lower-level) #

If you manage the scaffold yourself, drop in the bar directly:

AdaptiveBottomNavigationBar(
  items: items,
  selectedIndex: _index,
  onTap: (i) => setState(() => _index = i),
  selectedItemColor: Theme.of(context).colorScheme.primary,
  glassPillStyle: const GlassPillNavBarStyle(blurSigma: 40),
  // Override everything for the non-iOS-26 branch:
  fallbackNavBar: MyCustomBar(...),
)
7
likes
150
points
142
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter package for reusable dynamic glass UI surfaces and adaptive platform bottom navigation.

Repository (GitHub)
View/report issues

Topics

#flutter #widget #glassmorphism #blur #ui

License

BSD-3-Clause (license)

Dependencies

cupertino_icons, cupertino_native_glmv, flutter, flutter_svg

More

Packages that depend on dynamic_glass_glmv