Flutter气泡提示插件dash_bubble的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter气泡提示插件dash_bubble的使用

概览

Dash Bubble是一个Flutter插件,允许你在屏幕上创建一个浮动气泡。它基于Android的Floating-Bubble-View库构建。目前该插件仅支持Android平台,因为iOS不支持绘制在其他应用之上的功能。

Dash Bubble Banner

关键特性

  • 仅限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 回复

更多关于Flutter气泡提示插件dash_bubble的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用dash_bubble插件来实现气泡提示的一个示例。dash_bubble是一个用于显示浮动气泡提示的Flutter插件,非常适合用于引导用户或显示临时信息。

首先,确保你已经在pubspec.yaml文件中添加了dash_bubble依赖:

dependencies:
  flutter:
    sdk: flutter
  dash_bubble: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中创建一个示例页面,展示如何使用dash_bubble

import 'package:flutter/material.dart';
import 'package:dash_bubble/dash_bubble.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dash Bubble Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BubbleExampleScreen(),
    );
  }
}

class BubbleExampleScreen extends StatefulWidget {
  @override
  _BubbleExampleScreenState createState() => _BubbleExampleScreenState();
}

class _BubbleExampleScreenState extends State<BubbleExampleScreen> {
  late DashBubbleController _bubbleController;

  @override
  void initState() {
    super.initState();
    _bubbleController = DashBubbleController(
      bubbleConfig: BubbleConfig(
        color: Colors.blue.withOpacity(0.8),
        alignment: Alignment.topLeft,
        arrowSize: 10,
        arrowPosition: 50,
        margin: 16,
        padding: 16,
        borderRadius: 8,
        elevation: 4,
        textStyle: TextStyle(color: Colors.white, fontSize: 16),
      ),
    );

    // 显示气泡提示3秒后隐藏
    Future.delayed(Duration(seconds: 3), () {
      _bubbleController.showBubble(
        context: context,
        targetWidgetKey: GlobalKey(), // 目标小部件的key,这里我们省略了,因为没有指定目标
        message: '这是一个气泡提示!',
      );

      // 隐藏气泡提示,这里设置5秒后隐藏,可以根据需要调整
      Future.delayed(Duration(seconds: 5), () {
        _bubbleController.hideBubble();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dash Bubble Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '点击按钮将显示气泡提示(自动隐藏)',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                _bubbleController.showBubble(
                  context: context,
                  targetWidgetKey: GlobalKey(), // 目标小部件的key,这里我们省略了,因为没有指定目标
                  message: '你点击了按钮!',
                );

                // 隐藏气泡提示,这里设置3秒后隐藏,可以根据需要调整
                Future.delayed(Duration(seconds: 3), () {
                  _bubbleController.hideBubble();
                });
              },
              child: Text('显示气泡'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _bubbleController.dispose();
    super.dispose();
  }
}

解释

  1. 依赖导入:在pubspec.yaml中添加dash_bubble依赖。

  2. DashBubbleController:在_BubbleExampleScreenState中初始化DashBubbleController并配置气泡的样式。

  3. 显示和隐藏气泡:在initState中,我们使用Future.delayed来模拟在3秒后显示气泡,并在5秒后隐藏气泡。在实际使用中,你可能会根据用户的交互来显示和隐藏气泡。

  4. 按钮点击事件:在按钮点击事件中,调用_bubbleController.showBubble来显示气泡,并在3秒后调用_bubbleController.hideBubble来隐藏气泡。

  5. 资源释放:在dispose方法中调用_bubbleController.dispose来释放资源。

这个示例展示了如何使用dash_bubble插件来显示和隐藏气泡提示。你可以根据实际需要调整气泡的样式和显示逻辑。

回到顶部