flutter_adaptive_kit 0.1.2 copy "flutter_adaptive_kit: ^0.1.2" to clipboard
flutter_adaptive_kit: ^0.1.2 copied to clipboard

A comprehensive Flutter package for building responsive and adaptive UIs. Combines design size scaling, device detection, breakpoints, and extension methods in one unified API.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_adaptive_kit/adaptive_ui.dart';

void main() {
  runApp(const MyApp());
}

/// Example app demonstrating adaptive_ui package features.
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // Wrap your app with AdaptiveScope to enable adaptive features
    return AdaptiveScope(
      // Optional: customize breakpoints
      breakpoints: const AdaptiveBreakpoints(
        phone: 600,
        tablet: 1024,
        desktop: 1440,
      ),
      // Optional: set your design size from Figma/XD
      designSize: const DesignSize(
        phone: Size(375, 812),
        tablet: Size(768, 1024),
        desktop: Size(1440, 900),
      ),
      child: MaterialApp(
        title: 'Adaptive UI Example',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: const HomePage(),
      ),
    );
  }
}

/// Home page demonstrating adaptive layouts
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    // Set context for extensions to work
    AdaptiveContext.setContext(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Adaptive UI Demo'),
        actions: [
          // Show device info in app bar
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Center(
              child: Text(
                '${context.deviceType.name} | ${context.screenSize.name}',
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ),
        ],
      ),
      // Different navigation based on device type
      drawer: context.isPhone ? const AppDrawer() : null,
      body: AdaptiveBuilder(
        // Phone layout: single column with bottom nav
        phone: (context, info) => const PhoneLayout(),
        // Tablet layout: master-detail
        tablet: (context, info) => const TabletLayout(),
        // Desktop layout: full dashboard
        desktop: (context, info) => const DesktopLayout(),
      ),
      // Show bottom nav only on phone
      bottomNavigationBar: AdaptiveVisibility.phoneOnly(
        child: NavigationBar(
          destinations: const [
            NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
            NavigationDestination(icon: Icon(Icons.search), label: 'Search'),
            NavigationDestination(
              icon: Icon(Icons.settings),
              label: 'Settings',
            ),
          ],
        ),
      ),
    );
  }
}

/// Phone layout - single column
class PhoneLayout extends StatelessWidget {
  const PhoneLayout({super.key});

  @override
  Widget build(BuildContext context) {
    AdaptiveContext.setContext(context);

    return SingleChildScrollView(
      padding: EdgeInsets.all(AdaptiveSpacing.md(context)),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const DeviceInfoCard(),
          SizedBox(height: AdaptiveSpacing.md(context)),
          const ExtensionsDemo(),
          SizedBox(height: AdaptiveSpacing.md(context)),
          const ResponsiveGridDemo(),
        ],
      ),
    );
  }
}

/// Tablet layout - master-detail
class TabletLayout extends StatelessWidget {
  const TabletLayout({super.key});

