Skip to content

Instantly share code, notes, and snippets.

@ayoubzulfiqar
Last active April 29, 2026 06:50
Show Gist options
  • Select an option

  • Save ayoubzulfiqar/53db6565404b0ad033f335c1b0e46583 to your computer and use it in GitHub Desktop.

Select an option

Save ayoubzulfiqar/53db6565404b0ad033f335c1b0e46583 to your computer and use it in GitHub Desktop.
Flutter Rules for AI

Complete Flutter & Dart Best Practices Guide with Official Documentation References

Overview

This guide provides comprehensive, up-to-date best practices for Flutter and Dart development with direct links to official documentation, ensuring you're always following the latest standards and recommendations from Google and the Flutter team.

1. Dart Language Fundamentals & Null Safety

Sound Null Safety (Dart 3.0+)

**Starting with Dart 3.0, null safety is mandatory and sound. All code must be fully null-safe. **

Key Principles:

  • Sound Null Safety: Dart 3 and later requires sound null safety - all libraries must be fully migrated
  • Migration Path: Use dart pub outdated --mode=null-safety to check dependency status
  • Min SDK: Set sdk: '>=3.0.0 <4.0.0' in pubspec.yaml

Official Documentation:

Best Practices:

// ✅ DO: Use proper nullable/non-nullable types
class User {
  final String id;           // Non-nullable
  final String? email;       // Nullable
  final List<String> tags;   // Non-nullable collection
  
  const User({
    required this.id,        // Required for non-nullable
    this.email,
    this.tags = const [],    // Default value
  });
}

// ❌ DON'T: Use the ! operator unless absolutely certain
String value = nullableValue!;  // Avoid when possible

// ✅ DO: Use null-aware operators
String displayName = user?.name ?? 'Anonymous';

Effective Dart Guidelines

Official Documentation: Effective Dart

Style Guide Compliance:

// ✅ DO: Use PascalCase for classes
class MyWidget extends StatelessWidget { }

// ✅ DO: Use camelCase for variables and functions
final myVariable = 42;
void myFunction() { }

// ✅ DO: Use lowerCamelCase for constants
const defaultPadding = 16.0;

// ✅ DO: Use descriptive names
void calculateTotalRevenue() { }  // Good

// ❌ DON'T: Use abbreviations unless common
void calcRev() { }  // Avoid

2. Flutter Core Concepts & Latest Features

Flutter 3.27+ Highlights

Latest stable release as of December 2024: Flutter 3.27

Key Features:

  • Impeller as Default Renderer: Performance improvements with reduced jank on iOS and Android
  • Swift Package Manager: Replaces CocoaPods for iOS development
  • Enhanced Cupertino Widgets: Better iOS fidelity with updated CupertinoCheckbox, CupertinoRadio, CupertinoButton
  • New Layout Features: spacing parameter in Row/Column, CarouselView.weighted for dynamic layouts

Official Documentation:

Deprecated APIs in Flutter 3.27

Based on recent changes, these APIs are deprecated :

Deprecated Feature Replacement
TextField.canRequestFocus Use focus management directly
ThemeData.dialogBackgroundColor DialogThemeData.backgroundColor
InputDecoration.collapsed parameters Use only essential parameters
Automatic AssetManifest.json generation Manually specify if needed

Always check the Flutter Deprecation Guide before upgrading.

3. State Management Best Practices (2026)

Modern State Management Landscape

**As of 2026, teams optimize for clarity and predictability. The "state management wars" have matured. **

Recommended Options:

Solution Best For Documentation
Riverpod 2.0+ Most new projects, compile-time safety Riverpod Docs
BLoC Enterprise apps, complex business logic BLoC Library
Signals Ultra-hot paths, performance-critical UIs Signals for Flutter

Riverpod 2.6.0+ Best Practices

Latest version: 2.6.0 (October 2024)

// ✅ DO: Use Code Generation (Riverpod 2.0+)
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'counter_provider.g.dart';

@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;
  
  void increment() => state++;
}

// ✅ DO: Use ConsumerWidget for UI
class CounterDisplay extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
  }
}

// ⚠️ NOTE: Ref's type argument is deprecated in 2.6.0
// Old: Ref<MyState>
// New: Ref

Performance-Conscious State Management

**With 120Hz displays becoming mainstream, optimize for 8-11ms frame budgets. **

// ✅ DO: Use selectors to rebuild only what changed
final userName = ref.watch(userProvider.select((user) => user.name));

// ✅ DO: Minimize rebuild scope
@riverpod
class OptimizedNotifier extends _$OptimizedNotifier {
  @override
  int build() => 0;
  
  // Batch state updates
  void batchUpdate() {
    state = state + 1;
    // Avoid multiple separate updates
  }
}

4. Performance Optimization (2026 Edition)

The 3 Silent Performance Killers

1. Rebuild Spiral

// ❌ DON'T: Rebuilding unnecessarily
Widget build(BuildContext context) {
  return Container(
    child: Text(calculateExpensiveValue()), // Runs on every build
  );
}

// ✅ DO: Cache expensive computations
final expensiveValue = useMemoized(() => calculateExpensiveValue());

// ✅ DO: Use const constructors everywhere possible
const SizedBox(height: 16)  // Good
Padding(padding: EdgeInsets.all(8))  // Not const - use const EdgeInsets.all(8)

2. 120Hz Frame Budget

  • Target: ≤8ms per frame (down from 16ms at 60fps)
  • Profile with Flutter DevTools early and often
  • Measure frame times, not just CPU usage

3. Lazy Loading & Off-Screen Optimization

// ✅ DO: Always use builder for lists
ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)

// ✅ DO: Use RepaintBoundary for isolated animations
RepaintBoundary(
  child: ComplexAnimationWidget(),
)

Official Performance Resources:

Free GitHub Learning Resources :

5. Material Design 3 & Cupertino Styling

Material Design 3 (Material You)

**Flutter 3.27 enhances Material 3 support with revamped sliders, progress indicators, and component theme normalization. **

// ✅ DO: Use Material 3 with dynamic color scheme
class AppTheme {
  static ThemeData lightTheme = ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.deepPurple,
      brightness: Brightness.light,
    ),
  );
}

Cupertino (iOS-style) Widgets

Flutter 3.27 improves Cupertino widgets for better iOS fidelity:

  • CupertinoCheckbox and CupertinoRadio updated
  • CupertinoButton aligns with iOS 15+ customizability
  • CupertinoActionSheet, CupertinoContextMenu improvements
// ✅ DO: Use Cupertino widgets for iOS-specific styling
import 'package:flutter/cupertino.dart';

class IosStyledPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('iOS Style'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {},
          child: const Text('Press Me'),
        ),
      ),
    );
  }
}

Official Documentation:

6. Async Programming & Error Handling

Futures, Streams, and Error Handling

// ✅ DO: Proper async/await with error handling
Future<User> fetchUser(String id) async {
  try {
    final response = await http.get(Uri.parse('$apiUrl/users/$id'));
    if (response.statusCode == 200) {
      return User.fromJson(jsonDecode(response.body));
    }
    throw ApiException('Failed to load user: ${response.statusCode}');
  } on SocketException {
    throw NetworkException('No internet connection');
  } catch (e) {
    throw UnknownException('Unexpected error: $e');
  }
}

// ✅ DO: Use Stream for sequences of events
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;
  }
}

Official Documentation:

7. Latest Rendering Engine: Impeller

Impeller Overview

As of Flutter 3.27, Impeller is the default rendering engine for iOS and Android.

Performance Gains (2026):

  • Jank reduction: 30-50% for complex animations
  • Text rendering speed: 20-40% improvement
  • Drop frame rate: from 12% (Skia) to 1.5% (Impeller)
  • Supports 120Hz displays seamlessly
# No configuration needed - Impeller is default in Flutter 3.27+
# For older versions, enable in android/app/build.gradle:
android {
  defaultConfig {
    // ...
  }
}

Official Documentation:

8. Web & Desktop Development

WebAssembly (Wasm) Support

Flutter 2026 roadmap indicates Wasm will become the standard for Flutter Web.

# To enable Wasm compilation (future versions):
flutter build web --wasm

Benefits:

  • Near-native performance for Flutter Web
  • Smaller bundle sizes
  • Better memory management

