Adaptive Platform UI

repository·main·Indexed 42 days ago

https://github.com/berkaycatak/adaptive_platform_ui

A Flutter package providing platform-aware widgets that automatically adapt to the host OS. It features high-fidelity iOS 26+ designs with 'Liquid Glass' effects and spring animations, legacy Cupertino support for iOS 18 and below, and full Material 3 support for Android. Includes unified configuration via AdaptiveApp and a suite of adaptive components such as AdaptiveScaffold, AdaptiveAppBar, AdaptiveButton, and AdaptiveSnackBar.

Tokens
15.9K
Snippets
37
Records
54
Agent score
54%

What's inside Adaptive Platform UI

  1. Overview of Adaptive Platform UI

    main

    Adaptive Platform UI is a Flutter package designed to provide platform-specific widgets that automatically adapt to the host operating system. It features:

    • iOS 26+ Native Designs: Modern components featuring 'Liquid Glass' blur effects, native gesture handling, and spring animations.
    • iOS Legacy Support: Traditional Cupertino widgets for iOS 18 and below.
    • Material Design: Full Material 3 support for Android.
    • Automatic Platform Detection: The package automatically detects the platform and selects the appropriate widget version (e.g., modern iOS vs. legacy Cupertino vs. Material 3) without manual configuration.
    • AdaptiveApp: A unified configuration system for managing themes (Material and Cupertino) and router support.
  2. Use AdaptiveApp for unified app configuration

    main

    The AdaptiveApp abstraction provides a single entry point for configuring your application across all platforms. It handles:

    • Theme Management: Separate themes for Material (Android) and Cupertino (iOS).
    • Theme Modes: Full support for light, dark, and system modes.
    • Routing: Support for routers via AdaptiveApp.router().
    • Zero Config: Automatically applies the correct platform styles without manual setup.
  3. iOS 26+ Native UI Features

    main

    For devices running iOS 26+, the package provides high-fidelity native components that mimic the latest iOS design language:

    • Native UIToolbar: Includes Liquid Glass blur effects and native iOS 26 design.
    • Native UITabBar: Features minimize behavior and smooth animations.
    • Native UIButton: Includes spring animations and haptic feedback.
    • Native UISegmentedControl: Supports SF Symbols.
    • Native UISwitch & UISlider: Features native animations.
    • Visual Polish: Uses native corner radii, shadows, and a dynamic color system for light/dark modes.
  4. Customize the iOS Launch Screen assets

    main

    To change the image displayed during the app's launch on iOS, you can either replace the image files directly in the example/ios/Runner/Assets.xcassets/LaunchImage.imageset/ directory or use Xcode for a more visual approach.

    Using Xcode:

    1. Open the iOS project in Xcode by running open ios/Runner.xcworkspace from your terminal.
    2. In the Xcode Project Navigator, navigate to Runner/Assets.xcassets.
    3. Drag and drop your desired images into the asset catalog to replace the existing launch images.
    open ios/Runner.xcworkspace
  5. Configure your app with AdaptiveApp

    main

    Use AdaptiveApp to automatically configure your application for different platforms. It allows you to define separate themes for Material (Android) and Cupertino (iOS) and supports both standard and router-based navigation.

    import 'package:adaptive_platform_ui/adaptive_platform_ui.dart';
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return AdaptiveApp(
          title: 'My App',
          themeMode: ThemeMode.system,
          materialLightTheme: ThemeData.light(),
          materialDarkTheme: ThemeData.dark(),
          cupertinoLightTheme: const CupertinoThemeData(
            brightness: Brightness.light,
          ),
          cupertinoDarkTheme: const CupertinoThemeData(
            brightness: Brightness.dark,
          ),
          home: const HomePage(),
        );
      }
    }

    For Router support (e.g., GoRouter):

    AdaptiveApp.router(
      routerConfig: router,
      title: 'My App',
      themeMode: ThemeMode.system,
      materialLightTheme: ThemeData.light(),
      materialDarkTheme: ThemeData.dark(),
      cupertinoLightTheme: const CupertinoThemeData(
        brightness: Brightness.light,
      ),
      cupertinoDarkTheme: const CupertinoThemeData(
        brightness: Brightness.dark,
      ),
    )
  6. Configure localization for Adaptive Platform UI

    main

    To ensure proper localization support (e.g., automatic translations for date/time pickers, buttons, and other widgets), you must add the necessary localization delegates to your AdaptiveApp. Without GlobalCupertinoLocalizations.delegate, iOS-style widgets will default to English regardless of the system language.

    Add the following delegates to your localizationsDelegates list and define your supportedLocales in the AdaptiveApp configuration.

    import 'package:flutter_localizations/flutter_localizations.dart';
    
    AdaptiveApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate, // Important!
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en', ''), // English
        Locale('de', ''), // German
        Locale('tr', ''), // Turkish
      ],
      // ... rest of your app configuration
    )
  7. How AdaptiveAppBar handles platform rendering

    main

    The AdaptiveAppBar follows a hierarchical logic to determine which widget to render. Understanding this hierarchy is crucial for avoiding unexpected behavior when providing custom widgets.

    Rendering Logic Hierarchy

    1. Native iOS 26+: If useNativeToolbar is true and the platform is iOS 26+, the native UIToolbar is used. In this mode, cupertinoNavigationBar is ignored.
    2. Custom iOS Bar: If useNativeToolbar is false and cupertinoNavigationBar is provided, the custom CupertinoNavigationBar is used.
    3. Custom Android Bar: If appBar is provided, it is used on Android. This is ignored on iOS.
    4. Default Construction: If no custom bars are provided, the class builds a navigation bar using the title, actions, and leading properties based on the platform's standard (Material for Android, Cupertino for iOS).
  8. Use ToolbarSpacerType for iOS 26+ toolbar layout

    main

    When targeting iOS 26+, you can control the spacing between actions in the native UIToolbar using the spacerAfter property with ToolbarSpacerType:

    • ToolbarSpacerType.none: No extra space (default).
    • ToolbarSpacerType.fixed: Adds a 12pt fixed space, useful for grouping related items together in the same section.
    • ToolbarSpacerType.flexible: Adds flexible space, which pushes subsequent items to the opposite side of the toolbar (e.g., separating left-aligned actions from right-aligned actions).
    // Example: Grouping Undo/Redo on the left and More on the right
    actions: [
      AdaptiveAppBarAction(
        iosSymbol: 'arrow.uturn.backward',
        onPressed: undo,
      ),
      AdaptiveAppBarAction(
        iosSymbol: 'arrow.uturn.forward',
        onPressed: redo,
        spacerAfter: ToolbarSpacerType.flexible, // Pushes the next items to the right
      ),
      AdaptiveAppBarAction(
        iosSymbol: 'ellipsis',
        onPressed: showMore,
      ),
    ]
  9. Customize the bottom navigation bar for iOS or Android

    main

    You can bypass the auto-generated navigation bar by providing platform-specific custom widgets to AdaptiveBottomNavigationBar.

    For iOS

    To use a custom CupertinoTabBar, provide it to the cupertinoTabBar property. Note: On iOS 26+, this will be ignored if useNativeBottomBar is set to true.

    For Android

    To use a custom navigation bar on Android, provide a widget to the bottomNavigationBar property. This widget is ignored on iOS platforms.

    If neither cupertinoTabBar nor bottomNavigationBar is provided, the component will attempt to build a standard bar using the items list.

    // Custom iOS Tab Bar
    const iosCustomBar = AdaptiveBottomNavigationBar(
      cupertinoTabBar: CupertinoTabBar(
        items: [...],
      ),
      useNativeBottomBar: false, // Must be false on iOS 26+ to see custom bar
    );
    
    // Custom Android Navigation Bar
    const androidCustomBar = AdaptiveBottomNavigationBar(
      bottomNavigationBar: MyCustomAndroidNavBarWidget(),
    );
  10. Configure TabBarMinimizeBehavior for iOS 26+

    main

    On iOS 26+, you can control how the native tab bar reacts to scrolling using the minimizeBehavior property in AdaptiveScaffold.

    Options:

    • TabBarMinimizeBehavior.never: The tab bar never minimizes.
    • TabBarMinimizeBehavior.onScrollDown: Minimizes the tab bar when the user scrolls down.
    • TabBarMinimizeBehavior.onScrollUp: Minimizes the tab bar when the user scrolls up.
    • TabBarMinimizeBehavior.automatic: Let the system decide the behavior.
  11. Manage Drawers in AdaptiveScaffold

    main

    The AdaptiveScaffold supports both drawer (left) and endDrawer (right) panels.

    • Android: Passed directly to the Material Scaffold.
    • iOS/iOS 26+: Wrapped with a transparent Material Scaffold to ensure consistent drawer behavior.

    Programmatic Control: To open a drawer via code, provide a scaffoldKey (a GlobalKey<ScaffoldState>) to the AdaptiveScaffold and call:

    • scaffoldKey.currentState?.openDrawer()
    • scaffoldKey.currentState?.openEndDrawer()
    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    
    // In your widget tree
    AdaptiveScaffold(
      scaffoldKey: _scaffoldKey,
      drawer: MyDrawerWidget(),
      body: MyBodyWidget(),
    );
    
    // To open
    _scaffoldKey.currentState?.openDrawer();