Skip to main content

liquid_glass_tab_bar 0.1.0-dev.7 copy "liquid_glass_tab_bar: ^0.1.0-dev.7" to clipboard
liquid_glass_tab_bar: ^0.1.0-dev.7 copied to clipboard

iOS 26 liquid glass bottom navigation bar (tab bar, nav bar) for Flutter with a real refracting glass droplet, drag to select and light/dark mode.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:liquid_glass_tab_bar/liquid_glass_tab_bar.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) {
    const seed = Color(0xFF0E7C66);
    return MaterialApp(
      title: 'Liquid Glass Tab Bar',
      debugShowCheckedModeBanner: false,
      themeMode: _mode,
      theme: ThemeData(colorSchemeSeed: seed),
      darkTheme: ThemeData(
        colorSchemeSeed: seed,
        brightness: Brightness.dark,
        scaffoldBackgroundColor: Colors.black,
      ),
      home: HomePage(
        dark: _mode == ThemeMode.dark,
        onToggleTheme: () => setState(
          () => _mode = _mode == ThemeMode.dark
              ? ThemeMode.light
              : ThemeMode.dark,
        ),
      ),
    );
  }
}

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

  final bool dark;
  final VoidCallback onToggleTheme;

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

class _HomePageState extends State<HomePage> {
  int _index = 0;
  bool _labels = true;

  static const _titles = ['Home', 'Favorites', 'Search', 'Profile'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // Lets the page scroll behind the glass.
      extendBody: true,
      appBar: AppBar(
        title: Text(_titles[_index]),
        actions: [
          IconButton(
            tooltip: 'Toggle labels',
            icon: Icon(
              _labels ? Icons.label_off_outlined : Icons.label_outline,
            ),
            onPressed: () => setState(() => _labels = !_labels),
          ),
          IconButton(
            tooltip: 'Toggle theme',
            icon: Icon(widget.dark ? Icons.light_mode : Icons.dark_mode),
            onPressed: widget.onToggleTheme,
          ),
        ],
      ),
      body: _ColorfulList(seed: _index),
      bottomNavigationBar: LiquidGlassTabBar(
        currentIndex: _index,
        onTap: (i) => setState(() => _index = i),
        // "Search" opens a sheet instead of becoming the selected tab.
        onTapIntercept: (i) {
          if (i != 2) return false;
          showModalBottomSheet<void>(
            context: context,
            builder: (_) => const SizedBox(
              height: 200,
              child: Center(child: Text('Search sheet')),
            ),
          );
          return true;
        },
        // Icon-only bars look better with a smaller capsule.
        style: _labels
            ? const LiquidGlassTabBarStyle()
            : const LiquidGlassTabBarStyle(capsuleHeight: 44),
        items: [
          for (final (i, icon) in const [
            Icons.home_outlined,
            Icons.favorite_border,
            Icons.search,
            Icons.person_outline,
          ].indexed)
            LiquidGlassTabItem(
              icon: Icon(icon),
              label: _labels ? _titles[i] : null,
              semanticLabel: _titles[i],
            ),
        ],
      ),
    );
  }
}

/// Colorful cards so the glass has something to refract.
class _ColorfulList extends StatelessWidget {
  const _ColorfulList({required this.seed});

  final int seed;

  @override
  Widget build(BuildContext context) {
    final colors = Colors.primaries;
    final dark = Theme.of(context).brightness == Brightness.dark;
    return ListView.builder(
      // Keeps the last card above the bar.
      padding: EdgeInsets.fromLTRB(
        20,
        16,
        20,
        LiquidGlassTabBar.heightOf(context) + 16,
      ),
      itemCount: 24,
      itemBuilder: (context, i) {
        final color = colors[(i + seed * 3) % colors.length];
        return Container(
          height: 96,
          margin: const EdgeInsets.only(bottom: 12),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(20),
            gradient: LinearGradient(
              colors: dark
                  ? [
                      Color.lerp(color.shade700, Colors.black, 0.45)!,
                      Color.lerp(color.shade900, Colors.black, 0.6)!,
                    ]
                  : [color.shade300, color.shade700],
            ),
          ),
          alignment: Alignment.centerLeft,
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: Text(
            'Card ${i + 1}',
            style: const TextStyle(
              color: Colors.white,
              fontSize: 18,
              fontWeight: FontWeight.w600,
            ),
          ),
        );
      },
    );
  }
}
1
likes
0
points
506
downloads

Publisher

unverified uploader

Weekly Downloads

iOS 26 liquid glass bottom navigation bar (tab bar, nav bar) for Flutter with a real refracting glass droplet, drag to select and light/dark mode.

Repository (GitHub)
View/report issues

Topics

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

License

unknown (license)

Dependencies

flutter, liquid_glass_renderer

More

Packages that depend on liquid_glass_tab_bar