Skip to main content

liquid_glass_lens_navbar 0.1.0 copy "liquid_glass_lens_navbar: ^0.1.0" to clipboard
liquid_glass_lens_navbar: ^0.1.0 copied to clipboard

An iOS 26 Liquid Glass bottom navigation bar for Flutter: frosted glass, a refracting liquid lens selection, hide on scroll, and adaptive quality.

example/lib/main.dart

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

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

class ExampleApp extends StatefulWidget {
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  ThemeMode _mode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'liquid_glass_lens_navbar example',
      debugShowCheckedModeBanner: false,
      themeMode: _mode,
      theme: ThemeData(brightness: Brightness.light, useMaterial3: true),
      darkTheme: ThemeData(brightness: Brightness.dark, useMaterial3: true),
      home: HomePage(
        onToggleTheme: () => setState(
          () => _mode = _mode == ThemeMode.light
              ? ThemeMode.dark
              : ThemeMode.light,
        ),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key, required this.onToggleTheme});

  final VoidCallback onToggleTheme;

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _index = 1;
  final _tabBar = LiquidGlassNavBarController();
  LiquidGlassAppearance _appearance = LiquidGlassAppearance.clear;
  double? _opacity;

  void _openGlassSettings() {
    showModalBottomSheet<void>(
      context: context,
      builder: (context) => StatefulBuilder(
        builder: (context, setSheet) {
          void update(VoidCallback fn) {
            setState(fn);
            setSheet(() {});
          }

          return SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(20),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  const Text(
                    'Liquid Glass',
                    style: TextStyle(fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(height: 12),
                  SegmentedButton<LiquidGlassAppearance>(
                    segments: const [
                      ButtonSegment(
                        value: LiquidGlassAppearance.clear,
                        label: Text('Clear'),
                      ),
                      ButtonSegment(
                        value: LiquidGlassAppearance.tinted,
                        label: Text('Tinted'),
                      ),
                      ButtonSegment(
                        value: LiquidGlassAppearance.solid,
                        label: Text('Solid'),
                      ),
                    ],
                    selected: {_appearance},
                    onSelectionChanged: (v) =>
                        update(() => _appearance = v.first),
                  ),
                  const SizedBox(height: 16),
                  Row(
                    children: [
                      const Text('Background opacity'),
                      const Spacer(),
                      Text(
                        _opacity == null
                            ? 'default'
                            : '${(_opacity! * 100).round()}%',
                      ),
                    ],
                  ),
                  Slider(
                    value: _opacity ?? 0.3,
                    onChanged: (v) => update(() => _opacity = v),
                  ),
                  TextButton(
                    onPressed: () => update(() => _opacity = null),
                    child: const Text('Reset opacity'),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }

  @override
  void dispose() {
    _tabBar.dispose();
    super.dispose();
  }

  static const _tabs = [
    LiquidGlassNavItem(
      icon: Icons.article_outlined,
      selectedIcon: Icons.article,
      label: 'Today',
    ),
    LiquidGlassNavItem(
      icon: Icons.rocket_outlined,
      selectedIcon: Icons.rocket,
      label: 'Games',
    ),
    LiquidGlassNavItem(
      icon: Icons.layers_outlined,
      selectedIcon: Icons.layers,
      label: 'Apps',
    ),
    LiquidGlassNavItem(
      icon: Icons.sports_esports_outlined,
      selectedIcon: Icons.sports_esports,
      label: 'Arcade',
    ),
    LiquidGlassNavItem(icon: Icons.search, label: 'Search'),
  ];

  static const _colors = [
    Colors.indigo,
    Colors.deepOrange,
    Colors.teal,
    Colors.purple,
    Colors.blueGrey,
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // Let content scroll underneath the floating glass bar.
      extendBody: true,
      appBar: AppBar(
        title: Text(_tabs[_index].label),
        actions: [
          IconButton(
            icon: const Icon(Icons.tune),
            onPressed: _openGlassSettings,
          ),
          IconButton(
            icon: const Icon(Icons.brightness_6_outlined),
            onPressed: widget.onToggleTheme,
          ),
        ],
      ),
      body: LiquidGlassScrollMinimizer(
        controller: _tabBar,
        child: ListView.builder(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 120),
          itemCount: 30,
          itemBuilder: (context, i) => Padding(
            padding: const EdgeInsets.only(bottom: 12),
            child: Container(
              height: 96,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                gradient: LinearGradient(
                  colors: [
                    _colors[(i + _index) % _colors.length].shade300,
                    _colors[(i + _index + 2) % _colors.length].shade600,
                  ],
                ),
              ),
              alignment: Alignment.center,
              child: Text(
                '${_tabs[_index].label} card ${i + 1}',
                style: const TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
        ),
      ),
      bottomNavigationBar: LiquidGlassNavBar(
        controller: _tabBar,
        appearance: _appearance,
        backgroundOpacity: _opacity,
        items: _tabs,
        currentIndex: _index,
        onTap: (i) => setState(() => _index = i),
      ),
    );
  }
}
1
likes
160
points
78
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

An iOS 26 Liquid Glass bottom navigation bar for Flutter: frosted glass, a refracting liquid lens selection, hide on scroll, and adaptive quality.

Repository (GitHub)
View/report issues

Topics

#liquid-glass #bottom-navigation #tab-bar #glassmorphism #ios

License

MIT (license)

Dependencies

flutter

More

Packages that depend on liquid_glass_lens_navbar

Packages that implement liquid_glass_lens_navbar