Flutter气泡提示插件dash_bubble的使用
Flutter气泡提示插件dash_bubble的使用
概览
Dash Bubble是一个Flutter插件,允许你在屏幕上创建一个浮动气泡。它基于Android的Floating-Bubble-View库构建。目前该插件仅支持Android平台,因为iOS不支持绘制在其他应用之上的功能。
关键特性
- 仅限Android:由于权限和API限制,此插件只适用于Android。
- 自定义选项:可以自定义气泡的图标、位置、大小等。
- 回调函数:提供多种交互事件的回调函数,如点击、拖动等。
- 服务通知:启动气泡时会显示不可关闭的通知以保持服务运行。
设置与配置
项目配置
确保android/app/build.gradle
文件中的最小SDK版本设置为21或更高:
android {
defaultConfig {
...
minSdkVersion 21 // Set this to 21 or higher
...
}
}
权限声明
虽然插件会自动添加以下权限到AndroidManifest.xml
中,但了解这些权限是必要的:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
使用方法
导入包
首先需要导入dash_bubble包:
import 'package:dash_bubble/dash_bubble.dart';
单例调用
通过单例模式访问DashBubble的所有方法:
DashBubble.instance.requestOverlayPermission(); // 请求覆盖权限
DashBubble.instance.startBubble(); // 启动气泡
更多API参考请参见官方文档。
完整示例代码
下面是一个完整的Dart代码示例,展示了如何使用dash_bubble插件来创建并控制浮动气泡:
import 'dart:developer';
import 'package:dash_bubble/dash_bubble.dart';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Dash Bubble Playground',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSwatch().copyWith(
background: const Color(0xFF04599c),
),
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
titleTextStyle: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
backgroundColor: Colors.white,
foregroundColor: const Color(0xFF04599c),
minimumSize: const Size.fromHeight(50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({
super.key,
});
Future<void> _runMethod(
BuildContext context,
Future<void> Function() method,
) async {
try {
await method();
} catch (error) {
log(
name: 'Dash Bubble Playground',
error.toString(),
);
SnackBars.show(
context: context,
status: SnackBarStatus.error,
message: 'Error: ${error.runtimeType}',
);
}
}
Future<void> _requestOverlayPermission(BuildContext context) async {
await _runMethod(
context,
() async {
final isGranted = await DashBubble.instance.requestOverlayPermission();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: isGranted
? 'Overlay Permission Granted'
: 'Overlay Permission is not Granted',
);
},
);
}
Future<void> _hasOverlayPermission(BuildContext context) async {
await _runMethod(
context,
() async {
final hasPermission = await DashBubble.instance.hasOverlayPermission();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: hasPermission
? 'Overlay Permission Granted'
: 'Overlay Permission is not Granted',
);
},
);
}
Future<void> _requestPostNotificationsPermission(
BuildContext context,
) async {
await _runMethod(
context,
() async {
final isGranted =
await DashBubble.instance.requestPostNotificationsPermission();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: isGranted
? 'Post Notifications Permission Granted'
: 'Post Notifications Permission is not Granted',
);
},
);
}
Future<void> _hasPostNotificationsPermission(BuildContext context) async {
await _runMethod(
context,
() async {
final hasPermission =
await DashBubble.instance.hasPostNotificationsPermission();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: hasPermission
? 'Post Notifications Permission Granted'
: 'Post Notifications Permission is not Granted',
);
},
);
}
Future<void> _isRunning(BuildContext context) async {
await _runMethod(
context,
() async {
final isRunning = await DashBubble.instance.isRunning();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: isRunning ? 'Bubble is Running' : 'Bubble is not Running',
);
},
);
}
Future<void> _startBubble(
BuildContext context, {
BubbleOptions? bubbleOptions,
NotificationOptions? notificationOptions,
VoidCallback? onTap,
Function(double x, double y)? onTapDown,
Function(double x, double y)? onTapUp,
Function(double x, double y)? onMove,
}) async {
await _runMethod(
context,
() async {
final hasStarted = await DashBubble.instance.startBubble(
bubbleOptions: bubbleOptions,
notificationOptions: notificationOptions,
onTap: onTap,
onTapDown: onTapDown,
onTapUp: onTapUp,
onMove: onMove,
);
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: hasStarted ? 'Bubble Started' : 'Bubble has not Started',
);
},
);
}
Future<void> _stopBubble(BuildContext context) async {
await _runMethod(
context,
() async {
final hasStopped = await DashBubble.instance.stopBubble();
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: hasStopped ? 'Bubble Stopped' : 'Bubble has not Stopped',
);
},
);
}
void _logMessage({required BuildContext context, required String message}) {
log(name: 'DashBubblePlayground', message);
SnackBars.show(
context: context,
status: SnackBarStatus.success,
message: message,
);
}
String _getRoundedCoordinatesAsString(double x, double y) {
return '${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)}';
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dash Bubble Playground'),
),
body: Padding(
padding: const EdgeInsets.all(24),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () => _requestOverlayPermission(context),
child: const Text('Request Overlay Permission'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => _hasOverlayPermission(context),
child: const Text('Has Overlay Permission?'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => _requestPostNotificationsPermission(context),
child: const Text('Request Post Notifications Permission'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => _hasPostNotificationsPermission(context),
child: const Text('Has Post Notifications Permission?'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => _isRunning(context),
child: const Text('Is Running?'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
_startBubble(
context,
bubbleOptions: BubbleOptions(
bubbleIcon: 'github_bubble',
startLocationX: 0,
startLocationY: 100,
bubbleSize: 60,
opacity: 1,
enableClose: true,
closeBehavior: CloseBehavior.following,
distanceToClose: 100,
enableAnimateToEdge: true,
enableBottomShadow: true,
keepAliveWhenAppExit: false,
),
notificationOptions: NotificationOptions(
id: 1,
title: 'Dash Bubble Playground',
body: 'Dash Bubble service is running',
channelId: 'dash_bubble_notification',
channelName: 'Dash Bubble Notification',
),
onTap: () => _logMessage(
context: context,
message: 'Bubble Tapped',
),
onTapDown: (x, y) => _logMessage(
context: context,
message:
'Bubble Tapped Down on: ${_getRoundedCoordinatesAsString(x, y)}',
),
onTapUp: (x, y) => _logMessage(
context: context,
message:
'Bubble Tapped Up on: ${_getRoundedCoordinatesAsString(x, y)}',
),
onMove: (x, y) => _logMessage(
context: context,
message:
'Bubble Moved to: ${_getRoundedCoordinatesAsString(x, y)}',
),
);
},
child: const Text('Start Bubble'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => _stopBubble(context),
child: const Text('Stop Bubble'),
),
],
),
),
),
);
}
}
这个例子展示了如何请求必要的权限、检查权限状态、启动和停止气泡,并处理各种用户交互事件。希望这能帮助你更好地理解和使用dash_bubble插件!
更多关于Flutter气泡提示插件dash_bubble的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复