Official Documentation:

9. Linting & Code Quality

analysis_options.yaml (Strict Configuration)

include: package:flutter_lints/flutter.yaml

linter:
  rules:
    # Core quality rules
    - always_declare_return_types
    - avoid_print
    - avoid_unnecessary_containers
    - avoid_web_libraries_in_flutter
    - camel_case_types
    - constant_identifier_names
    - curly_braces_in_flow_control_structures
    - depend_on_referenced_packages
    - no_adjacent_strings_in_list
    - no_duplicate_case_values
    - prefer_const_constructors
    - prefer_const_declarations
    - prefer_final_fields
    - prefer_final_locals
    - prefer_single_quotes
    - sort_child_properties_last
    - sort_pub_dependencies
    - unnecessary_brace_in_string_interps
    - unnecessary_const
    - unnecessary_final
    - unnecessary_lambdas
    - unnecessary_null_aware_assignments
    - unnecessary_null_checks
    - unnecessary_nullable_for_final_variable_declarations
    - unnecessary_string_interpolations

analyzer:
  errors:
    invalid_annotation_target: ignore
    missing_required_param: error
    missing_return: error
    must_be_immutable: error
    unrelated_type_equality_checks: error

Official Documentation:

10. Testing Strategy

Testing Hierarchy

// 1. Unit Tests (Business Logic)
test('Counter increments correctly', () {
  final counter = Counter();
  counter.increment();
  expect(counter.value, 1);
});

// 2. Widget Tests (UI Components)
testWidgets('Button shows correct text', (tester) async {
  await tester.pumpWidget(MyButton(text: 'Click'));
  expect(find.text('Click'), findsOneWidget);
});

// 3. Integration Tests (Full User Flows)
test('Complete user flow', () async {
  await driver.tap(find.byValueKey('login_button'));
  await driver.enterText(find.byValueKey('email'), 'user@example.com');
  await driver.tap(find.byValueKey('submit'));
  expect(await driver.getText(find.byValueKey('welcome')), 'Welcome!');
});

Commands:

# Run all tests
flutter test

# Run with coverage
flutter test --coverage

# Generate coverage report
genhtml coverage/lcov.info -o coverage/html

# Run integration tests
flutter test integration_test/

Official Documentation:

11. Recent Deprecations & Breaking Changes (2024-2025)

Must-Know Changes:

Library/Feature Deprecation Replacement Version
Riverpod Ref Type Argument Ref<MyState> Ref only Riverpod 2.6.0
CocoaPods for iOS iOS dependency management Swift Package Manager Flutter 3.27
Skia Renderer on Android Skia default Impeller default Flutter 3.27
TextField.canRequestFocus Property Direct focus management Flutter 3.27

How to Check for Deprecations:

# Run with deprecation warnings
flutter analyze

# Check specific package
dart pub outdated

# View migration guide
dart fix --dry-run
dart fix --apply

12. Essential Packages & Their Official Docs (2026)

Category Recommended Package Documentation
State Management Riverpod ^2.6.0 riverpod.dev
Navigation go_router ^14.0+ pub.dev/go_router
Networking Dio ^5.4+ pub.dev/dio
Local Storage Hive ^4.0+ pub.dev/hive
JSON Serialization json_serializable ^6.8+ pub.dev/json_serializable
Immutable Models Freezed ^2.5+ pub.dev/freezed
Dependency Injection (Built into Riverpod) N/A
Logging Logger ^2.0+ pub.dev/logger
Analytics Firebase Analytics ^11.0+ firebase.flutter.dev
Crash Reporting Sentry ^8.0+ pub.dev/sentry

13. Essential Commands Reference

# Create new project
flutter create my_app --org com.example --platforms=ios,android,web

# Run with specific flavor
flutter run --flavor prod -t lib/main_prod.dart

# Build for production
flutter build apk --release --split-per-abi
flutter build ios --release
flutter build web --wasm  # Future

# Analyze and fix issues
flutter analyze
dart fix --apply

# Update dependencies
flutter pub upgrade --major-versions

# Check null safety status
dart pub outdated --mode=null-safety

# Profile performance
flutter run --profile

# Generate code
dart run build_runner build --delete-conflicting-outputs

# Test with coverage
flutter test --coverage --machine > coverage.json

14. Official Documentation Quick Reference

Primary Sources:

Performance & Best Practices:

Community & Updates:

Final Checklist for Production-Ready Code

Before committing code, verify:

  • ✅ No analyzer warnings (flutter analyze passes)
  • ✅ All tests pass (flutter test)
  • const used wherever possible
  • ✅ No unnecessary rebuilds (check with DevTools)
  • ✅ Null safety fully implemented (no ! abuses)
  • ✅ Proper error handling for async operations
  • ✅ Semantic labels for accessibility
  • ✅ Responsive layout for all screen sizes
  • ✅ Deprecated APIs replaced
  • ✅ Dependencies are up-to-date and null-safe
  • ✅ Impeller rendering enabled (Flutter 3.27+)
  • ✅ iOS and Android specific UI considerations addressed

Android & iOS Native Design Guide for Flutter

As of 2026, both Android and iOS have introduced significant design updates—Material 3 Expressive and Apple's Liquid Glass—while the Flutter team has strategically paused direct integration of these features into core libraries. This guide provides comprehensive, actionable strategies for creating truly native-feeling Flutter apps on both platforms using current best practices and community-driven solutions.

Part 1: Current Platform Design Landscape (2026)

Android 16+ Design: Material 3 Expressive

Announced at Google I/O 2025 and rolling out with Android 16, Material 3 Expressive represents a significant evolution from Material You :

Feature Description Implementation Need
Bouncier Animations UI elements jiggle on swipe, snap back on dismiss Custom animation controllers
Revamped Quick Settings Smaller, categorized tiles with drag-and-drop Platform channel integration
Enhanced Wallpaper Effects Weather overlays (snow, rain, fog) with adjustable intensity Not applicable to in-app UI
New Volume Panel Sleeker layout with floating options System UI, not app-controlled
Audio Sharing LE Audio support for shared listening Platform-specific feature

Critical Note: The Flutter team has officially announced they are not actively developing Material 3 Expressive features in core, citing the complex migration from Material 2 to 3 and ongoing architectural reevaluation . The plan is to potentially decouple Material and Cupertino design systems into standalone packages for independent evolution .

iOS 26 Design: Liquid Glass

Announced at WWDC 2025, Apple's Liquid Glass introduces a system-wide frosted-glass aesthetic :

Feature Description
Refractive Effects Dynamic lighting that responds to device orientation
Depth & Layering Multi-layered translucency for hierarchy communication
Contextual Blur Adaptive blur strength based on content underneath
Glassmorphism Subtle tinted glass effects with dynamic lighting

Current Status: The Flutter team has stated that work is not currently planned to integrate Liquid Glass into core Cupertino widgets . This aligns with community sentiment that Flutter's strength is transcending platform limitations rather than chasing every design trend .

Strategic Pause Rationale

The Flutter team's decision to pause native design system integration is strategic :

  1. Decoupling Architecture: Moving Material and Cupertino to standalone packages for faster, independent evolution
  2. Core Focus Areas (2026 Roadmap):
    • Completing Impeller migration on Android
    • WebAssembly (Wasm) becoming default for web
    • GenUI SDK for AI-driven adaptive interfaces
    • Full-stack Dart support
  3. Community Leverage: Trusting the ecosystem to fill design gaps while core focuses on performance

Official Roadmap: Flutter & Dart's 2026 Roadmap

Part 2: Core Platform Adaptations (Built into Flutter)

Flutter provides automatic platform adaptations for behaviors that would feel "wrong" if different . These work immediately without additional packages.

Navigation Adaptations

// Flutter automatically adapts navigation to platform
// Android: Zoom transition (ZoomPageTransitionsBuilder)
// iOS: Slide transition with parallax effect

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => DetailScreen()),
);
// On iOS: slides from right (or left in RTL)
// On Android: zooms in from tapped element

// Full-screen modal (iOS-style bottom sheet)
Navigator.push(
  context,
  MaterialPageRoute(
    fullscreenDialog: true,  // iOS: present-style modal
    builder: (context) => ModalScreen(),
  ),
);

Back Navigation Differences

