liquid_glass_bottom_nav_water_effect 1.3.0
liquid_glass_bottom_nav_water_effect: ^1.3.0 copied to clipboard
A customizable liquid glass bottom navigation bar with adaptive device performance, independent SafeArea sides, drag selection, RTL, and haptics.
Liquid Glass Bottom Nav Water Effect #
A reusable Flutter bottom navigation bar with a draggable liquid-glass thumb, adaptive device performance, independent SafeArea controls, RTL support, haptic feedback, and no dependency on routing or state-management packages.
Demo #
Features #
- Full liquid-glass quality by default
- Optional automatic quality selection based on real Flutter frame timings
- Manual
quality,balanced, andperformanceoverrides - Separate SafeArea controls for top, bottom, left, and right
- Controlled selected index
- Custom labels and any icon widgets
- Optional active icons
- Tap and drag selection
- RTL support
- Light and dark theme support
- Configurable colors, dimensions, text styles, blur, and animations
- No continuous idle repainting in balanced and performance modes
- Works with Bloc, Cubit, Provider, Riverpod, setState, AutoRoute, GoRouter, and other architectures
Installation #
flutter pub add liquid_glass_bottom_nav_water_effect
dependencies:
liquid_glass_bottom_nav_water_effect: ^1.3.0
Basic usage #
import 'package:liquid_glass_bottom_nav_water_effect/liquid_glass_bottom_nav_water_effect.dart';
Scaffold(
// Required when screen content should remain visible behind the glass.
extendBody: true,
body: yourScreenContent,
bottomNavigationBar: LiquidGlassBottomNavBar(
currentIndex: currentIndex,
onItemSelected: (index) {
setState(() => currentIndex = index);
},
items: const [
LiquidGlassBottomNavItem(
label: 'Home',
icon: Icon(Icons.home_outlined),
activeIcon: Icon(Icons.home_rounded),
),
LiquidGlassBottomNavItem(
label: 'Settings',
icon: Icon(Icons.settings_outlined),
activeIcon: Icon(Icons.settings_rounded),
),
],
),
)
performanceMode defaults to quality, and bottom SafeArea is enabled by
default because this widget is normally used as a bottom navigation bar. The
default glass background uses a translucent tint of primaryLiquidColor
instead of a black or white fill.
Use Scaffold(extendBody: true) to place screen content behind the navigation
bar. Without it, the bar remains translucent but Flutter reserves an empty area
below the page body, so there is no screen content behind the glass to reveal.
Automatic device performance #
Enable automatic performance adaptation explicitly:
LiquidGlassBottomNavBar(
performanceMode: LiquidGlassPerformanceMode.automatic,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
)
The package does not depend only on a device model name. It samples actual Flutter build and raster frame timings, so it can handle:
- Older flagship devices that still perform well
- Newer low-end devices
- Tablets and large displays
- Devices affected by thermal throttling or heavy screen content
In profile and release builds, automatic mode resolves to:
| Resolved mode | Rendering behavior | Typical device state |
|---|---|---|
quality |
Full blur, animated liquid waves, idle animation | Smooth/high-capability |
balanced |
Reduced blur, no continuous idle repaint | Medium/default production |
performance |
No backdrop blur or liquid waves | Slow, busy, or battery-sensitive |
Debug builds cannot classify hardware reliably because debug frame timings
include development overhead. They therefore use the configured initialMode,
which defaults to quality, while adaptive switching runs in profile/release.
You can observe the resolved mode:
LiquidGlassBottomNavBar(
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
onResolvedPerformanceModeChanged: (mode) {
debugPrint('Liquid glass mode: ${mode.name}');
},
)
Quality-friendly automatic defaults #
Version 1.2.0 makes automatic mode less strict:
- Uses the slower of build and raster duration instead of adding both stages
- Allows a small
8%jank ratio while still selectingquality - Selects
qualityat an average frame-pipeline time up to16ms - Selects
performanceonly from24msaverage or more than20%jank - Uses the configured
initialModein debug, which defaults toquality
This favors the full visual effect on capable devices while still protecting slower devices when sustained frame pressure is detected.
Customize automatic detection #
LiquidGlassBottomNavBar(
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
performanceMode: LiquidGlassPerformanceMode.automatic,
adaptivePerformanceConfig: const LiquidGlassAdaptivePerformanceConfig(
initialMode: LiquidGlassPerformanceMode.quality,
sampleFrameCount: 36,
upgradeAverageFrameTime: Duration(milliseconds: 16),
downgradeAverageFrameTime: Duration(milliseconds: 24),
jankFrameTime: Duration(milliseconds: 32),
maximumQualityJankRatio: 0.08,
maximumJankRatio: 0.20,
minimumModeDuration: Duration(seconds: 4),
allowQualityMode: true,
allowPerformanceMode: true,
),
)
Force a mode manually #
Manual mode disables automatic detection:
performanceMode: LiquidGlassPerformanceMode.quality,
Other options:
performanceMode: LiquidGlassPerformanceMode.balanced,
performanceMode: LiquidGlassPerformanceMode.performance,
SafeArea control #
Bottom only — default #
LiquidGlassBottomNavBar(
safeAreaTop: false,
safeAreaBottom: true,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
)
Top only #
LiquidGlassBottomNavBar(
safeAreaTop: true,
safeAreaBottom: false,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
)
Top and bottom #
LiquidGlassBottomNavBar(
safeAreaTop: true,
safeAreaBottom: true,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
)
Disable SafeArea completely #
LiquidGlassBottomNavBar(
safeAreaTop: false,
safeAreaBottom: false,
safeAreaLeft: false,
safeAreaRight: false,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
)
The old useSafeArea parameter remains temporarily available for backward
compatibility but is deprecated.
Using SVG icons #
The package accepts any Widget, so your app can use flutter_svg without
forcing that dependency on every package consumer:
LiquidGlassBottomNavItem(
label: context.l10n.home,
icon: SvgPicture.asset(
'assets/icons/home.svg',
colorFilter: const ColorFilter.mode(Colors.black, BlendMode.srcIn),
),
)
Custom style #
LiquidGlassBottomNavBar(
currentIndex: currentIndex,
onItemSelected: onItemSelected,
items: items,
style: const LiquidGlassBottomNavStyle(
height: 80,
borderRadius: 40,
primaryLiquidColor: Color(0xFF6C63FF),
secondaryLiquidColor: Color(0xFF9A95FF),
backgroundColor: Color(0x246C63FF),
darkBackgroundColor: Color(0x386C63FF),
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white70,
),
)
Glass controls #
LiquidGlassBottomNavBar(
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
enableGlassEffect: true,
enableWobble: true,
showLabels: true,
style: const LiquidGlassBottomNavStyle(
glassOpacity: 0.025,
darkGlassOpacity: 0.045,
barBlurSigma: 6,
highlightColor: Colors.white,
highlightIntensity: 0.85,
thumbShape: LiquidGlassThumbShape.capsule,
),
)
The default indicator shape is capsule. The other available shapes are
liquid and circle.
Gradient glass #
style: const LiquidGlassBottomNavStyle(
backgroundGradient: LinearGradient(
colors: [Color(0x336C63FF), Color(0x2218A0FB)],
),
darkBackgroundGradient: LinearGradient(
colors: [Color(0x446C63FF), Color(0x3318A0FB)],
),
),
Normal container without glass #
LiquidGlassBottomNavBar(
enableGlassEffect: false,
currentIndex: currentIndex,
items: items,
onItemSelected: onItemSelected,
style: const LiquidGlassBottomNavStyle(
solidBackgroundColor: Color(0xFFF4F1FA),
darkSolidBackgroundColor: Color(0xFF211D2A),
thumbShape: LiquidGlassThumbShape.capsule,
highlightIntensity: 0,
),
)
Use showLabels: false for icons only and enableWobble: false for a stable
selection indicator.
Using it with Cubit #
BlocBuilder<BottomNavCubit, BottomNavState>(
builder: (context, state) {
return LiquidGlassBottomNavBar(
currentIndex: state.currentIndex,
onItemSelected: context.read<BottomNavCubit>().changeIndex,
items: items,
);
},
)
Performance testing #
Test automatic detection on a real device in profile mode:
cd example
flutter run --profile
Use Flutter DevTools Performance view while dragging between destinations and scrolling content behind the navigation bar.