Flutter Custom Overlay

A Flutter plugin that enables Android apps to display customizable overlays with bidirectional data communication. Create rich overlay interfaces using Flutter widgets with full control over position, size, and behavior.

Features

Custom Flutter Overlay UI - Create any Flutter widget tree for your overlay interface
🔄 Bidirectional Data Communication - Share data between main app and overlay seamlessly
📍 Dynamic Position & Size Control - Adjust overlay properties on the fly
👆 Draggable Overlays - Enable touch-based dragging
⚙️ Flexible Configuration - Control focusability, click-through behavior, and more
🔐 Permission Management - Built-in helpers for overlay permissions

Platform Support

Platform Supported
Android ✅ API 23+
iOS
Web
Windows
macOS
Linux

Installation

Add this to your pubspec.yaml:

dependencies:
  flutter_custom_overlay: ^0.2.0

Android Setup

1. Permissions

The plugin automatically adds required permissions to your app. Ensure your AndroidManifest.xml includes:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

2. Minimum SDK

Set your minimum SDK to API 23 (Android 6.0) or higher in android/app/build.gradle:

android {
    defaultConfig {
        minSdkVersion 23
    }
}

Usage

1. Check and Request Overlay Permission

import 'package:flutter_custom_overlay/flutter_custom_overlay.dart';

// Check if permission is granted
bool hasPermission = await FlutterCustomOverlay.hasOverlayPermission();

if (!hasPermission) {
  // Request permission (opens system settings)
  await FlutterCustomOverlay.requestOverlayPermission();
}

2. Create Overlay Entry Point

Define a top-level or static function that will run in the overlay:

@pragma('vm:entry-point')
void overlayMain() {
  runApp(const MyOverlayApp());
}

class MyOverlayApp extends StatelessWidget {
  const MyOverlayApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.transparent,
        body: Container(
          decoration: BoxDecoration(
            color: Colors.blue,
            borderRadius: BorderRadius.circular(16),
          ),
          child: Center(
            child: Text(
              'Hello from Overlay!',
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ),
    );
  }
}

3. Show the Overlay

// Configure overlay properties
final config = OverlayConfig(
  width: 300,
  height: 200,
  x: 0,
  y: 100,
  isDraggable: true,
  isClickThrough: false,
  alignment: OverlayAlignment.topLeft,
  isFocusable: false, // Optional: Enable text input
);

// Show overlay
bool success = await FlutterCustomOverlay.showOverlay(
  config: config,
  data: {'message': 'Hello from main!'}, // Optional: Send initial data
);

4. Update Overlay Position and Size

// Update position
await FlutterCustomOverlay.updatePosition(x: 100, y: 200);

// Update size
await FlutterCustomOverlay.updateSize(width: 400, height: 300);

5. Share Data Between App and Overlay

Send data from main app to overlay:

// 1. Send during showOverlay (Initial Data)
await FlutterCustomOverlay.showOverlay(
  config: config,
  data: {'key': 'Initial Value'},
);

// 2. Send anytime (Runtime Data)
await FlutterCustomOverlay.shareData({
  'message': 'Runtime update!',
});

Receive data from overlay in main app:

FlutterCustomOverlay.overlayStream.listen((data) {
  print('Received from overlay: ${data.data}');
});

6. Hide the Overlay

Option A: Hide (Keep State)
Hides the window but keeps the Flutter engine running. Ideal for temporary hiding.

await FlutterCustomOverlay.hideOverlay();

Option B: Hide & Reset
Hides the window and destroys the engine. Next showOverlay starts fresh.

await FlutterCustomOverlay.hideAndRestartOverlay();

7. Check Overlay Status

// Check if service is running
bool isActive = await FlutterCustomOverlay.isOverlayActive();

// Check if window is currently visible onscreen
bool isVisible = await FlutterCustomOverlay.isOverlayVisible();

Configuration Options

OverlayConfig

Property Type Default Description
width int 300 Width in pixels
height int 200 Height in pixels
x int 0 X position (offset from alignment)
y int 100 Y position (offset from alignment)
isDraggable bool true Enable drag to move
isClickThrough bool false Allow touches to pass through
alignment OverlayAlignment .topLeft Anchor position
isFocusable bool false Can receive focus

Alignment Options (OverlayAlignment)

  • topLeft, topCenter, topRight
  • centerLeft, center, centerRight
  • bottomLeft, bottomCenter, bottomRight

Complete Example

See the example directory for a complete working application demonstrating all features.

How It Works

The plugin creates a foreground service that runs a separate Flutter engine instance for the overlay. This allows:

  1. Independent UI: The overlay has its own widget tree separate from the main app
  2. Persistent Display: Overlay remains visible even when the main app is minimized
  3. Full Flutter Features: Use any Flutter widgets, animations, and state management
  4. Bidirectional Communication: Method channels enable data flow in both directions

Limitations

  • Android Only: Currently only supports Android platform
  • API 23+: Requires Android 6.0 (Marshmallow) or higher
  • Permission Required: User must grant SYSTEM_ALERT_WINDOW permission
  • Resource Usage: Running two Flutter engines consumes more memory

Troubleshooting

Overlay doesn't appear

  • Verify overlay permission is granted
  • Check Android version is API 23+
  • Ensure entry point function is marked with @pragma('vm:entry-point')

Permission request doesn't work

  • Make sure permissions are declared in AndroidManifest.xml
  • Some OEMs have additional permission restrictions

Data not received in overlay

  • Ensure you're listening to the appropriate channel
  • Check that data is properly serialized (must be JSON-compatible)

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

License

MIT License - see LICENSE file for details

Author

Created with ❤️ for the Flutter community