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.
import 'package:flutter/material.dart';
import 'package:liquid_glass_bottom_nav_water_effect/liquid_glass_bottom_nav_water_effect.dart';
void main() {
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(colorSchemeSeed: Colors.indigo),
darkTheme: ThemeData(
brightness: Brightness.dark,
colorSchemeSeed: Colors.indigo,
),
home: const ExampleScreen(),
);
}
}
class ExampleScreen extends StatefulWidget {
const ExampleScreen({super.key});
@override
State<ExampleScreen> createState() => _ExampleScreenState();
}
class _ExampleScreenState extends State<ExampleScreen> {
int _currentIndex = 0;
LiquidGlassPerformanceMode _performanceMode =
LiquidGlassPerformanceMode.automatic;
LiquidGlassPerformanceMode _resolvedPerformanceMode =
LiquidGlassPerformanceMode.quality;
static const _pages = <Widget>[
_Page(title: 'Home', icon: Icons.home_rounded),
_Page(title: 'Materials', icon: Icons.folder_rounded),
_Page(title: 'Lessons', icon: Icons.play_lesson_rounded),
_Page(title: 'Subscriptions', icon: Icons.workspace_premium_rounded),
_Page(title: 'Settings', icon: Icons.settings_rounded),
];
@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
appBar: AppBar(
title: const Text('Liquid Glass Bottom Nav'),
actions: [
Center(
child: Padding(
padding: const EdgeInsetsDirectional.only(end: 4),
child: Text(
_resolvedPerformanceMode.name,
style: Theme.of(context).textTheme.labelMedium,
),
),
),
PopupMenuButton<LiquidGlassPerformanceMode>(
initialValue: _performanceMode,
tooltip: 'Performance mode',
onSelected: (mode) {
setState(() => _performanceMode = mode);
},
itemBuilder: (context) => LiquidGlassPerformanceMode.values
.map(
(mode) => PopupMenuItem(value: mode, child: Text(mode.name)),
)
.toList(),
icon: const Icon(Icons.speed_rounded),
),
],
),
body: IndexedStack(index: _currentIndex, children: _pages),
bottomNavigationBar: LiquidGlassBottomNavBar(
currentIndex: _currentIndex,
performanceMode: _performanceMode,
onResolvedPerformanceModeChanged: (mode) {
if (_resolvedPerformanceMode != mode) {
setState(() => _resolvedPerformanceMode = mode);
}
},
onItemSelected: (index) {
setState(() => _currentIndex = index);
},
items: const [
LiquidGlassBottomNavItem(
label: 'Home',
icon: Icon(Icons.home_outlined),
activeIcon: Icon(Icons.home_rounded),
),
LiquidGlassBottomNavItem(
label: 'Materials',
icon: Icon(Icons.folder_outlined),
activeIcon: Icon(Icons.folder_rounded),
),
LiquidGlassBottomNavItem(
label: 'Lessons',
icon: Icon(Icons.play_lesson_outlined),
activeIcon: Icon(Icons.play_lesson_rounded),
),
LiquidGlassBottomNavItem(
label: 'Subscriptions',
icon: Icon(Icons.workspace_premium_outlined),
activeIcon: Icon(Icons.workspace_premium_rounded),
),
LiquidGlassBottomNavItem(
label: 'Settings',
icon: Icon(Icons.settings_outlined),
activeIcon: Icon(Icons.settings_rounded),
),
],
style: const LiquidGlassBottomNavStyle(
primaryLiquidColor: Colors.indigo,
secondaryLiquidColor: Colors.blueAccent,
),
),
);
}
}
class _Page extends StatelessWidget {
const _Page({required this.title, required this.icon});
final String title;
final IconData icon;
static const _cards = <_DemoCardData>[
_DemoCardData(
title: 'Design systems',
subtitle: '12 new components',
icon: Icons.palette_outlined,
colors: [Color(0xFF7C4DFF), Color(0xFF536DFE)],
),
_DemoCardData(
title: 'Flutter animations',
subtitle: 'Continue learning · 68%',
icon: Icons.auto_awesome_motion_rounded,
colors: [Color(0xFF00B8D4), Color(0xFF2979FF)],
),
_DemoCardData(
title: 'Weekly progress',
subtitle: 'You completed 8 lessons',
icon: Icons.insights_rounded,
colors: [Color(0xFFFF6D00), Color(0xFFFFAB00)],
),
_DemoCardData(
title: 'Saved resources',
subtitle: '24 items available offline',
icon: Icons.bookmark_outline_rounded,
colors: [Color(0xFF00C853), Color(0xFF00BFA5)],
),
_DemoCardData(
title: 'Upcoming session',
subtitle: 'Today at 7:30 PM',
icon: Icons.calendar_month_outlined,
colors: [Color(0xFFD500F9), Color(0xFFFF4081)],
),
];
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.primaryContainer,
],
),
),
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 24),
children: [
Row(
children: [
CircleAvatar(
radius: 28,
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
child: Icon(icon, size: 30),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(context).textTheme.headlineSmall,
),
Text(
'Welcome back, Mustafa',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
],
),
const SizedBox(height: 24),
Row(
children: const [
Expanded(
child: _StatCard(value: '12', label: 'Courses'),
),
SizedBox(width: 12),
Expanded(
child: _StatCard(value: '68%', label: 'Progress'),
),
SizedBox(width: 12),
Expanded(
child: _StatCard(value: '7', label: 'Day streak'),
),
],
),
const SizedBox(height: 24),
Text('For you', style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 12),
..._cards.map((card) => _DemoCard(data: card)),
],
),
);
}
}
class _StatCard extends StatelessWidget {
const _StatCard({required this.value, required this.label});
final String value;
final String label;
@override
Widget build(BuildContext context) {
return Card(
elevation: 0,
color: Theme.of(context).colorScheme.surface.withValues(alpha: 0.72),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
children: [
Text(value, style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 3),
Text(label, style: Theme.of(context).textTheme.labelMedium),
],
),
),
);
}
}
class _DemoCard extends StatelessWidget {
const _DemoCard({required this.data});
final _DemoCardData data;
@override
Widget build(BuildContext context) {
return Container(
height: 112,
margin: const EdgeInsets.only(bottom: 14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
gradient: LinearGradient(colors: data.colors),
),
child: ListTile(
contentPadding: const EdgeInsets.all(20),
leading: CircleAvatar(
radius: 25,
backgroundColor: Colors.white.withValues(alpha: 0.2),
child: Icon(data.icon, color: Colors.white),
),
title: Text(
data.title,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
),
),
subtitle: Text(
data.subtitle,
style: TextStyle(color: Colors.white.withValues(alpha: 0.82)),
),
trailing: const Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.white,
size: 17,
),
),
);
}
}
class _DemoCardData {
const _DemoCardData({
required this.title,
required this.subtitle,
required this.icon,
required this.colors,
});
final String title;
final String subtitle;
final IconData icon;
final List<Color> colors;
}