flutter_custom_overlay 0.2.0
flutter_custom_overlay: ^0.2.0 copied to clipboard
A Flutter plugin for creating customizable overlay windows on Android with bidirectional data communication and dynamic control.
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:
path: ../flutter_custom_overlay # Update with actual path or pub.dev reference
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,topRightcenterLeft,center,centerRightbottomLeft,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:
- Independent UI: The overlay has its own widget tree separate from the main app
- Persistent Display: Overlay remains visible even when the main app is minimized
- Full Flutter Features: Use any Flutter widgets, animations, and state management
- 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_WINDOWpermission - 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