Flutter自定义指向弹出框插件custom_pointed_popup的使用

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

Flutter自定义指向弹出框插件custom_pointed_popup的使用

简介

custom_pointed_popup 是一个Flutter插件,允许你在任何目标小部件上显示带有自定义指针设计的弹出框。这个插件提供了丰富的自定义选项,包括背景颜色、指针方向、边框半径等。

截图

以下是该插件的效果图: alt text alt text alt text alt text

使用示例

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 custom_pointed_popup 依赖:

dependencies:
  custom_pointed_popup: ^最新版本号

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

2. 完整示例代码

以下是一个完整的示例代码,展示了如何使用 custom_pointed_popup 插件:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  [@override](/user/override)
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final GlobalKey widgetKey = GlobalKey();

  CustomPointedPopup getCustomPointedPopup(BuildContext context) {
    return CustomPointedPopup(
      backgroundColor: Colors.red, // 弹出框的背景颜色
      context: context, // 当前上下文
      widthFractionWithRespectToDeviceWidth: 3, // 弹出框宽度相对于设备宽度的比例
      triangleDirection: TriangleDirection.FullLeft, // 指针方向
      popupElevation: 10, // 弹出框的阴影高度
      displayBelowWidget: true, // 是否显示在目标小部件下方
      customHeight: 150, // 弹出框的高度

      /// 你可以添加边框半径
      // popupBorderRadius: BorderRadius.circular(10),

      item: CustomPointedPopupItem(
        title: 'Popup that can be shown on any targeted widget with customized pointed design.', // 弹出框的标题
        textStyle: Theme.of(context).textTheme.caption!.copyWith(
              color: Theme.of(context).cardColor, // 标题文本样式
            ),
        iconWidget: Icon(
          Icons.add_moderator, // 弹出框中的图标
          color: Theme.of(context).cardColor,
        ),

        /// 或者你可以添加自定义的小部件代替上面的三个属性
        // itemWidget: Container(
        //   child: Center(
        //     child: Text('Custom item'),
        //   ),
        // ),
      ),
      onClickWidget: (onClickMenu) {
        print('popup item clicked'); // 点击弹出框时的回调
      },
      onDismiss: () {
        print('on dismissed called'); // 弹出框关闭时的回调
      },
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Custom Pointed Popup [CPP]',
        ),
      ),
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'CPP with straight pointer & item.',
                style: TextStyle(
                  color: Colors.red,
                  fontSize: 14.0,
                  fontStyle: FontStyle.italic,
                  fontWeight: FontWeight.bold,
                ),
              ),
              SizedBox(
                height: 40,
              ),
              GestureDetector(
                onTap: () {
                  getCustomPointedPopup(context)
                    ..show(
                      widgetKey: widgetKey, // 目标小部件的全局键
                    );
                },
                child: Card(
                  key: widgetKey, // 目标小部件的全局键
                  elevation: 10,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Container(
                    height: 100,
                    width: 100,
                    child: Center(
                      child: Text(
                        'Click Me \nTo\n Display CPP',
                        textAlign: TextAlign.center,
                        overflow: TextOverflow.clip,
                        style: TextStyle(
                          color: Colors.blueGrey,
                          fontWeight: FontWeight.w900,
                          fontSize: 14.0,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter自定义指向弹出框插件custom_pointed_popup的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义指向弹出框插件custom_pointed_popup的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中自定义和使用一个指向弹出框插件 custom_pointed_popup 的示例代码。请注意,实际使用时,你可能需要先在你的 pubspec.yaml 文件中添加该插件的依赖项(假设该插件存在并且已经在pub.dev上发布)。由于 custom_pointed_popup 并非官方或广泛认知的插件,以下示例将展示一个类似的自定义实现。

1. 添加依赖项(假设插件存在)

首先,在 pubspec.yaml 文件中添加依赖项(如果插件真实存在):

dependencies:
  flutter:
    sdk: flutter
  custom_pointed_popup: ^x.y.z  # 替换为实际版本号

然后运行 flutter pub get

2. 自定义指向弹出框的实现(如果插件不存在)

如果 custom_pointed_popup 插件不存在,你可以自己实现一个类似的弹出框。以下是一个简单的实现示例:

创建一个指向弹出框组件

import 'package:flutter/material.dart';

class PointedPopup extends StatelessWidget {
  final Offset point; // 指向的位置
  final Widget child; // 弹出框内容

  const PointedPopup({Key? key, required this.point, required this.child})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final RenderBox? overlayBox = context.findRenderObject();
    final overlayOffset = overlayBox?.localToGlobal(Offset.zero) ?? Offset.zero;
    final targetPosition = overlayOffset + point;

    return Positioned(
      left: targetPosition.dx - 50, // 调整位置以适应箭头
      top: targetPosition.dy + 20,  // 调整位置以适应箭头和内容
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          _Arrow(direction: ArrowDirection.down),
          Container(
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(8),
              boxShadow: [
                BoxShadow(
                  color: Colors.grey.withOpacity(0.5),
                  spreadRadius: 5,
                  blurRadius: 7,
                  offset: Offset(0, 3), // changes position of shadow
                ),
              ],
            ),
            padding: EdgeInsets.all(16),
            child: child,
          ),
        ],
      ),
    );
  }
}

enum ArrowDirection { up, down, left, right }

class _Arrow extends StatelessWidget {
  final ArrowDirection direction;

  const _Arrow({Key? key, required this.direction}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border(
          bottom: direction == ArrowDirection.up
              ? BorderSide(color: Colors.grey.shade300, width: 2)
              : BorderSide.none,
          top: direction == ArrowDirection.down
              ? BorderSide(color: Colors.grey.shade300, width: 2)
              : BorderSide.none,
          left: direction == ArrowDirection.right
              ? BorderSide(color: Colors.grey.shade300, width: 2)
              : BorderSide.none,
          right: direction == ArrowDirection.left
              ? BorderSide(color: Colors.grey.shade300, width: 2)
              : BorderSide.none,
        ),
        shape: BoxShape.rectangle,
      ),
      child: Padding(
        padding: EdgeInsets.only(
          bottom: direction == ArrowDirection.up ? 8 : 0,
          top: direction == ArrowDirection.down ? 8 : 0,
          left: direction == ArrowDirection.right ? 8 : 0,
          right: direction == ArrowDirection.left ? 8 : 0,
        ),
        child: Transform.rotate(
          angle: direction == ArrowDirection.up
              ? -math.pi / 2
              : direction == ArrowDirection.down
                  ? math.pi / 2
                  : direction == ArrowDirection.left
                      ? math.pi
                      : 0,
          child: Container(
            width: 16,
            height: 8,
            decoration: BoxDecoration(
              color: Colors.grey.shade300,
            ),
          ),
        ),
      ),
    );
  }
}