Platform Back Behavior
Android System back button pops top route automatically
iOS Edge swipe gesture pops route, no system back button

Both work automatically with Flutter's Navigator.

Scrolling Physics

Flutter automatically applies platform-appropriate scrolling physics :

// These all adapt automatically
ListView.builder(...)
SingleChildScrollView(...)
CustomScrollView(...)

// iOS characteristics:
// - More weight and dynamic friction
// - Momentum stacking (repeated flings build speed)
// - Tapping status bar scrolls to top

// Android characteristics:
// - More static friction, less "slippery"
// - Glow overscroll indicator (not bounce)

Overscroll Behavior

// MaterialApp automatically configures correct overscroll
MaterialApp(
  theme: ThemeData(useMaterial3: true),
  home: MyHomePage(),
);

// Android: Glow indicator (colored by theme)
// iOS: Bounce with resistance

Typography & Iconography

// Automatic font selection
MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
    // Android: Roboto
    // iOS: San Francisco (license restricts to Apple platforms)
  ),
);

// Platform-adaptive icons
Icon(Icons.adaptive.more_vert)  // iOS: horizontal dots, Android: vertical dots
Icon(Icons.adaptive.arrow_back)  // Platform-appropriate back arrow

Text Editing Differences

Interaction Android iOS
Single tap Cursor at tap location with handle Cursor at nearest word edge
Long press Selects word, shows toolbar Places cursor, shows toolbar
Long press drag Expands selection Moves cursor
Keyboard gestures Space bar swipe moves cursor Force touch for floating cursor

All handled automatically by TextField and CupertinoTextField.

Haptic Feedback

Flutter automatically triggers platform-appropriate haptics :

Action Android iOS
Long press text field Buzz vibration None
Picker item scroll None Light impact
// Manual haptics when needed
import 'package:flutter/services.dart';

// Light impact (button press)
await HapticFeedback.lightImpact();

// Selection click (picker wheel)
await HapticFeedback.selectionClick();

// Heavy impact (error/confirmation)
await HapticFeedback.heavyImpact();

Part 3: Implementing Platform-Specific UI Components

Adaptive Constructors (Built-in)

Flutter provides .adaptive() constructors for components tightly integrated with OS expectations :

Material Widget Cupertino Widget Adaptive Constructor
Switch CupertinoSwitch Switch.adaptive()
Slider CupertinoSlider Slider.adaptive()
CircularProgressIndicator CupertinoActivityIndicator CircularProgressIndicator.adaptive()
RefreshProgressIndicator CupertinoActivityIndicator RefreshIndicator.adaptive()
Checkbox CupertinoCheckbox Checkbox.adaptive()
Radio CupertinoRadio Radio.adaptive()
AlertDialog CupertinoAlertDialog AlertDialog.adaptive()

Important Note: AlertDialog.adaptive() requires manual button styling for complete native feel :

// Complete adaptive dialog with proper button styling
Future<void> showAdaptiveDialog(BuildContext context) async {
  return showDialog(
    context: context,
    builder: (BuildContext context) {
      final theme = Theme.of(context);
      return AlertDialog.adaptive(
        title: const Text('Confirm'),
        content: const Text('Are you sure?'),
        actions: [
          adaptiveAction(
            context: context,
            onPressed: () => Navigator.pop(context, false),
            child: const Text('Cancel'),
          ),
          adaptiveAction(
            context: context,
            onPressed: () => Navigator.pop(context, true),
            child: const Text('Confirm'),
          ),
        ],
      );
    },
  );
}

Widget adaptiveAction({
  required BuildContext context,
  required VoidCallback onPressed,
  required Widget child,
}) {
  final theme = Theme.of(context);
  switch (theme.platform) {
    case TargetPlatform.iOS:
    case TargetPlatform.macOS:
      return CupertinoDialogAction(
        onPressed: onPressed,
        child: child,
      );
    default:
      return TextButton(
        onPressed: onPressed,
        child: child,
      );
  }
}

Platform-Aware Scaffolding

// Complete platform-aware scaffold
import 'dart:io' show Platform;

class PlatformScaffold extends StatelessWidget {
  final String title;
  final Widget body;
  final List<Widget>? actions;
  
  const PlatformScaffold({
    required this.title,
    required this.body,
    this.actions,
  });
  
  @override
  Widget build(BuildContext context) {
    if (Platform.isIOS) {
      return CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: Text(title),
          trailing: actions != null && actions!.isNotEmpty
              ? Row(mainAxisSize: MainAxisSize.min, children: actions!)
              : null,
        ),
        child: body,
      );
    }
    
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        actions: actions,
        surfaceTintColor: Colors.transparent, // iOS-style minimalism
      ),
      body: body,
    );
  }
}

Adaptive Navigation Bars

// Platform-appropriate bottom navigation
class AdaptiveBottomNavigation extends StatelessWidget {
  final int selectedIndex;
  final ValueChanged<int> onTap;
  final List<BottomNavigationItem> items;
  
  const AdaptiveBottomNavigation({
    required this.selectedIndex,
    required this.onTap,
    required this.items,
  });
  
  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    
    switch (theme.platform) {
      case TargetPlatform.iOS:
      case TargetPlatform.macOS:
        return CupertinoTabBar(
          currentIndex: selectedIndex,
          onTap: onTap,
          items: items.map((item) => BottomNavigationBarItem(
            icon: Icon(item.icon),
            label: item.label,
          )).toList(),
        );
      default:
        return NavigationBar(
          selectedIndex: selectedIndex,
          onDestinationSelected: onTap,
          destinations: items.map((item) => NavigationDestination(
            icon: Icon(item.icon),
            label: item.label,
          )).toList(),
        );
    }
  }
}

class BottomNavigationItem {
  final IconData icon;
  final String label;
  
  const BottomNavigationItem({required this.icon, required this.label});
}

Part 4: Community Solutions for Latest Design Trends

Liquid Glass Effect (iOS 26)

Since core Cupertino widgets won't immediately support Liquid Glass, the community has created solutions :

dependencies:
  liquid_glass: ^0.1.0  # Community package for glassmorphism
  # OR
  liquid_glass_renderer: ^0.0.1  # Impeller-only version

Note: liquid_glass_renderer currently only supports the Impeller rendering engine .

Manual Implementation using BackdropFilter:

// Custom glassmorphism effect (approximates Liquid Glass)
class GlassmorphicCard extends StatelessWidget {
  final Widget child;
  final double blurStrength;
  final double opacity;
  
  const GlassmorphicCard({
    required this.child,
    this.blurStrength = 10,
    this.opacity = 0.2,
  });
  
  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(20),
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: blurStrength, sigmaY: blurStrength),
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Colors.white.withOpacity(opacity),
                Colors.white.withOpacity(opacity * 0.5),
              ],
            ),
            border: Border.all(
              color: Colors.white.withOpacity(0.3),
              width: 1,
            ),
            borderRadius: BorderRadius.circular(20),
          ),
          child: child,
        ),
      ),
    );
  }
}

Material 3 Expressive Animation Effects

Since core Material doesn't include the "bouncy" animations of M3 Expressive, implement custom animations :

// Spring-based bounce animation for Material 3 Expressive feel
class BouncyButton extends StatelessWidget {
  final VoidCallback onPressed;
  final Widget child;
  
  const BouncyButton({
    required this.onPressed,
    required this.child,
  });
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => HapticFeedback.lightImpact(),
      onTap: onPressed,
      child: TweenAnimationBuilder(
        tween: Tween<double>(begin: 1.0, end: 1.0),
        duration: const Duration(milliseconds: 200),
        curve: Curves.elasticOut,
        builder: (context, scale, child) {
          return Transform.scale(
            scale: scale,
            child: child,
          );
        },
        child: Material(
          elevation: 2,
          borderRadius: BorderRadius.circular(12),
          child: InkWell(
            onTap: () {},
            borderRadius: BorderRadius.circular(12),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
              child: child,
            ),
          ),
        ),
      ),
    );
  }
}

Part 5: Advanced Platform-Aware Widget Libraries

Extended Platform Widgets Package

For comprehensive platform adaptation without conditional code:

dependencies:
  extended_platform_widgets: ^1.0.0  # Fork supporting all platforms

Usage:

// Instead of manual conditionals:
if (Platform.isAndroid) {
  return ElevatedButton(...);
} else if (Platform.isIOS) {
  return CupertinoButton(...);
}

// Use platform widget:
PlatformElevatedButton(
  onPressed: () {},
  child: Text('Button'),
)
// Renders: ElevatedButton on Android, CupertinoButton.filled on iOS

This library supports all Flutter platforms: Android, iOS, Web, macOS, Windows, Linux, Fuchsia .

Platform-Specific Navigation Transitions

// Custom page route with platform-appropriate transitions
class PlatformPageRoute<T> extends PageRoute<T> {
  final WidgetBuilder builder;
  
  PlatformPageRoute({required this.builder});
  
  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    final platform = Theme.of(context).platform;
    
    if (platform == TargetPlatform.iOS) {
      return CupertinoPageTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: false,
        child: builder(context),
      );
    }
    
    return FadeTransition(
      opacity: animation,
      child: builder(context),
    );
  }
  
  // ... implement other required PageRoute methods
}

Part 6: Responsive & Adaptive Layout (Android 16 Approach)

Android 16 emphasizes adaptive layouts using window size classes—a concept equally applicable to Flutter :

Window Size Classes

// Implement Android 16's window size class concept
enum WindowSizeClass { compact, medium, expanded }

class AdaptiveLayout extends StatelessWidget {
  final Widget compactLayout;
  final Widget mediumLayout;
  final Widget expandedLayout;
  
  const AdaptiveLayout({
    required this.compactLayout,
    required this.mediumLayout,
    required this.expandedLayout,
  });
  
  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    final sizeClass = _getWindowSizeClass(width);
    
    switch (sizeClass) {
      case WindowSizeClass.expanded:
        return expandedLayout;
      case WindowSizeClass.medium:
        return mediumLayout;
      case WindowSizeClass.compact:
        return compactLayout;
    }
  }
  
  WindowSizeClass _getWindowSizeClass(double width) {
    if (width >= 840) return WindowSizeClass.expanded;
    if (width >= 600) return WindowSizeClass.medium;
    return WindowSizeClass.compact;
  }
}

List-Detail Pattern (Two-Pane Layout)

Android 16's Material 3 Adaptive library includes ListDetailPaneScaffold—implement similarly in Flutter :

// Two-pane layout (tablet/desktop) vs single-pane (phone)
class AdaptiveListDetailView extends StatelessWidget {
  final List<Item> items;
  final Widget Function(Item) detailBuilder;
  
  const AdaptiveListDetailView({
    required this.items,
    required this.detailBuilder,
  });
  
  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    final isTwoPane = width >= 600;
    
    if (isTwoPane) {
      return Row(
        children: [
          SizedBox(
            width: width * 0.35,
            child: _buildList(),
          ),
          VerticalDivider(width: 1),
          Expanded(
            child: _buildDetail(selectedItem),
          ),
        ],
      );
    }
    
    return _buildList();
  }
  
  Widget _buildList() => ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, index) => ListTile(
      title: Text(items[index].title),
      onTap: () => Navigator.push(
        context,
        MaterialPageRoute(
          builder: (_) => detailBuilder(items[index]),
        ),
      ),
    ),
  );
}

Part 7: Testing Platform Adaptations

// Test platform-specific behavior
void main() {
  testWidgets('Shows Cupertino button on iOS', (tester) async {
    // Set platform to iOS
    debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
    
    await tester.pumpWidget(
      MaterialApp(
        home: PlatformElevatedButton(
          onPressed: () {},
          child: Text('Button'),
        ),
      ),
    );
    
    expect(find.byType(CupertinoButton), findsOneWidget);
    
    // Reset
    debugDefaultTargetPlatformOverride = null;
  });
}

Part 8: Quick Reference Table

Requirement Android iOS Implementation
Navigation bar AppBar CupertinoNavigationBar Platform check or PlatformScaffold
Bottom tabs NavigationBar CupertinoTabBar Platform check
Buttons ElevatedButton CupertinoButton .adaptive() constructors
Dialogs AlertDialog CupertinoAlertDialog AlertDialog.adaptive() with custom actions
Progress CircularProgressIndicator CupertinoActivityIndicator .adaptive() constructor
Switches Switch CupertinoSwitch Switch.adaptive()
Scroll physics Glow overscroll Bounce overscroll Automatic
Back navigation System back button Edge swipe Automatic
Haptics Vibration on long press Light impact on pickers Automatic + manual
Typography Roboto San Francisco Automatic in MaterialApp
Icons Vertical dots Horizontal dots Icons.adaptive

Part 9: Official Documentation References

Primary Sources:

Community & Platform Updates:

Final Recommendations

  1. Leverage built-in adaptations first – Navigation, scrolling, text editing, and haptics work automatically
  2. Use .adaptive() constructors for switches, sliders, progress indicators, and alerts
  3. Implement custom platform_widgets for scaffolding and complex components
  4. Monitor community packages for Liquid Glass and Material 3 Expressive effects
  5. Test on both platforms using debugDefaultTargetPlatformOverride
  6. Design responsively using window size classes for foldables and tablets
  7. Stay updated on Flutter's decoupling of Material/Cupertinto—expected to enable faster trend adoption

Flutter Widget Library & MethodChannel Guidelines

This guide provides a comprehensive catalog of Flutter's widget library organized by category, with the latest updates from Flutter 3.27+ and practical implementation patterns for MethodChannel.

Part 1: Complete Widget Library by Category

1.1 Core Basics Widgets

The foundational building blocks for any Flutter application.

Widget Description Key Use Case
Container Combines painting, positioning, and sizing Most common layout wrapper with padding, margin, decoration
Row Horizontally arranges children Horizontal layouts, button groups, form rows
Column Vertically arranges children Vertical stacks, forms, lists
Stack Positions children relative to edges Overlays, badges, floating elements
IndexedStack Shows one child at a time by index Tab content switching without rebuilding
ListView Scrollable list of children Long lists, chat messages, feeds
GridView Scrollable 2D array of children Photo galleries, product grids
SingleChildScrollView Makes a single child scrollable Forms that exceed screen height
CustomScrollView Creates custom scroll effects Sliver-based layouts, custom scroll behaviors

1.2 Material Design 3 Widgets (Android/Cross-Platform)

With Flutter 3.27+, Material 3 is the default for new projects.

App Structure & Navigation

Widget Description Latest Updates
MaterialApp Top-level app container with Material theming M3+ support for dynamic color schemes
Scaffold Basic Material layout structure Improved scroll-under behavior fixed in 3.27
AppBar Application bar with toolbar and actions surfaceTintColor for elevation effect
NavigationBar Bottom navigation (replaces BottomNavigationBar) M3 replacement for BottomNavigationBar
NavigationRail Side navigation for large screens Ideal for tablets and desktop
Drawer Slide-out navigation panel Standard Material drawer
TabBar + TabBarView Tab navigation with content Connected tabs

Migration Note: BottomNavigationBar is deprecated in favor of NavigationBar for Material 3.

Material Action Widgets

Widget Description
ElevatedButton Raised button with elevation (preferred for M3)
FilledButton Solid background button (M3 primary action)
FilledButton.icon Replaces ElevatedButton.icon
TextButton Flat, text-only button
OutlinedButton Button with border, no fill
FloatingActionButton Circular action button—use .small or .large constructors
IconButton Icon as interactive button

Selection & Input

Widget Description M3 Status
Checkbox Boolean selection Use .adaptive() for cross-platform
Radio Single selection from group Standard M3 styling
Switch On/off toggle Use .adaptive()
Slider Value selection sliding M3 updated design
SegmentedButton Button group for selection Now supports vertical direction property
TextField Text input with decoration M3 styling
DropdownMenu Enhanced dropdown with search Improved focus handling in 3.27

Feedback & Dialogs

Widget Description
AlertDialog Interruptive confirmation dialog
SimpleDialog Simple options dialog
SnackBar Temporary bottom notification
BottomSheet Modal or persistent bottom sheet
Tooltip Help text on long press
ProgressIndicator Linear and circular progress

1.3 Cupertino Widgets (iOS Style)

Flutter 3.27 brought major Cupertino improvements to match iOS 15+ design.

Core iOS Widgets

