debug_panel 0.1.0
debug_panel: ^0.1.0 copied to clipboard
A reusable draggable floating ball with edge-snap spring animation, badge slots, boundary clamping and debug-only mode. Great for debug bubbles and floating menus.
import 'package:debug_panel/debug_panel.dart';
import 'package:flutter/material.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
bool _paused = false;
final int _cacheCount = 3;
int _failedCount = 0;
@override
Widget build(BuildContext context) {
final media = MediaQuery.of(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
// 用 Builder 取得 MaterialApp 之下的 context(供 onTap 弹 SnackBar 用)
home: Builder(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text('debug_panel example')),
body: Stack(
children: [
Positioned.fill(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Wrap(
spacing: 8,
children: [
FilledButton(
onPressed: () => setState(() => _paused = !_paused),
child: Text(_paused ? '恢复采集' : '暂停采集'),
),
FilledButton.tonal(
onPressed: () => setState(() => _failedCount++),
child: const Text('产生失败'),
),
OutlinedButton(
onPressed: () => setState(() => _failedCount = 0),
child: const Text('清除角标'),
),
],
),
const SizedBox(height: 16),
const Text('拖动浮球试试,松手会吸附到左右边缘'),
],
),
),
),
// 可拖动吸附浮球(直接作为 Stack 子节点)
DebugFloatBall(
paused: _paused,
// 右上角标:失败红点
topRightBadge: _failedCount > 0
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 5, vertical: 1),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.white, width: 1.5),
),
child: Text(
_failedCount > 99 ? '99+' : '$_failedCount',
style: const TextStyle(
fontSize: 9,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
)
: null,
// 左下角标:暂停 ⏸
bottomLeftBadge: _paused
? Container(
width: 18,
height: 18,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 1.5),
),
child: const Icon(
Icons.pause,
size: 11,
color: Colors.white,
),
)
: null,
// 垂直边界:限制在导航栏下、tabbar 上
topBoundary: media.padding.top + kToolbarHeight,
bottomBoundary: media.size.height -
media.padding.bottom -
kBottomNavigationBarHeight,
// 行为
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('浮球被点击'),
duration: Duration(milliseconds: 800),
),
);
},
onDoubleTap: () => setState(() => _paused = !_paused),
onLongPress: () => setState(() => _failedCount = 0),
// 球心内容
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('📊', style: TextStyle(fontSize: 16)),
if (_cacheCount > 0)
Text(
'$_cacheCount',
style: const TextStyle(
fontSize: 10,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
),
);
}
}