使用指向弹出框组件

import 'package:flutter/material.dart';
import 'pointed_popup.dart'; // 假设你将上面的代码保存在pointed_popup.dart文件中

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Pointed Popup Example'),
        ),
        body: Center(
          child: Stack(
            children: <Widget>[
              Positioned(
                top: 200,
                left: 150,
                child: GestureDetector(
                  onTap: () {
                    showMenu(
                      context: context,
                      position: RelativeRect.fromLTRB(
                        100, // 根据需要调整
                        250, // 根据需要调整
                        300, // 根据需要调整
                        350, // 根据需要调整
                      ),
                      items: <PopupMenuEntry<void>>[
                        PopupMenuItem<void>(
                          child: StatefulBuilder(
                            builder: (BuildContext context, void Function(void) setState) {
                              Offset? point;
                              return GestureDetector(
                                onTapDown: (details) {
                                  point = details.globalPosition;
                                  setState(() {});
                                },
                                child: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  children: <Widget>[
                                    if (point != null)
                                      PointedPopup(
                                        point: point!,
                                        child: Container(
                                          color: Colors.transparent,
                                          child: Text('Hello, this is a pointed popup!'),
                                        ),
                                      ),
                                    SizedBox(height: 20), // 为了展示点击效果,添加一些间距
                                    Text('Tap me to show popup'),
                                  ],
                                ),
                              );
                            },
                          ),
                        ),
                      ],
                    );
                  },
                  child: Text('Show Popup'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的指向弹出框组件 PointedPopup,并在点击文本时显示它。这个示例并没有使用实际的 custom_pointed_popup 插件,而是展示了如何自定义一个类似的组件。如果你有一个具体的 custom_pointed_popup 插件,你应该参考其文档来了解如何使用。

回到顶部