Widget Description 3.27+ Updates
CupertinoApp iOS-style app root Standard
CupertinoPageScaffold Basic iOS page structure Standard
CupertinoTabScaffold Tabbed iOS app structure Standard
CupertinoNavigationBar iOS navigation bar Now has transparent background until scroll
CupertinoSliverNavigationBar Collapsible navigation bar Transparent background, smooth color transitions
CupertinoTabBar Bottom tab bar Standard

iOS Interaction Widgets

Widget Description 3.27+ Updates
CupertinoButton iOS-style button Now supports iOS 15+ styles: .filled, .tinted constructors
CupertinoTextField iOS-style text input Standard
CupertinoSwitch iOS toggle switch More configurable thumb images, fill colors
CupertinoSlider iOS-style slider Standard
CupertinoCheckbox iOS checkbox Refined sizes, colors, stroke widths
CupertinoRadio iOS radio button Updated press behaviors
CupertinoSlidingSegmentedControl iOS segmented picker Proportional layouts, disable individual segments
CupertinoPicker iOS scroll wheel picker Scroll directly to tapped items
CupertinoDatePicker Date/time picker Tapped item scrolling
CupertinoAlertDialog iOS alert dialog Tap-slide gesture support
CupertinoContextMenu 3D Touch-style menu Improvements in 3.27
CupertinoActivityIndicator Loading spinner Standard

1.4 Layout & Positioning Widgets

Single-Child Layout

Widget Description
Center Centers child within parent
Align Positions child using alignment
Padding Adds empty space around child
SizedBox Fixed size box (also used for spacing)
ConstrainedBox Applies min/max constraints
Expanded Fills available space in Row/Column
Flexible Can flex but not forced to expand
AspectRatio Maintains aspect ratio
FittedBox Scales child to fit
Transform Applies matrix transformations
Offstage Hides child without destroying state
Opacity Makes child partially transparent
ClipRect / ClipRRect / ClipOval / ClipPath Clips child with shapes

Multi-Child Layout

Widget Description
Row Horizontal arrangement
Column Vertical arrangement
Wrap Flows children to next line/column
Flow Custom multi-child layouts
Table Table layout algorithm
ListBody Sequential layout along axis

New in Flutter 3.27: Row and Column now have a spacing parameter for space between children.

1.5 Scrolling & Slivers

Widget Description
ListView Standard scrollable list
GridView Scrollable grid
SingleChildScrollView Single widget scroll
CustomScrollView Custom sliver composition
NestedScrollView Nested scrolling with floating app bars
Scrollbar Scroll position indicator
RefreshIndicator Pull-to-refresh gesture
NotificationListener Listen to scroll notifications

1.6 Text Widgets

Widget Description
Text Single-styled text
RichText Multiple text styles inline
SelectableText Text that can be copied
TextField Text input (also in input category)
DefaultTextStyle Inherited text style
TextSpan Inline text fragments for RichText

1.7 Images, Icons & Assets

Widget Description
Image Displays images (asset, network, file, memory)
Icon Material Design icon
CircleAvatar Circular image with fallback
FadeInImage Image with fade-in placeholder
RawImage Direct dart:ui image display

1.8 Async Widgets

Widget Description
FutureBuilder Builds UI based on Future state
StreamBuilder Builds UI based on Stream emissions

1.9 Animation Widgets

Widget Description
AnimatedContainer Animates container properties
AnimatedOpacity Fades widget in/out
AnimatedPadding Animates padding changes
AnimatedAlign Animates alignment
AnimatedPositioned Animates position in Stack
AnimatedCrossFade Fades between two children
Hero Shared element transitions
AnimatedBuilder Custom animation builder
AnimatedList Animated list insert/remove

1.10 Interaction & Gesture

Widget Description
GestureDetector Detects various gestures
InkWell Material ripple effect + gesture
Draggable / DragTarget Drag and drop
Dismissible Swipe-to-dismiss
LongPressDraggable Long press then drag
IgnorePointer Ignores touch input
AbsorbPointer Absorbs touch input

1.11 Styling & Theming

Widget Description
Theme Applies Material theme
MediaQuery Provides screen size/orientation
LayoutBuilder Builds based on parent constraints
OrientationBuilder Builds based on orientation

1.12 Accessibility

Widget Description
Semantics Describes widget meaning for screen readers
MergeSemantics Groups semantic nodes
ExcludeSemantics Removes from accessibility tree

1.13 Carousel & Advanced Layout

New in Flutter 3.27: CarouselView.weighted allows dynamic layouts with flex weights:

Constructor Description
CarouselView Standard carousel
CarouselView.weighted Custom relative item weights (multi-browse, hero, centered-hero layouts)

Part 2: Platform Channels & Native Integration

2.1 Core Concepts

Platform channels enable communication between Flutter and native platform code for features not available in Flutter packages.

Channel Types:

  • MethodChannel - Invoke methods and receive return values
  • EventChannel - Stream events from native to Flutter
  • BasicMessageChannel - Send raw messages

2.2 MethodChannel Implementation

Flutter (Dart) Side

import 'package:flutter/services.dart';

// Define channel with unique identifier
static const platform = MethodChannel('com.example.app/native');

// Call method and handle response
Future<String> getBatteryLevel() async {
  try {
    final String result = await platform.invokeMethod('getBatteryLevel');
    return result;
  } on PlatformException catch (e) {
    print("Failed: '${e.message}'");
    return "Unknown";
  }
}

// With parameters
Future<void> saveToGallery(Uint8List imageBytes) async {
  try {
    await platform.invokeMethod('saveImage', {'image': imageBytes});
  } on PlatformException catch (e) {
    print("Save failed: ${e.message}");
  }
}

Android (Kotlin) Side

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.app/native"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getBatteryLevel" -> getBatteryLevel(result)
                    "saveImage" -> saveImage(call.arguments, result)
                    else -> result.notImplemented()
                }
            }
    }

    private fun getBatteryLevel(result: MethodChannel.Result) {
        val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
        val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        
        if (batteryLevel != -1) {
            result.success(batteryLevel)
        } else {
            result.error("UNAVAILABLE", "Battery level not available", null)
        }
    }
    
    private fun saveImage(arguments: Any?, result: MethodChannel.Result) {
        val args = arguments as Map<String, Any>
        val bytes = args["image"] as ByteArray
        // Save implementation
        result.success(true)
    }
}

iOS (Swift) Side

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let controller = window?.rootViewController as! FlutterViewController
    let batteryChannel = FlutterMethodChannel(
      name: "com.example.app/native",
      binaryMessenger: controller.binaryMessenger
    )
    
    batteryChannel.setMethodCallHandler { (call, result) in
      switch call.method {
      case "getBatteryLevel":
        self.getBatteryLevel(result: result)
      case "saveImage":
        self.saveImage(call: call, result: result)
      default:
        result(FlutterMethodNotImplemented)
      }
    }
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  private func getBatteryLevel(result: FlutterResult) {
    let device = UIDevice.current
    device.isBatteryMonitoringEnabled = true
    let level = device.batteryLevel
    
    if level != -1.0 {
      result(Int(level * 100))
    } else {
      result(FlutterError(code: "UNAVAILABLE", message: "Battery level unavailable", details: nil))
    }
  }
  
  private func saveImage(call: FlutterMethodCall, result: FlutterResult) {
    guard let args = call.arguments as? [String: Any],
          let imageData = args["image"] as? FlutterStandardTypedData else {
      result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
      return
    }
    // Save implementation
    result(true)
  }
}

2.3 EventChannel (Streaming)

Flutter Side:

import 'package:flutter/services.dart';

class NativeSensorService {
  static const EventChannel _sensorChannel = EventChannel('com.example.app/sensors');
  
  Stream<double> get accelerometerStream {
    return _sensorChannel.receiveBroadcastStream()
        .map((event) => event['x'] as double);
  }
}

Android Side:

class MainActivity: FlutterActivity() {
    private var eventSink: EventChannel.EventSink? = null
    
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        EventChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.app/sensors")
            .setStreamHandler(object : EventChannel.StreamHandler {
                override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                    eventSink = events
                    startSensorListening()
                }
                
                override fun onCancel(arguments: Any?) {
                    stopSensorListening()
                    eventSink = null
                }
            })
    }
    
    private fun onSensorChanged(x: Float, y: Float, z: Float) {
        eventSink?.success(mapOf("x" to x, "y" to y, "z" to z))
    }
}

