liquid_glass_bottom_nav_water_effect 1.3.0 copy "liquid_glass_bottom_nav_water_effect: ^1.3.0" to clipboard
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.

example/lib/main.dart

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;
}
20
likes
160
points
176
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A customizable liquid glass bottom navigation bar with adaptive device performance, independent SafeArea sides, drag selection, RTL, and haptics.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on liquid_glass_bottom_nav_water_effect