  @override
  Widget build(BuildContext context) {
    AdaptiveContext.setContext(context);

    return Row(
      children: [
        // Side navigation
        NavigationRail(
          selectedIndex: 0,
          destinations: const [
            NavigationRailDestination(
              icon: Icon(Icons.home),
              label: Text('Home'),
            ),
            NavigationRailDestination(
              icon: Icon(Icons.search),
              label: Text('Search'),
            ),
            NavigationRailDestination(
              icon: Icon(Icons.settings),
              label: Text('Settings'),
            ),
          ],
        ),
        const VerticalDivider(thickness: 1, width: 1),
        // Main content
        Expanded(
          child: SingleChildScrollView(
            padding: EdgeInsets.all(AdaptiveSpacing.lg(context)),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const DeviceInfoCard(),
                SizedBox(height: AdaptiveSpacing.lg(context)),
                const ExtensionsDemo(),
                SizedBox(height: AdaptiveSpacing.lg(context)),
                const ResponsiveGridDemo(),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

/// Desktop layout - full dashboard with sidebar
class DesktopLayout extends StatelessWidget {
  const DesktopLayout({super.key});

  @override
  Widget build(BuildContext context) {
    AdaptiveContext.setContext(context);

    return Row(
      children: [
        // Extended navigation
        NavigationRail(
          extended: true,
          selectedIndex: 0,
          destinations: const [
            NavigationRailDestination(
              icon: Icon(Icons.home),
              label: Text('Home'),
            ),
            NavigationRailDestination(
              icon: Icon(Icons.search),
              label: Text('Search'),
            ),
            NavigationRailDestination(
              icon: Icon(Icons.analytics),
              label: Text('Analytics'),
            ),
            NavigationRailDestination(
              icon: Icon(Icons.settings),
              label: Text('Settings'),
            ),
          ],
        ),
        const VerticalDivider(thickness: 1, width: 1),
        // Main content area
        Expanded(
          flex: 3,
          child: SingleChildScrollView(
            padding: EdgeInsets.all(AdaptiveSpacing.xl(context)),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Expanded(child: DeviceInfoCard()),
                    SizedBox(width: AdaptiveSpacing.lg(context)),
                    const Expanded(child: ExtensionsDemo()),
                  ],
                ),
                SizedBox(height: AdaptiveSpacing.xl(context)),
                const ResponsiveGridDemo(),
              ],
            ),
          ),
        ),
        const VerticalDivider(thickness: 1, width: 1),
        // Right sidebar
        SizedBox(
          width: 300,
          child: Padding(
            padding: EdgeInsets.all(AdaptiveSpacing.md(context)),
            child: const Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Quick Actions',
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 16),
                ListTile(leading: Icon(Icons.add), title: Text('New Item')),
                ListTile(leading: Icon(Icons.upload), title: Text('Import')),
                ListTile(leading: Icon(Icons.download), title: Text('Export')),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

/// Card showing current device info
class DeviceInfoCard extends StatelessWidget {
  const DeviceInfoCard({super.key});

  @override
  Widget build(BuildContext context) {
    final info = context.deviceInfo;

    return Card(
      child: Padding(
        padding: EdgeInsets.all(AdaptiveSpacing.md(context)),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Device Information',
              style: TextStyle(
                fontSize: AdaptiveFontSize.title(context),
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            _InfoRow('Device Type', info.deviceType.name),
            _InfoRow('Screen Size', info.screenSize.name),
            _InfoRow(
              'Dimensions',
              '${info.screenWidth.toInt()} x ${info.screenHeight.toInt()}',
            ),
            _InfoRow('Orientation', info.orientation.name),
            _InfoRow('Pixel Ratio', info.pixelRatio.toStringAsFixed(2)),
            _InfoRow('Scale Width', info.scaleWidth.toStringAsFixed(3)),
            _InfoRow('Scale Height', info.scaleHeight.toStringAsFixed(3)),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            Wrap(
              spacing: 8,
              children: [
                Chip(label: Text('isPhone: ${context.isPhone}')),
                Chip(label: Text('isTablet: ${context.isTablet}')),
                Chip(label: Text('isDesktop: ${context.isDesktop}')),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _InfoRow extends StatelessWidget {
  final String label;
  final String value;

  const _InfoRow(this.label, this.value);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
          Text(
            value,
            style: TextStyle(color: Theme.of(context).colorScheme.primary),
          ),
        ],
      ),
    );
  }
}

/// Demo showing extension methods
class ExtensionsDemo extends StatelessWidget {
  const ExtensionsDemo({super.key});

  @override
  Widget build(BuildContext context) {
    AdaptiveContext.setContext(context);

    return Card(
      child: Padding(
        padding: EdgeInsets.all(AdaptiveSpacing.md(context)),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Extension Methods Demo',
              style: TextStyle(
                fontSize: AdaptiveFontSize.title(context),
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            // Box scaled with .aw (adaptive width)
            Container(
              width: 200.aw,
              height: 60.ah,
              decoration: BoxDecoration(
                color: Colors.deepPurple.shade100,
                borderRadius: BorderRadius.circular(12.ar),
              ),
              alignment: Alignment.center,
              child: Text(
                '200.aw x 60.ah\nBorderRadius: 12.ar',
                textAlign: TextAlign.center,
                style: TextStyle(fontSize: 12.asp),
              ),
            ),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            // Percentage-based sizing
            Container(
              width: 50.pw, // 50% of screen width
              height: 40,
              color: Colors.blue.shade100,
              alignment: Alignment.center,
              child: const Text('50.pw (50% width)'),
            ),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            // Responsive values
            Text(
              'Responsive Value Example:',
              style: TextStyle(fontSize: AdaptiveFontSize.body(context)),
            ),
            const SizedBox(height: 8),
            Text(
              'Padding: ${context.adaptive<double>(phone: 16, tablet: 24, desktop: 32).toInt()}px',
              style: TextStyle(
                color: Theme.of(context).colorScheme.secondary,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/// Demo showing responsive grid
class ResponsiveGridDemo extends StatelessWidget {
  const ResponsiveGridDemo({super.key});

  @override
  Widget build(BuildContext context) {
    // Get columns based on screen size
    final columns = context.responsive<int>(xs: 1, sm: 2, md: 3, lg: 4, xl: 6);

    return Card(
      child: Padding(
        padding: EdgeInsets.all(AdaptiveSpacing.md(context)),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Responsive Grid ($columns columns)',
              style: TextStyle(
                fontSize: AdaptiveFontSize.title(context),
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: AdaptiveSpacing.sm(context)),
            GridView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: columns,
                crossAxisSpacing: AdaptiveSpacing.sm(context),
                mainAxisSpacing: AdaptiveSpacing.sm(context),
                childAspectRatio: 1,
              ),
              itemCount: 12,
              itemBuilder: (context, index) {
                return Container(
                  decoration: BoxDecoration(
                    color: Colors
                        .primaries[index % Colors.primaries.length]
                        .shade100,
                    borderRadius: BorderRadius.circular(8.ar),
                  ),
                  alignment: Alignment.center,
                  child: Text(
                    '${index + 1}',
                    style: TextStyle(
                      fontSize: AdaptiveFontSize.headline(context),
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

/// Simple drawer for phone layout
class AppDrawer extends StatelessWidget {
  const AppDrawer({super.key});

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
        children: [
          DrawerHeader(
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.primaryContainer,
            ),
            child: const Text('Adaptive UI', style: TextStyle(fontSize: 24)),
          ),
          const ListTile(leading: Icon(Icons.home), title: Text('Home')),
          const ListTile(leading: Icon(Icons.search), title: Text('Search')),
          const ListTile(
            leading: Icon(Icons.settings),
            title: Text('Settings'),
          ),
        ],
      ),
    );
  }
}
3
likes
160
points
194
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter package for building responsive and adaptive UIs. Combines design size scaling, device detection, breakpoints, and extension methods in one unified API.

Repository (GitHub)
View/report issues

Topics

#responsive #adaptive #ui #screen-size #breakpoints

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on flutter_adaptive_kit