iOS Side:

class AppDelegate: FlutterAppDelegate {
    private var eventSink: FlutterEventSink?
    
    override func application(...) -> Bool {
        let controller = window?.rootViewController as! FlutterViewController
        let sensorChannel = FlutterEventChannel(
            name: "com.example.app/sensors",
            binaryMessenger: controller.binaryMessenger
        )
        
        sensorChannel.setStreamHandler(self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

extension AppDelegate: FlutterStreamHandler {
    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        self.eventSink = events
        startSensorUpdates()
        return nil
    }
    
    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        stopSensorUpdates()
        eventSink = nil
        return nil
    }
}

2.4 Best Practices

Error Handling:

// Always handle PlatformException
try {
  await platform.invokeMethod('method');
} on PlatformException catch (e) {
  switch (e.code) {
    case 'PERMISSION_DENIED':
      // Request permission
      break;
    case 'UNAVAILABLE':
      // Show fallback
      break;
    default:
      // Generic error
  }
}

Type Safety:

// Define method names as constants
class NativeMethods {
  static const String getBattery = 'getBatteryLevel';
  static const String saveImage = 'saveImage';
}

// Define argument keys
class NativeArgs {
  static const String image = 'image';
}

2.5 Common Use Cases for Platform Channels

Use Case Reason
Hardware sensors Camera, gyroscope, proximity
File system Advanced file operations
Biometric auth Face ID, fingerprint
Local notifications Rich notifications
Bluetooth BLE communication
NFC Payment, scanning
Platform-specific UI Native maps, video players
Battery/Network info System monitoring

Part 3: Widget Deprecations & Migrations (Flutter 3.27+)

Material Components Replacements

Deprecated Replacement
ElevatedButton.icon FilledButton.icon
TextButton.icon FilledButton.icon
OutlinedButton.icon Use standard OutlinedButton
BottomNavigationBar NavigationBar
Chip (generic) FilterChip, AssistChip, InputChip, ElevatedChip
FloatingActionButton (default) FloatingActionButton.large or .small
PopupMenuButton MenuAnchor (more flexible)

Theme Changes

Deprecated Replacement
ThemeData.dialogBackgroundColor DialogThemeData.backgroundColor
MaterialStateProperty<T> WidgetStateProperty<T>

Material 3 Migration Command

flutter create --platforms=android,ios --template=app my_app

Part 4: Quick Widget Selection Guide

Need Start Here
Simple container Container
List of items ListView.builder
Grid of items GridView.builder
Form with inputs Form + TextField
Two-pane layout Row with Expanded or NavigationRail
Modal overlay AlertDialog or showModalBottomSheet
Loading indicator CircularProgressIndicator.adaptive()
Page navigation Navigator + GoRouter
User toggle Switch.adaptive()
Multiple selection Checkbox or SegmentedButton

Complete Flutter Guidelines: Final Coverage

Part 1: Advanced Platform Channels & Native Interop

1.1 Platform Channel Architecture Overview

Platform channels enable communication between Flutter and native platform code. Understanding the architecture is crucial for effective implementation.

Channel Types:

  • MethodChannel: Invoke methods and receive return values (most common)
  • EventChannel: Stream events from native to Flutter
  • BasicMessageChannel: Send raw messages for custom protocols

Supported Platforms & Languages:

Platform Languages
Android Kotlin, Java
iOS Swift, Objective-C
macOS Objective-C
Windows C++
Linux C

1.2 Complete Platform Channel Implementation Patterns

Flutter Side (Dart) - Complete Pattern

import 'package:flutter/services.dart';
import 'dart:developer' as developer;

class NativeBatteryService {
  static const MethodChannel _channel = MethodChannel('com.example.app/battery');
  
  // Singleton pattern for channel services
  static final NativeBatteryService _instance = NativeBatteryService._internal();
  factory NativeBatteryService() => _instance;
  NativeBatteryService._internal();
  
  // Public API with proper error handling
  Future<int> getBatteryLevel() async {
    try {
      final int level = await _channel.invokeMethod('getBatteryLevel');
      return level;
    } on PlatformException catch (e) {
      developer.log(
        'Failed to get battery level',
        name: 'NativeBatteryService',
        level: 1000,
        error: e,
      );
      
      // Re-throw typed exceptions for caller handling
      switch (e.code) {
        case 'UNAVAILABLE':
          throw BatteryUnavailableException();
        case 'PERMISSION_DENIED':
          throw BatteryPermissionException();
        default:
          throw BatteryException(e.message ?? 'Unknown error');
      }
    }
  }
  
  // Method with parameters
  Future<bool> setPowerSavingMode(bool enabled) async {
    try {
      return await _channel.invokeMethod('setPowerSavingMode', {'enabled': enabled});
    } on PlatformException catch (e) {
      developer.log('Power saving mode failed', error: e);
      return false;
    }
  }
  
  // Streaming data from native
  Stream<double> getBatteryLevelStream() {
    const EventChannel eventChannel = EventChannel('com.example.app/battery_stream');
    return eventChannel.receiveBroadcastStream().map((event) => event as double);
  }
}

Android (Kotlin) - Complete Implementation

class MainActivity: FlutterActivity() {
    private val BATTERY_CHANNEL = "com.example.app/battery"
    private val BATTERY_STREAM_CHANNEL = "com.example.app/battery_stream"
    private var eventSink: EventChannel.EventSink? = null
    private var batteryLevelHandler: BatteryLevelHandler? = null
    
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        // Method Channel
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, BATTERY_CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getBatteryLevel" -> getBatteryLevel(result)
                    "setPowerSavingMode" -> setPowerSavingMode(call, result)
                    else -> result.notImplemented()
                }
            }
        
        // Event Channel for streaming
        EventChannel(flutterEngine.dartExecutor.binaryMessenger, BATTERY_STREAM_CHANNEL)
            .setStreamHandler(object : EventChannel.StreamHandler {
                override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                    eventSink = events
                    startBatteryMonitoring()
                }
                
                override fun onCancel(arguments: Any?) {
                    stopBatteryMonitoring()
                    eventSink = null
                }
            })
    }
    
    private fun getBatteryLevel(result: MethodChannel.Result) {
        val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
        val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        
        if (batteryLevel != -1) {
            result.success(batteryLevel)
        } else {
            result.error("UNAVAILABLE", "Battery level not available", null)
        }
    }
    
    private fun setPowerSavingMode(call: MethodCall, result: MethodChannel.Result) {
        val enabled = call.argument<Boolean>("enabled") ?: false
        // Implementation for power saving mode
        result.success(true)
    }
    
    private fun startBatteryMonitoring() {
        // Register battery level listener
        batteryLevelHandler = BatteryLevelHandler { level ->
            eventSink?.success(level)
        }
    }
    
    private fun stopBatteryMonitoring() {
        batteryLevelHandler?.unregister()
        batteryLevelHandler = null
    }
}

iOS (Swift) - Complete Implementation

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let BATTERY_CHANNEL = "com.example.app/battery"
    private let BATTERY_STREAM_CHANNEL = "com.example.app/battery_stream"
    private var eventSink: FlutterEventSink?
    
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller = window?.rootViewController as! FlutterViewController
        
        // Method Channel
        let batteryChannel = FlutterMethodChannel(
            name: BATTERY_CHANNEL,
            binaryMessenger: controller.binaryMessenger
        )
        
        batteryChannel.setMethodCallHandler { [weak self] call, result in
            switch call.method {
            case "getBatteryLevel":
                self?.getBatteryLevel(result: result)
            case "setPowerSavingMode":
                self?.setPowerSavingMode(call: call, result: result)
            default:
                result(FlutterMethodNotImplemented)
            }
        }
        
        // Event Channel
        let batteryEventChannel = FlutterEventChannel(
            name: BATTERY_STREAM_CHANNEL,
            binaryMessenger: controller.binaryMessenger
        )
        
        batteryEventChannel.setStreamHandler(self)
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    private func getBatteryLevel(result: FlutterResult) {
        let device = UIDevice.current
        device.isBatteryMonitoringEnabled = true
        let level = device.batteryLevel
        
        if level != -1.0 {
            result(Int(level * 100))
        } else {
            result(FlutterError(
                code: "UNAVAILABLE",
                message: "Battery level unavailable",
                details: nil
            ))
        }
    }
    
    private func setPowerSavingMode(call: FlutterMethodCall, result: FlutterResult) {
        guard let args = call.arguments as? [String: Any],
              let enabled = args["enabled"] as? Bool else {
            result(FlutterError(code: "INVALID_ARGS", message: nil, details: nil))
            return
        }
        // Implementation
        result(true)
    }
}

