flutter_native_overlay 0.0.1 copy "flutter_native_overlay: ^0.0.1" to clipboard
flutter_native_overlay: ^0.0.1 copied to clipboard

A Flutter plugin for displaying truly native system-level overlays on Android and iOS, with support for drag-to-dismiss, progress bars, avatars, and iOS Live Activities.

example/lib/main.dart

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

import 'package:flutter/services.dart';
import 'package:flutter_native_overlay/flutter_native_overlay.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _flutterNativeOverlayPlugin = FlutterNativeOverlay();
  bool _hasOverlayPermission = false;
  Map<String, double> _nativePadding = {};

  StreamSubscription<Map<String, dynamic>>? _overlayEventSubscription;

  @override
  void initState() {
    super.initState();
    _checkPermissions();
    _getNativePadding();

    _overlayEventSubscription = _flutterNativeOverlayPlugin.overlayEvents
        .listen((event) {
          debugPrint('Received overlay event: $event');
          // Using a global key or just print if scaffold isn't available easily
        });
  }

  @override
  void dispose() {
    _overlayEventSubscription?.cancel();
    super.dispose();
  }

  Future<void> _checkPermissions() async {
    bool hasPermission = false;
    try {
      hasPermission = await _flutterNativeOverlayPlugin
          .checkOverlayPermission();
    } on PlatformException {
      hasPermission = false;
    }
    if (!mounted) return;
    setState(() {
      _hasOverlayPermission = hasPermission;
    });
  }

  Future<void> _requestPermissions() async {
    await _flutterNativeOverlayPlugin.requestOverlayPermission();
    // After returning from settings, check again
    _checkPermissions();
  }

  Future<void> _getNativePadding() async {
    Map<String, double> padding = {};
    try {
      padding = await _flutterNativeOverlayPlugin.getNativePadding();
    } catch (e) {
      padding = {};
    }
    if (!mounted) return;
    setState(() {
      _nativePadding = padding;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        primaryColor: Colors.deepPurple,
        scaffoldBackgroundColor: const Color(0xFF121212),
      ),
      home: Builder(
        builder: (context) => Scaffold(
          appBar: AppBar(
            title: const Text('Native Overlay Demo'),
            backgroundColor: Colors.deepPurple,
            elevation: 0,
          ),
          body: SingleChildScrollView(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                _buildSectionHeader('Edge-to-Edge Native Padding'),
                _buildInfoCard(
                  'Top: ${_nativePadding['top']?.toStringAsFixed(1) ?? '0.0'}\n'
                  'Bottom: ${_nativePadding['bottom']?.toStringAsFixed(1) ?? '0.0'}\n'
                  'Left: ${_nativePadding['left']?.toStringAsFixed(1) ?? '0.0'}\n'
                  'Right: ${_nativePadding['right']?.toStringAsFixed(1) ?? '0.0'}',
                  Icons.padding,
                ),
                const SizedBox(height: 24),

                _buildSectionHeader('Android System Overlay'),
                _buildInfoCard(
                  'Permission: ${_hasOverlayPermission ? "Granted" : "Denied"}',
                  _hasOverlayPermission ? Icons.check_circle : Icons.error,
                  color: _hasOverlayPermission
                      ? Colors.green
                      : Colors.redAccent,
                ),
                const SizedBox(height: 16),
                if (!_hasOverlayPermission)
                  ElevatedButton.icon(
                    onPressed: _requestPermissions,
                    icon: const Icon(Icons.security),
                    label: const Text('Request Overlay Permission'),
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      backgroundColor: Colors.deepPurpleAccent,
                    ),
                  ),
                if (_hasOverlayPermission) ...[
                  Row(
                    children: [
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () {
                            _flutterNativeOverlayPlugin.showOverlay(
                              title: 'Phone',
                              isDraggable: true,
                              style: const NativeOverlayStyle(
                                container: NativeContainerStyle(
                                  backgroundColor: Colors.deepPurple,
                                  shape: OverlayShape.circle,
                                  height: 70,
                                  width: 70,
                                  padding: NativeEdgeInsets.symmetric(
                                    horizontal: 12,
                                    vertical: 8,
                                  ),
                                ),
                                content: NativeContentStyle(
                                  titleFontSize: 12,
                                  titleColor: Colors.white,
                                ),
                                button: NativeButtonStyle(
                                  text: 'Acknowledge',
                                  backgroundColor: Colors.tealAccent,
                                  textColor: Colors.black,
                                ),
                              ),
                            );
                          },
                          icon: const Icon(Icons.visibility),
                          label: const Text('Show Overlay'),
                          style: ElevatedButton.styleFrom(
                            padding: const EdgeInsets.symmetric(vertical: 16),
                            backgroundColor: Colors.green,
                          ),
                        ),
                      ),
                      const SizedBox(width: 12),
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () {
                            _flutterNativeOverlayPlugin.showOverlay(
                              title: 'Auto Dismissing',
                              content: 'This will disappear in 3 seconds',
                              duration: const Duration(seconds: 3),
                              style: NativeOverlayStyle(
                                container: const NativeContainerStyle(
                                  backgroundColor: Colors.blueGrey,
                                  borderRadius: 12,
                                ),
                                progress: NativeProgressStyle(
                                  color: Colors.orangeAccent.withValues(
                                    alpha: 0.8,
                                  ),
                                  height: 4,
                                ),
                              ),
                            );
                          },
                          icon: const Icon(Icons.timer),
                          label: const Text('Auto Dismiss'),
                          style: ElevatedButton.styleFrom(
                            padding: const EdgeInsets.symmetric(vertical: 16),
                            backgroundColor: Colors.blueGrey[800],
                            foregroundColor: Colors.white,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                  Row(
                    children: [
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () {
                            _flutterNativeOverlayPlugin.showOverlay(
                              title: '99+',
                              isDraggable: true,
                              duration: const Duration(seconds: 5),
                              style: NativeOverlayStyle(
                                container: const NativeContainerStyle(
                                  backgroundColor: Colors.redAccent,
                                  shape: OverlayShape.circle,
                                  width: 70,
                                  height: 70,
                                ),
                                content: const NativeContentStyle(
                                  titleColor: Colors.white,
                                  titleFontSize: 20,
                                ),
                                progress: const NativeProgressStyle(
                                  color: Colors.white,
                                  height: 8,
                                ),
                              ),
                            );
                          },
                          icon: const Icon(Icons.radio_button_checked),
                          label: const Text('Circular Timer'),
                          style: ElevatedButton.styleFrom(
                            padding: const EdgeInsets.symmetric(vertical: 16),
                            backgroundColor: Colors.red[900],
                            foregroundColor: Colors.white,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                  Row(
                    children: [
                      Expanded(
                        child: ElevatedButton.icon(
                          onPressed: () async {
                            final ByteData data = await rootBundle.load(
                              'assets/avatar.png',
                            );
                            final Uint8List bytes = data.buffer.asUint8List();

                            _flutterNativeOverlayPlugin.showOverlay(
                              title: 'Incoming Call',
                              content: 'John Doe is calling...',
                              avatarBytes: bytes,
                              isDraggable: true,
                              style: const NativeOverlayStyle(
                                container: NativeContainerStyle(
                                  backgroundColor: Color(0xFF1E1E1E),
                                  borderRadius: 24.0,
                                ),
                                avatar: NativeAvatarStyle(
                                  size: 56.0,
                                  borderRadius: 28.0,
                                ),
                                button: NativeButtonStyle(
                                  showButton: true,
                                  text: 'Decline',
                                  backgroundColor: Colors.redAccent,
                                ),
                              ),
                            );
                          },
                          icon: const Icon(Icons.person),
                          label: const Text('Avatar Overlay'),
                          style: ElevatedButton.styleFrom(
                            padding: const EdgeInsets.symmetric(vertical: 16),
                            backgroundColor: Colors.blueAccent,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                  ElevatedButton.icon(
                    onPressed: () => _flutterNativeOverlayPlugin.hideOverlay(),
                    icon: const Icon(Icons.visibility_off),
                    label: const Text('Hide Overlay'),
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      backgroundColor: Colors.redAccent,
                    ),
                  ),
                  const SizedBox(height: 12),
                  ElevatedButton.icon(
                    onPressed: () async {
                      _flutterNativeOverlayPlugin.showCustom(
                        context: context,
                        widget: Container(
                          width: 80,
                          height: 80,
                          decoration: const BoxDecoration(
                            shape: BoxShape.circle,
                            gradient: LinearGradient(
                              colors: [Colors.deepPurple, Colors.tealAccent],
                              begin: Alignment.topLeft,
                              end: Alignment.bottomRight,
                            ),
                          ),
                          child: const Icon(
                            Icons.phone,
                            color: Colors.white,
                            size: 36,
                          ),
                        ),
                        style: const NativeOverlayStyle(
                          container: NativeContainerStyle(
                            shape: OverlayShape.circle,
                            width: 80,
                            height: 80,
                          ),
                        ),
                      );
                    },
                    icon: const Icon(Icons.bubble_chart),
                    label: const Text('Show Widget as Circle Overlay'),
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      backgroundColor: Colors.deepPurpleAccent,
                    ),
                  ),
                ],

                const SizedBox(height: 32),
                _buildSectionHeader('iOS Live Activity / Dynamic Island'),
                ElevatedButton.icon(
                  onPressed: () {
                    _flutterNativeOverlayPlugin.startLiveActivity(
                      title: 'Delivery Status',
                      content: 'Arriving in 5 mins',
                    );
                  },
                  icon: const Icon(Icons.apple),
                  label: const Text('Start Live Activity'),
                  style: ElevatedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    backgroundColor: Colors.blueAccent,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildSectionHeader(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12.0),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 18,
          fontWeight: FontWeight.bold,
          color: Colors.white70,
        ),
      ),
    );
  }

  Widget _buildInfoCard(String text, IconData icon, {Color? color}) {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF1E1E1E),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.white10),
      ),
      child: Row(
        children: [
          Icon(icon, size: 32, color: color ?? Colors.deepPurpleAccent),
          const SizedBox(width: 16),
          Expanded(
            child: Text(
              text,
              style: const TextStyle(fontSize: 16, height: 1.5),
            ),
          ),
        ],
      ),
    );
  }
}
2
likes
150
points
70
downloads
screenshot

Documentation

API reference

Publisher

verified publisherbasharatmehdi.in

Weekly Downloads

A Flutter plugin for displaying truly native system-level overlays on Android and iOS, with support for drag-to-dismiss, progress bars, avatars, and iOS Live Activities.

Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_native_overlay

Packages that implement flutter_native_overlay