Flutter弹出菜单插件starlight_popup_menu的使用

Flutter弹出菜单插件starlight_popup_menu的使用

概述

Starlight Popup Menu 是一个可以扩展的弹出菜单小部件。如果您想将其作为函数使用,可以考虑使用 starlight_utils 包。

预览

安装

pubspec.yaml 文件中添加以下依赖项:

dependencies:
  starlight_popup_menu:
    git:
      url: https://github.com/YeMyoAung/starlight_popup_menu.git

设置

对于 Android 和 iOS 平台,无需额外集成步骤。

使用

首先,您需要导入我们的包:

import 'package:starlight_popup_menu/starlight_popup_menu.dart';

然后,您可以轻松地使用它。

StarlightPopupMenuBase

StarlightPopupMenuBase 是一个可以像 StatefulWidgetStatelessWidget 一样扩展的小部件。

class SettingButton extends StarlightPopupMenuBase {
}

StarlightPopupMenuController

StarlightPopupMenuController 可以控制您的菜单。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  Widget builder(
      BuildContext context, StarlightPopupMenuController controller) {
    // 显示菜单
    controller.showMenu();
    // 隐藏菜单
    controller.hideMenu();
  }
}
class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  Widget builder(
      BuildContext context, StarlightPopupMenuController controller) {
    return StreamBuilder<bool>(
        initialData: false,
        stream: _state.stream,
        builder: (_, snapshot) {
          return AnimatedIcon(
            icon: snapshot.data == true
                ? AnimatedIcons.menu_close
                : AnimatedIcons.arrow_menu,
            progress: kAlwaysCompleteAnimation,
          );
        });
  }
}

Builder 方法

Builder 方法会为您提供 BuildContextStarlightPopupMenuController。您必须返回一个 Widget,该 Widget 将作为按钮显示。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  Widget builder(
      BuildContext context, StarlightPopupMenuController controller) {
    return StreamBuilder<bool>(
        initialData: false,
        stream: _state.stream,
        builder: (_, snapshot) {
          return AnimatedIcon(
            icon: snapshot.data == true
                ? AnimatedIcons.menu_close
                : AnimatedIcons.arrow_menu,
            progress: kAlwaysCompleteAnimation,
          );
        });
  }
}

菜单

Builder 方法同样会为您提供 BuildContextStarlightPopupMenuController。您必须返回一个 Widget,该 Widget 将作为菜单显示。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  Widget menu(BuildContext context, StarlightPopupMenuController controller) {
    return Container(
      width: 200,
      height: 120,
      color: Colors.white,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ListTile(
            onTap: controller.hideMenu,
            title: Row(
              children: const [
                Icon(Icons.settings),
                SizedBox(
                  width: 10,
                ),
                Text("Setting"),
              ],
            ),
          ),
          ListTile(
            onTap: controller.hideMenu,
            title: Row(
              children: const [
                Icon(Icons.help),
                SizedBox(
                  width: 10,
                ),
                Text("Help"),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

风格

您可以返回一个 StarlightPopupMenuTheme 对象,该对象将包含颜色、大小、位置和指示器。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  StarlightPopupMenuTheme style() => StarlightPopupMenuTheme(
        position: StarlightPreferredPosition.bottom,
        horizontalMargin: 8,
        verticalMargin: 0,
        indicatorSize: 15,
        indicatorColor: Colors.white,
        customIndicator: StarClipper(),
      );
}

按压类型

您可以返回一个 StarlightPressType 枚举,该枚举将用于您的手势。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  StarlightPressType pressType() => StarlightPressType.onTap;
}

改变事件

您可以使用 onChange 方法监听菜单是否已关闭。

class SettingButton extends StarlightPopupMenuBase {
  [@override](/user/override)
  void onChange(bool value) {
    _state.onChange(value);
    super.onChange(value);
  }
}

示例

下面是一个完整的示例演示如何使用 starlight_popup_menu 插件。

import 'dart:async';
import 'dart:math';

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("默认样式"),
            MenuVertical(state: State()),
            const SizedBox(height: 20),
            const Text("自定义样式"),
            MenuVertical(
              state: State(),
              customIndicator: StarClipper(),
            ),
          ],
        ),
      ),
    );
  }
}

class State {
  Stream<bool> get stream => _streamController.stream;

  final StreamController<bool> _streamController = StreamController.broadcast();

  void onChange(bool value) {
    _streamController.sink.add(value);
  }
}

class MenuVertical extends StarlightPopupMenuBase {
  final CustomClipper<Path>? customIndicator;
  final State state;
  const MenuVertical({Key? key, this.customIndicator, required this.state})
      : super(key: key);

  [@override](/user/override)
  void onChange(bool value) {
    state.onChange(value);
    super.onChange(value);
  }

  [@override](/user/override)
  StarlightPressType pressType() {
    return StarlightPressType.onTap;
  }

  [@override](/user/override)
  StarlightPopupMenuTheme style(BuildContext context) =>
      StarlightPopupMenuTheme(
        position: StarlightPreferredPosition.bottom,
        horizontalMargin: 8,
        verticalMargin: 0,
        indicatorSize: 15,
        indicatorColor: Colors.white,
        customIndicator: customIndicator,
      );

  [@override](/user/override)
  Widget builder(
      BuildContext context, StarlightPopupMenuController controller) {
    return StreamBuilder<bool>(
        initialData: false,
        stream: state.stream,
        builder: (_, snapshot) {
          return AnimatedIcon(
            icon: snapshot.data == true
                ? AnimatedIcons.menu_close
                : AnimatedIcons.arrow_menu,
            progress: kAlwaysCompleteAnimation,
          );
        });
  }