extension AppDelegate: FlutterStreamHandler {
    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        self.eventSink = events
        startBatteryMonitoring()
        return nil
    }
    
    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        stopBatteryMonitoring()
        eventSink = nil
        return nil
    }
}

1.3 Type-Safe Code Generation with Pigeon

For production apps, use the Pigeon package for type-safe platform channel code generation .

# pubspec.yaml
dev_dependencies:
  pigeon: ^22.0.0
// pigeon.dart (input file)
import 'package:pigeon/pigeon.dart';

@ConfigurePigeon(PigeonOptions(
  dartOut: 'lib/native_api.g.dart',
  kotlinOut: 'android/app/src/main/kotlin/com/example/NativeApi.g.kt',
  swiftOut: 'ios/Runner/NativeApi.g.swift',
))

@HostApi()
abstract class BatteryApi {
  int getBatteryLevel();
  
  @async
  Future<bool> setPowerSavingMode(bool enabled);
}

Run generation:

dart run pigeon --input pigeon.dart

1.4 Platform Channel Best Practices

DO's ✅

  • Use unique, reverse-domain channel names: com.yourcompany.appname/feature
  • Handle notImplemented case: Always call result.notImplemented() for unknown methods
  • Use async/await with try-catch: Wrap all invokeMethod calls
  • Keep native handlers thin: Parse arguments, call business logic, return results
  • Document method contracts: Specify argument types and return values
  • Use constants for method names: Avoid string literals scattered in code
  • Implement proper error handling: Return structured errors with codes

DON'Ts ❌

  • Don't block the main thread: Channel calls are synchronous on native side
  • Don't put business logic in channel handlers: Delegate to services
  • Don't ignore exceptions: Always handle PlatformException
  • Don't use channels for trivial operations: High-frequency calls can impact performance
  • Don't share channel names across features: Each feature should have its own channel

1.5 Common Platform Channel Use Cases

Use Case Why Platform Channel
Biometric Authentication Native Face ID/Touch ID APIs
Camera Customization Advanced camera features beyond camera plugin
File System Access Access to external storage, document pickers
Bluetooth/BLE Low-level Bluetooth control
NFC Payment, tag reading
Background Services Push notifications, background sync
Hardware Sensors Gyroscope, proximity, temperature
Platform-Specific UI Native maps, video players, WebView
Existing Native SDKs Payment SDKs, analytics, CRM integration

1.6 Testing Platform Channels

// Unit test with mocked MethodChannel
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  const MethodChannel batteryChannel = MethodChannel('com.example.app/battery');
  
  test('getBatteryLevel returns expected value', () async {
    // Setup mock response
    batteryChannel.setMockMethodCallHandler((call) async {
      if (call.method == 'getBatteryLevel') {
        return 75;
      }
      return null;
    });
    
    final service = NativeBatteryService();
    final level = await service.getBatteryLevel();
    
    expect(level, 75);
  });
  
  tearDown(() {
    batteryChannel.setMockMethodCallHandler(null);
  });
}

Part 2: Flutter 3.27+ Key Updates & Deprecations

2.1 Cupertino Widget Major Updates

Flutter 3.27 brought significant improvements to iOS-style widgets, bringing them closer to Apple's Human Interface Guidelines .

Widget Key Updates
CupertinoCheckbox New sizes, colors, stroke widths, press behaviors
CupertinoRadio Mouse cursors, semantic labels, fill colors
CupertinoSwitch Thumb images, fill colors, track color renamed
CupertinoSlidingSegmentedControl Thumb radius, separator height, proportional layout, disable individual segments
CupertinoNavigationBar Transparent background until scroll
CupertinoSliverNavigationBar Colors interpolate during scroll
CupertinoButton iOS 15+ styles via sizeStyle, .tinted constructor, onLongPress
CupertinoPicker/CupertinoDatePicker Scroll to tapped items
CupertinoAlertDialog Tap-slide gesture support
CupertinoActionSheet Proper padding/font sizes across text settings, haptic feedback
CupertinoContextMenu Scrollable when actions overflow
CupertinoMagnifier Zoom effect with magnification scale

2.2 Material 3 Deprecations & Replacements

With Material 3 as default, several widgets have been deprecated :

Deprecated Replacement Notes
ElevatedButton.icon FilledButton.icon M3 recommends FilledButton for primary actions
TextButton.icon FilledButton.icon Icon buttons now use FilledButton
OutlinedButton.icon OutlinedButton Icon constructor removed
BottomNavigationBar NavigationBar Complete redesign for M3
Chip (generic) FilterChip, AssistChip, InputChip, ElevatedChip More specific chip types
FloatingActionButton (default) .large or .small constructors Explicit size required
PopupMenuButton MenuAnchor More flexible menu control
MaterialStateProperty<T> WidgetStateProperty<T> Renamed for clarity
ThemeData.dialogBackgroundColor DialogThemeData.backgroundColor Organized under dialog theme
ChipThemeData (M2) ChipTheme (M3) New theming structure

2.3 New Features in Flutter 3.27

CarouselView.weighted: Dynamic carousel layouts with flex weights

CarouselView.weighted(
  flexWeights: [2, 1, 1, 2],  // Custom relative sizing
  children: [...],
)

Row/Column Spacing: Direct spacing parameter removes need for SizedBox between children

Row(
  spacing: 16,  // New in 3.27
  children: [...],
)

SegmentedButton Vertical Direction:

SegmentedButton(
  direction: Axis.vertical,  // New property
  segments: [...],
  selected: {...},
)

ModalRoute Transition Improvements: Exit transitions now sync with enter transitions for smoother navigation

Part 3: Testing Strategy & Best Practices

3.1 Testing Pyramid for Flutter

Test Type Proportion Description Execution Time
Unit Tests 70% Business logic, models, services Milliseconds
Widget Tests 20% Individual widget behavior Seconds
Integration Tests 10% Full user flows Minutes

3.2 Unit Testing with Mocktail

import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';

// Create mock
class MockUserRepository extends Mock implements UserRepository {}

void main() {
  late UserService service;
  late MockUserRepository mockRepository;
  
  setUp(() {
    mockRepository = MockUserRepository();
    service = UserService(mockRepository);
  });
  
  group('getUser', () {
    test('returns user when found', () async {
      // Arrange
      const userId = '123';
      final expectedUser = User(id: userId, name: 'Test');
      when(() => mockRepository.fetchUser(userId))
          .thenAnswer((_) async => expectedUser);
      
      // Act
      final result = await service.getUser(userId);
      
      // Assert
      expect(result, expectedUser);
      verify(() => mockRepository.fetchUser(userId)).called(1);
    });
    
    test('throws UserNotFound when user missing', () async {
      when(() => mockRepository.fetchUser(any()))
          .thenThrow(UserNotFoundException());
      
      expect(() => service.getUser('999'), throwsA(isA<UserNotFoundException>()));
    });
  });
}

3.3 Widget Testing with Golden Tests

import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Button matches golden file', (tester) async {
    await tester.pumpWidget(
      MaterialApp(
        theme: AppTheme.lightTheme,
        home: Scaffold(
          body: Center(
            child: MyCustomButton(label: 'Click Me'),
          ),
        ),
      ),
    );
    
    await expectLater(
      find.byType(MyCustomButton),
      matchesGoldenFile('goldens/my_button.png'),
    );
  });
}

3.4 Integration Testing

