Skip to main content

fold_adaptive_nav 1.5.0 copy "fold_adaptive_nav: ^1.5.0" to clipboard
fold_adaptive_nav: ^1.5.0 copied to clipboard

Detects foldables and their posture on iOS and Android, and adapts navigation by itself: bottom bar on phones, thumb rail on cover displays, tablet layouts when open.

example/lib/main.dart

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

import 'device_page.dart';
import 'gallery_page.dart';
import 'inbox_page.dart';
import 'player_page.dart';
import 'settings_page.dart';
import 'transfer_page.dart';

void main() {
  // No SystemChrome.setPreferredOrientations here: FoldScope sets them once
  // the first fold reading arrives.
  runApp(const ExampleApp());
}

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

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

class _ExampleAppState extends State<ExampleApp> {
  var _settings = const ExampleSettings();

  @override
  Widget build(BuildContext context) {
    return FoldScope(
      config: _settings.config,
      child: MaterialApp(
        title: 'fold_adaptive_nav',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(colorSchemeSeed: Colors.teal),
        darkTheme: ThemeData(
          colorSchemeSeed: Colors.teal,
          brightness: Brightness.dark,
        ),
        locale: _settings.rtl ? const Locale('ar') : null,
        // Pins the form factor below this point, to preview the cover and
        // tablet layouts on any device.
        builder: (context, child) {
          // Shows what the package sees: form factor, posture, the fold.
          Widget app =
              FoldDebugOverlay(enabled: _settings.debugOverlay, child: child!);
          if (_settings.preview case final FormFactor preview) {
            app = FormFactorOverride(formFactor: preview, child: app);
          }
          return Directionality(
            textDirection:
                _settings.rtl ? TextDirection.rtl : TextDirection.ltr,
            child: app,
          );
        },
        home: HomeShell(
          settings: _settings,
          onSettingsChanged: (s) => setState(() => _settings = s),
        ),
      ),
    );
  }
}

class HomeShell extends StatefulWidget {
  const HomeShell({
    super.key,
    required this.settings,
    required this.onSettingsChanged,
  });

  final ExampleSettings settings;
  final ValueChanged<ExampleSettings> onSettingsChanged;

  @override
  State<HomeShell> createState() => _HomeShellState();
}

class _HomeShellState extends State<HomeShell> {
  int _tab = 0;

  // Six tabs: the bar and the cover rail show four and "More"; the tablet
  // rail and drawer show all of them.
  static const _destinations = [
    NavDestination(
      icon: Icons.devices_fold_outlined,
      selectedIcon: Icons.devices_fold,
      label: 'Device',
    ),
    NavDestination(
      icon: Icons.inbox_outlined,
      selectedIcon: Icons.inbox,
      label: 'Inbox',
      badge: '3',
    ),
    NavDestination(
      icon: Icons.swap_horiz_outlined,
      selectedIcon: Icons.swap_horiz,
      label: 'Transfer',
    ),
    NavDestination(
      icon: Icons.play_circle_outline,
      selectedIcon: Icons.play_circle,
      label: 'Player',
    ),
    NavDestination(
      icon: Icons.photo_library_outlined,
      selectedIcon: Icons.photo_library,
      label: 'Gallery',
    ),
    NavDestination(
      icon: Icons.tune_outlined,
      selectedIcon: Icons.tune,
      label: 'Settings',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return FoldListener(
      onPostureChanged: (previous, current) =>
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        duration: const Duration(seconds: 2),
        content: Text('Posture: ${previous.name} → ${current.name}'),
      )),
      child: AdaptiveNavScaffold(
        destinations: _destinations,
        currentIndex: _tab,
        onSelect: (i) => setState(() => _tab = i),
        hideBarOnScroll: widget.settings.hideBarOnScroll,
        // A FAB on phones and tablets, the foot of the rail on the cover display.
        trailingAction: FloatingActionButton(
          tooltip: 'Scan',
          onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Scan tapped')),
          ),
          child: const Icon(Icons.qr_code_scanner),
        ),
        body: IndexedStack(
          index: _tab,
          children: [
            const DevicePage(),
            const InboxPage(),
            const TransferPage(),
            const PlayerPage(),
            const GalleryPage(),
            SettingsPage(
              settings: widget.settings,
              onChanged: widget.onSettingsChanged,
            ),
          ],
        ),
      ),
    );
  }
}
2
likes
160
points
418
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Detects foldables and their posture on iOS and Android, and adapts navigation by itself: bottom bar on phones, thumb rail on cover displays, tablet layouts when open.

Repository (GitHub)
View/report issues
Contributing

Topics

#foldable #adaptive #navigation #responsive

License

BSD-3-Clause (license)

Dependencies

flutter, fold_adaptive_nav_android, fold_adaptive_nav_ios, fold_adaptive_nav_platform_interface

More

Packages that depend on fold_adaptive_nav

Packages that implement fold_adaptive_nav