  [@override](/user/override)
  Widget menu(BuildContext context, StarlightPopupMenuController controller) {
    return Container(
      width: 200,
      height: 120,
      color: Colors.white,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ListTile(
            onTap: controller.hideMenu,
            title: Row(
              children: const [
                Icon(Icons.settings),
                SizedBox(
                  width: 10,
                ),
                Text("设置"),
              ],
            ),
          ),
          ListTile(
            onTap: controller.hideMenu,
            title: Row(
              children: const [
                Icon(Icons.help),
                SizedBox(
                  width: 10,
                ),
                Text("帮助"),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class StarClipper extends CustomClipper<Path> {
  StarClipper();

  double _degreeToRadian(double deg) => deg * (pi / 180.0);

  [@override](/user/override)
  Path getClip(Size size) {
    Path path = Path();
    double max = 2 * pi;

    double width = size.width;
    double halfWidth = width / 2;

    double wingRadius = halfWidth;
    double radius = halfWidth / 2;

    double degreesPerStep = _degreeToRadian(360 / 6);
    double halfDegreesPerStep = degreesPerStep / 2;

    path.moveTo(width, halfWidth);

    for (double step = 0; step < max; step += degreesPerStep) {
      path.lineTo(halfWidth + wingRadius * cos(step),
          halfWidth + wingRadius * sin(step));
      path.lineTo(halfWidth + radius * cos(step + halfDegreesPerStep),
          halfWidth + radius * sin(step + halfDegreesPerStep));
    }

    path.close();
    return path;
  }

  [@override](/user/override)
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}

更多关于Flutter弹出菜单插件starlight_popup_menu的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter弹出菜单插件starlight_popup_menu的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


starlight_popup_menu 是一个 Flutter 插件,用于在应用中创建自定义的弹出菜单。它提供了灵活的配置选项,允许你根据需求定制弹出菜单的外观和行为。以下是如何使用 starlight_popup_menu 的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 starlight_popup_menu 依赖:

dependencies:
  flutter:
    sdk: flutter
  starlight_popup_menu: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 导入包

在你的 Dart 文件中导入 starlight_popup_menu

import 'package:starlight_popup_menu/starlight_popup_menu.dart';

3. 创建弹出菜单

你可以使用 StarlightPopupMenu 类来创建弹出菜单。以下是一个简单的示例:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Starlight Popup Menu Example'),
        ),
        body: Center(
          child: PopupMenuExample(),
        ),
      ),
    );
  }
}

class PopupMenuExample extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return StarlightPopupMenu(
      child: Text('Show Menu'),
      items: [
        PopupMenuItem(
          child: Text('Item 1'),
          onTap: () {
            print('Item 1 tapped');
          },
        ),
        PopupMenuItem(
          child: Text('Item 2'),
          onTap: () {
            print('Item 2 tapped');
          },
        ),
        PopupMenuItem(
          child: Text('Item 3'),
          onTap: () {
            print('Item 3 tapped');
          },
        ),
      ],
    );
  }
}

4. 自定义弹出菜单

starlight_popup_menu 提供了多种自定义选项,例如设置菜单的位置、背景颜色、阴影等。以下是一些常见的自定义配置:

  • 位置:你可以通过 position 参数设置菜单的弹出位置。例如,PopupMenuPosition.topPopupMenuPosition.bottom 等。
  • 背景颜色:通过 backgroundColor 参数设置菜单的背景颜色。
  • 阴影:通过 shadowColorelevation 参数设置菜单的阴影效果。
StarlightPopupMenu(
  child: Text('Show Menu'),
  position: PopupMenuPosition.bottom,
  backgroundColor: Colors.blue,
  shadowColor: Colors.black.withOpacity(0.5),
  elevation: 10.0,
  items: [
    PopupMenuItem(
      child: Text('Item 1'),
      onTap: () {
        print('Item 1 tapped');
      },
    ),
    PopupMenuItem(
      child: Text('Item 2'),
      onTap: () {
        print('Item 2 tapped');
      },
    ),
  ],
);

5. 处理菜单项点击事件

每个 PopupMenuItem 都有一个 onTap 回调函数,当用户点击该菜单项时,这个函数会被调用。你可以在 onTap 中执行任何你需要的操作。

PopupMenuItem(
  child: Text('Item 1'),
  onTap: () {
    print('Item 1 tapped');
    // 执行其他操作
  },
),

6. 完整示例

以下是一个完整的示例,展示了如何使用 starlight_popup_menu 创建一个自定义弹出菜单:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Starlight Popup Menu Example'),
        ),
        body: Center(
          child: PopupMenuExample(),
        ),
      ),
    );
  }
}

class PopupMenuExample extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return StarlightPopupMenu(
      child: Text('Show Menu'),
      position: PopupMenuPosition.bottom,
      backgroundColor: Colors.blue,
      shadowColor: Colors.black.withOpacity(0.5),
      elevation: 10.0,
      items: [
        PopupMenuItem(
          child: Text('Item 1'),
          onTap: () {
            print('Item 1 tapped');
          },
        ),
        PopupMenuItem(
          child: Text('Item 2'),
          onTap: () {
            print('Item 2 tapped');
          },
        ),
        PopupMenuItem(
          child: Text('Item 3'),
          onTap: () {
            print('Item 3 tapped');
          },
        ),
      ],
    );
  }
}
回到顶部