// integration_test/app_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  
  testWidgets('Complete login and navigation flow', (tester) async {
    app.main();
    await tester.pumpAndSettle();
    
    // Login
    await tester.enterText(find.byKey(const Key('email_field')), 'user@example.com');
    await tester.enterText(find.byKey(const Key('password_field')), 'password');
    await tester.tap(find.byKey(const Key('login_button')));
    await tester.pumpAndSettle(const Duration(seconds: 2));
    
    // Verify navigation to home
    expect(find.byType(HomeScreen), findsOneWidget);
    
    // Navigate to details
    await tester.tap(find.byKey(const Key('item_0')));
    await tester.pumpAndSettle();
    expect(find.byType(DetailScreen), findsOneWidget);
  });
}

Run integration tests:

flutter test integration_test

3.5 Test Coverage

Generate coverage report:

flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html

Minimum coverage targets:

  • Core business logic: 100%
  • Repositories/Services: 90%
  • BLoC/Providers: 85%
  • UI Widgets: 70%
  • Overall: 80%

Part 4: Accessibility (A11Y) Deep Dive

4.1 WCAG Compliance Requirements

Level Requirement Flutter Implementation
A (Minimum) Non-text content has text alternative Semantics(label: 'description')
A Keyboard navigable Focus and FocusNode widgets
AA Color contrast 4.5:1 Use ColorScheme with sufficient contrast
AA Text resize 200% Test with MediaQuery.textScaler
AA Focus visible FocusHighlight widget

4.2 Complete Accessibility Implementation

// Accessible custom card widget
class AccessibleCard extends StatelessWidget {
  final String title;
  final String description;
  final VoidCallback onTap;
  final String? imageUrl;
  
  const AccessibleCard({
    required this.title,
    required this.description,
    required this.onTap,
    this.imageUrl,
  });
  
  @override
  Widget build(BuildContext context) {
    return Semantics(
      label: '$title. $description',
      hint: 'Double tap to view details',
      button: true,
      enabled: true,
      onTap: onTap,
      child: FocusableActionDetector(
        onFocusChange: (hasFocus) {
          // Announce focus change for screen readers
          if (hasFocus) {
            SemanticsService.announce('$title card focused', Directionality.of(context));
          }
        },
        child: Material(
          color: Colors.transparent,
          child: InkWell(
            onTap: onTap,
            borderRadius: BorderRadius.circular(12),
            child: Container(
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.surfaceContainerHighest,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Row(
                children: [
                  if (imageUrl != null)
                    ExcludeSemantics(
                      child: Image.asset(
                        imageUrl!,
                        width: 50,
                        height: 50,
                        excludeFromSemantics: true,
                      ),
                    ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          title,
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        Text(
                          description,
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

4.3 Dynamic Font Scaling

class ScalableApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) {
        // Respect system font scale
        final mediaQuery = MediaQuery.of(context);
        final textScaler = mediaQuery.textScaler.clamp(
          minScale: 1.0,
          maxScale: 2.0,
        );
        
        return MediaQuery(
          data: mediaQuery.copyWith(textScaler: textScaler),
          child: child,
        );
      },
      home: const MyHomePage(),
    );
  }
}

4.4 Testing Accessibility

testWidgets('Accessibility labels are present', (tester) async {
  await tester.pumpWidget(const AccessibleCard(
    title: 'Test',
    description: 'Description',
    onTap: () {},
  ));
  
  final semantics = tester.getSemantics(find.byType(AccessibleCard));
  expect(semantics.label, 'Test. Description');
  expect(semantics.hasFlag(SemanticsFlag.isButton), true);
});

Part 5: State Management Advanced Patterns

5.1 Riverpod Code Generation (Recommended)

// providers/counter_provider.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'counter_provider.g.dart';

@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;
  
  void increment() => state++;
  void decrement() => state--;
}

@riverpod
class FilteredTodos extends _$FilteredTodos {
  @override
  List<Todo> build() {
    final todos = ref.watch(todoListProvider);
    final filter = ref.watch(todoFilterProvider);
    
    return switch (filter) {
      TodoFilter.completed => todos.where((t) => t.completed).toList(),
      TodoFilter.active => todos.where((t) => !t.completed).toList(),
      TodoFilter.all => todos,
    };
  }
}

// Usage in UI
class CounterWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);
    
    return Row(
      children: [
        IconButton(
          icon: const Icon(Icons.remove),
          onPressed: counterNotifier.decrement,
        ),
        Text('$count'),
        IconButton(
          icon: const Icon(Icons.add),
          onPressed: counterNotifier.increment,
        ),
      ],
    );
  }
}

5.2 BLoC Pattern (Alternative for Complex Apps)

// Event
abstract class LoginEvent {}
class LoginEmailChanged extends LoginEvent {
  final String email;
  LoginEmailChanged(this.email);
}
class LoginPasswordChanged extends LoginEvent {
  final String password;
  LoginPasswordChanged(this.password);
}
class LoginSubmitted extends LoginEvent {}

// State
abstract class LoginState {}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
  final User user;
  LoginSuccess(this.user);
}
class LoginFailure extends LoginState {
  final String error;
  LoginFailure(this.error);
}

// BLoC
class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final AuthRepository authRepository;
  
  LoginBloc(this.authRepository) : super(LoginInitial()) {
    on<LoginEmailChanged>((event, emit) {
      // Handle email change
    });
    
    on<LoginSubmitted>((event, emit) async {
      emit(LoginLoading());
      try {
        final user = await authRepository.login();
        emit(LoginSuccess(user));
      } catch (e) {
        emit(LoginFailure(e.toString()));
      }
    });
  }
}

Part 6: Internationalization (i18n) & Localization

6.1 ARB File Setup

# pubspec.yaml
flutter:
  generate: true  # Enable code generation

# l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
// lib/l10n/app_en.arb
{
  "appTitle": "My App",
  "welcomeMessage": "Welcome, {name}!",
  "@welcomeMessage": {
    "placeholders": {
      "name": {
        "type": "String"
      }
    }
  },
  "itemsCount": "{count, plural, =0{No items} one{1 item} other{{count} items}}"
}

6.2 Using Localizations

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final t = AppLocalizations.of(context)!;
    
    return Column(
      children: [
        Text(t.appTitle),
        Text(t.welcomeMessage('John')),
        Text(t.itemsCount(5)),
      ],
    );
  }
}

6.3 RTL Support

MaterialApp(
  locale: Locale('ar'),  // Arabic
  supportedLocales: const [
    Locale('en'),
    Locale('ar'),
  ],
  localizationsDelegates: AppLocalizations.localizationsDelegates,
  // Automatically handles RTL layout
);

Part 7: Production Checklist

Pre-Launch Checklist

Performance

  • No unnecessary rebuilds (check with PerformanceOverlay)
  • ListView.builder used for long lists
  • Images with proper caching (cached_network_image)
  • Animations use RepaintBoundary
  • No expensive operations in build() method
  • const constructors used where possible
  • App size optimized (remove unused assets)

Security

  • No hardcoded API keys or secrets
  • Sensitive data stored in secure storage
  • Network traffic encrypted (HTTPS)
  • Certificate pinning for critical APIs
  • Proguard/R8 enabled for Android (minifyEnabled)
  • iOS code obfuscation enabled
  • Input validation for all user inputs
  • Proper session management with refresh tokens

Accessibility

  • All interactive elements have semantic labels
  • Color contrast ratio ≥ 4.5:1
  • Dynamic type scaling supported
  • Focus navigation works on all platforms
  • Tested with TalkBack (Android) and VoiceOver (iOS)

Platform Integration

  • iOS:
    • App icons (all sizes)
    • Launch screen storyboard
    • Info.plist properly configured
    • Swift Package Manager dependencies set
  • Android:
    • Adaptive icons
    • Edge-to-edge display handling
    • Predictive back gesture (Android 14+)
    • Material You dynamic colors

Code Quality

  • flutter analyze passes with 0 warnings
  • dart format --output=none --set-exit-if-changed . passes
  • Test coverage ≥ 80%
  • No print() statements in production
  • Proper logging with developer.log or logger package
  • All async operations have error handling

Build & Deployment

  • Android:
    • Signing configuration for release builds
    • Proguard rules configured
    • Split APK by ABI
  • iOS:
    • Distribution certificate
    • Provisioning profile
    • App Store Connect metadata complete
  • Web:
    • PWA manifest configured
    • Service worker registered
    • SEO meta tags

Part 8: Official Documentation References

Primary Sources

Platform-Specific

Tools & Testing

Community & Updates


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment