assistive_touch_overlay
Assistive Touch-style draggable floating bubble overlay for Flutter (snap-to-edge + optional pulse), plus an optional Dio API inspector with a dark-theme UI. Co-authored and inspired by Safal Shrestha.
AssistiveTouchOverlay— reusable draggable bubble primitive (no Dio dependency)- API inspector —
ApiInspectorService+ApiInspectorInterceptor+ApiInspectorController+ApiInspectorOverlay
Automatically disabled in release mode — zero overhead in production builds.
Preview
Install
dependencies:
assistive_touch_overlay: ^0.0.5
API Inspector (Dio)
1. Create the service and controller
import 'package:assistive_touch_overlay/api_inspector.dart';
import 'package:flutter/material.dart';
final _navigatorKey = GlobalKey<NavigatorState>();
final _inspectorService = ApiInspectorService();
final _inspectorController = ApiInspectorController(
service: _inspectorService,
navigatorKey: _navigatorKey, // required when overlay is inside MaterialApp.builder
overlayVisible: true,
);
2. Add the interceptor to Dio
import 'package:dio/dio.dart';
import 'package:assistive_touch_overlay/api_inspector.dart';
final dio = Dio()
..interceptors.add(ApiInspectorInterceptor(_inspectorService));
3. Render the overlay above your app
Pass navigatorKey to both MaterialApp and ApiInspectorController. The overlay is placed inside MaterialApp.builder, whose context sits above the Navigator — without the key the inspector cannot push routes.
import 'package:assistive_touch_overlay/api_inspector.dart';
import 'package:flutter/material.dart';
MaterialApp(
navigatorKey: _navigatorKey,
builder: (context, child) {
return Stack(
children: [
child ?? const SizedBox.shrink(),
ApiInspectorOverlay(controller: _inspectorController),
],
);
},
)
How it works
- Tap the floating bubble to start capture — it pulses red and shows a countdown + request count.
- Make your API calls normally.
- When the capture window ends (default 20 s) or you tap again to stop, the inspector automatically opens the captured call list.
- Tap any row to see full request/response detail, headers, body, cURL command, and stack trace.
- Tap the bubble again from the done state to re-open the list.
Bubble states
| State | Appearance |
|---|---|
| Idle | Dark bubble with wifi icon |
| Recording | Red pulsing bubble — seconds left + request count |
| Done (no errors) | Green bubble — checkmark + total count |
| Done (client errors) | Orange bubble — error count / total |
| Done (server errors) | Red bubble — error count / total |
ApiInspectorController options
| Parameter | Default | Description |
|---|---|---|
service |
new instance | Shared ApiInspectorService store |
navigatorKey |
null |
Required when overlay is in MaterialApp.builder |
recordingDurationSeconds |
20 |
How long a capture session lasts |
overlayVisible |
false |
Whether the bubble starts visible |
initialPosition |
Offset(-20, 200) |
Starting position of the bubble |
Release mode
ApiInspectorOverlay returns an empty widget and ApiInspectorInterceptor becomes a transparent pass-through when kReleaseMode is true. No recording, no UI, no overhead — safe to leave wired up for production.
AssistiveTouchOverlay (standalone)
AssistiveTouchOverlay must be placed under a Stack (it uses AnimatedPositioned internally).
import 'package:assistive_touch_overlay/assistive_touch_overlay.dart';
import 'package:flutter/material.dart';
Stack(
children: [
const MyScreen(),
AssistiveTouchOverlay(
isPulsing: true,
onTap: () => debugPrint('tapped'),
builder: (context, pulseAnimation) {
return ScaleTransition(
scale: pulseAnimation,
child: const MyBubbleWidget(),
);
},
),
],
)
AssistiveTouchOverlay options
| Parameter | Default | Description |
|---|---|---|
builder |
required | Builds the bubble content; receives the pulse animation |
onTap |
null |
Called on tap (not drag) |
bubbleSize |
60.0 |
Bubble diameter in logical pixels |
edgePadding |
-20.0 |
Snap/clamp padding — negative = flush against edge (iOS-style) |
initialPosition |
Offset(edgePadding, 200) |
Starting position |
isPulsing |
false |
Starts/stops the scale pulse animation |
snapDuration |
300ms |
Duration of the snap-to-edge animation |
snapCurve |
easeOutCubic |
Curve for the snap-to-edge animation |
pulseDuration |
900ms |
Duration of one pulse cycle |
pulseBegin / pulseEnd |
1.0 / 1.15 |
Scale range of the pulse |
Example app
cd example
flutter pub get
flutter run
Notes
- All storage is in-memory — records are cleared when capture restarts or
reset()is called. - Stack traces are captured only when Dio provides them on
DioException. - The package requires Dart
>=3.1.0anddio ^5.9.2.
Credits
A huge thank you to Safal Shrestha for his invaluable guidance, inspiration, and co-authoring contributions that helped bring this library to life!
Libraries
- api_inspector
- Dio API Inspector overlay library for Flutter. Co-authored and inspired by Safal Shrestha.
- assistive_touch_overlay
- Assistive Touch Overlay library for Flutter. Co-authored and inspired by Safal Shrestha.