├── .gitignore
├── .metadata
├── .vscode
└── launch.json
├── 01.png
├── 02.png
├── 03.png
├── 04.png
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── README.md
├── android
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── popup_menu_example
│ │ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ └── copy.png
├── ios
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ ├── gesture_demo.dart
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── lib
├── popup_menu.dart
└── src
│ ├── grid_menu_layout.dart
│ ├── list_menu_layout.dart
│ ├── menu_config.dart
│ ├── menu_item.dart
│ ├── menu_item_widget.dart
│ ├── menu_layout.dart
│ ├── popup_menu.dart
│ ├── triangle_painter.dart
│ └── utils.dart
├── popupmenu.png
├── pubspec.lock
├── pubspec.yaml
└── test
└── popup_menu_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 |
67 | # Exceptions to above rules.
68 | !**/ios/**/default.mode1v3
69 | !**/ios/**/default.mode2v3
70 | !**/ios/**/default.pbxuser
71 | !**/ios/**/default.perspectivev3
72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
73 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 6861c2cca0ac21380bede5e0565f7ca4ebda1f45
8 | channel: origin/master
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/01.png
--------------------------------------------------------------------------------
/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/02.png
--------------------------------------------------------------------------------
/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/03.png
--------------------------------------------------------------------------------
/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/04.png
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [2.0.0] - 2022.03.21
2 | * Refactoring code
3 | * Support list menu
4 |
5 | ## [1.0.4] - 2019.10.17
6 | * Fix [#5](https://github.com/chinabrant/popup_menu/issues/5)
7 | * Add some comments
8 | * Fix MenuItemProvider, you can use custom model now.
9 |
10 | ## [1.0.3] - 2019.08.30
11 | * Close menu on scroll/swipe gestures. [issues 3](https://github.com/chinabrant/popup_menu/issues/3)
12 |
13 | ## [1.0.2] - 2019.08.19
14 | * Fix #1
15 | * Fix health suggestions
16 | * Add stateChanged callback, [issues 2](https://github.com/chinabrant/popup_menu/issues/2)
17 |
18 | ## [1.0.1] - 2019.06.02
19 | * Fix health suggestions
20 |
21 | ## [0.0.1] - 2019.05.31
22 |
23 | * Custom backgroundColor
24 | * Custom TextStyle
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ## PopupMenu
2 |
3 | MIT License
4 |
5 | Copyright (c) 2019 chinabrant
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://pub.dev/packages/popup_menu)
4 |
5 | This project was written completely in dart, and it supports both iOS and Android.
6 |
7 | # Screenshots
8 | 

9 |
10 |
11 |
12 | # Todo
13 | - [ ] show/hide animation
14 |
15 | # Usage
16 |
17 |
18 | You can find the demo at the 'example' folder.
19 |
20 | First, you should set the context at somewhere in you code. Like below:
21 | ```dart
22 | PopupMenu.context = context;
23 | ```
24 | ```dart
25 | PopupMenu menu = PopupMenu(
26 | items: [
27 | MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
28 | MenuItem(title: 'Home', image: Icon(Icons.home, color: Colors.white,)),
29 | MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.white,)),
30 | MenuItem(title: 'Power', image: Icon(Icons.power, color: Colors.white,)),
31 | MenuItem(title: 'Setting', image: Icon(Icons.settings, color: Colors.white,)),
32 | MenuItem(title: 'Traffic', image: Icon(Icons.traffic, color: Colors.white,))],
33 | onClickMenu: onClickMenu,
34 | onShow: onShow,
35 | onDismiss: onDismiss);
36 |
37 | menu.show(rect: rect);
38 |
39 |
40 | ```
41 |
42 | or
43 |
44 | ```dart
45 | PopupMenu menu = PopupMenu(
46 | backgroundColor: Colors.teal,
47 | lineColor: Colors.tealAccent,
48 | maxColumn: 3,
49 | items: [
50 | MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
51 | MenuItem(
52 | title: 'Home',
53 | textStyle: TextStyle(fontSize: 10.0, color: Colors.tealAccent),
54 | image: Icon(
55 | Icons.home,
56 | color: Colors.white,
57 | )),
58 | MenuItem(
59 | title: 'Mail',
60 | image: Icon(
61 | Icons.mail,
62 | color: Colors.white,
63 | )),
64 | MenuItem(
65 | title: 'Power',
66 | image: Icon(
67 | Icons.power,
68 | color: Colors.white,
69 | )),
70 | MenuItem(
71 | title: 'Setting',
72 | image: Icon(
73 | Icons.settings,
74 | color: Colors.white,
75 | )),
76 | MenuItem(
77 | title: 'PopupMenu',
78 | image: Icon(
79 | Icons.menu,
80 | color: Colors.white,
81 | ))
82 | ],
83 | onClickMenu: onClickMenu,
84 | onDismiss: onDismiss);
85 | menu.show(widgetKey: btnKey2);
86 | ```
87 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # popup_menu_example
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.example.popup_menu_example"
37 | minSdkVersion 16
38 | targetSdkVersion 28
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
13 |
20 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/popup_menu_example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.popup_menu_example;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/assets/copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/assets/copy.png
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/brant/.fvm/versions/stable"
4 | export "FLUTTER_APPLICATION_PATH=/Users/brant/Documents/code/github/popup_menu/example"
5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true"
6 | export "FLUTTER_TARGET=/Users/brant/Documents/code/github/popup_menu/example/lib/main.dart"
7 | export "FLUTTER_BUILD_DIR=build"
8 | export "FLUTTER_BUILD_NAME=1.0.0"
9 | export "FLUTTER_BUILD_NUMBER=1"
10 | export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl"
11 | export "DART_OBFUSCATION=false"
12 | export "TRACK_WIDGET_CREATION=true"
13 | export "TREE_SHAKE_ICONS=false"
14 | export "PACKAGE_CONFIG=/Users/brant/Documents/code/github/popup_menu/example/.dart_tool/package_config.json"
15 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
13 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
14 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
15 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
16 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
17 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXCopyFilesBuildPhase section */
21 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
22 | isa = PBXCopyFilesBuildPhase;
23 | buildActionMask = 2147483647;
24 | dstPath = "";
25 | dstSubfolderSpec = 10;
26 | files = (
27 | );
28 | name = "Embed Frameworks";
29 | runOnlyForDeploymentPostprocessing = 0;
30 | };
31 | /* End PBXCopyFilesBuildPhase section */
32 |
33 | /* Begin PBXFileReference section */
34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
39 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
40 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
41 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
42 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
48 | /* End PBXFileReference section */
49 |
50 | /* Begin PBXFrameworksBuildPhase section */
51 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
52 | isa = PBXFrameworksBuildPhase;
53 | buildActionMask = 2147483647;
54 | files = (
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | /* End PBXFrameworksBuildPhase section */
59 |
60 | /* Begin PBXGroup section */
61 | 9740EEB11CF90186004384FC /* Flutter */ = {
62 | isa = PBXGroup;
63 | children = (
64 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
65 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
66 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
67 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
68 | );
69 | name = Flutter;
70 | sourceTree = "";
71 | };
72 | 97C146E51CF9000F007C117D = {
73 | isa = PBXGroup;
74 | children = (
75 | 9740EEB11CF90186004384FC /* Flutter */,
76 | 97C146F01CF9000F007C117D /* Runner */,
77 | 97C146EF1CF9000F007C117D /* Products */,
78 | );
79 | sourceTree = "";
80 | };
81 | 97C146EF1CF9000F007C117D /* Products */ = {
82 | isa = PBXGroup;
83 | children = (
84 | 97C146EE1CF9000F007C117D /* Runner.app */,
85 | );
86 | name = Products;
87 | sourceTree = "";
88 | };
89 | 97C146F01CF9000F007C117D /* Runner */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
93 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
94 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
95 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
96 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97 | 97C147021CF9000F007C117D /* Info.plist */,
98 | 97C146F11CF9000F007C117D /* Supporting Files */,
99 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
100 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
101 | );
102 | path = Runner;
103 | sourceTree = "";
104 | };
105 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 97C146F21CF9000F007C117D /* main.m */,
109 | );
110 | name = "Supporting Files";
111 | sourceTree = "";
112 | };
113 | /* End PBXGroup section */
114 |
115 | /* Begin PBXNativeTarget section */
116 | 97C146ED1CF9000F007C117D /* Runner */ = {
117 | isa = PBXNativeTarget;
118 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
119 | buildPhases = (
120 | 9740EEB61CF901F6004384FC /* Run Script */,
121 | 97C146EA1CF9000F007C117D /* Sources */,
122 | 97C146EB1CF9000F007C117D /* Frameworks */,
123 | 97C146EC1CF9000F007C117D /* Resources */,
124 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
125 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
126 | );
127 | buildRules = (
128 | );
129 | dependencies = (
130 | );
131 | name = Runner;
132 | productName = Runner;
133 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
134 | productType = "com.apple.product-type.application";
135 | };
136 | /* End PBXNativeTarget section */
137 |
138 | /* Begin PBXProject section */
139 | 97C146E61CF9000F007C117D /* Project object */ = {
140 | isa = PBXProject;
141 | attributes = {
142 | LastUpgradeCheck = 1510;
143 | ORGANIZATIONNAME = "The Chromium Authors";
144 | TargetAttributes = {
145 | 97C146ED1CF9000F007C117D = {
146 | CreatedOnToolsVersion = 7.3.1;
147 | DevelopmentTeam = VD53F6HB6C;
148 | };
149 | };
150 | };
151 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
152 | compatibilityVersion = "Xcode 3.2";
153 | developmentRegion = English;
154 | hasScannedForEncodings = 0;
155 | knownRegions = (
156 | English,
157 | en,
158 | Base,
159 | );
160 | mainGroup = 97C146E51CF9000F007C117D;
161 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
162 | projectDirPath = "";
163 | projectRoot = "";
164 | targets = (
165 | 97C146ED1CF9000F007C117D /* Runner */,
166 | );
167 | };
168 | /* End PBXProject section */
169 |
170 | /* Begin PBXResourcesBuildPhase section */
171 | 97C146EC1CF9000F007C117D /* Resources */ = {
172 | isa = PBXResourcesBuildPhase;
173 | buildActionMask = 2147483647;
174 | files = (
175 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
176 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
177 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
178 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
179 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
180 | );
181 | runOnlyForDeploymentPostprocessing = 0;
182 | };
183 | /* End PBXResourcesBuildPhase section */
184 |
185 | /* Begin PBXShellScriptBuildPhase section */
186 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | alwaysOutOfDate = 1;
189 | buildActionMask = 2147483647;
190 | files = (
191 | );
192 | inputPaths = (
193 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
194 | );
195 | name = "Thin Binary";
196 | outputPaths = (
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | shellPath = /bin/sh;
200 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
201 | };
202 | 9740EEB61CF901F6004384FC /* Run Script */ = {
203 | isa = PBXShellScriptBuildPhase;
204 | alwaysOutOfDate = 1;
205 | buildActionMask = 2147483647;
206 | files = (
207 | );
208 | inputPaths = (
209 | );
210 | name = "Run Script";
211 | outputPaths = (
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | shellPath = /bin/sh;
215 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
216 | };
217 | /* End PBXShellScriptBuildPhase section */
218 |
219 | /* Begin PBXSourcesBuildPhase section */
220 | 97C146EA1CF9000F007C117D /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
225 | 97C146F31CF9000F007C117D /* main.m in Sources */,
226 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
227 | );
228 | runOnlyForDeploymentPostprocessing = 0;
229 | };
230 | /* End PBXSourcesBuildPhase section */
231 |
232 | /* Begin PBXVariantGroup section */
233 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
234 | isa = PBXVariantGroup;
235 | children = (
236 | 97C146FB1CF9000F007C117D /* Base */,
237 | );
238 | name = Main.storyboard;
239 | sourceTree = "";
240 | };
241 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
242 | isa = PBXVariantGroup;
243 | children = (
244 | 97C147001CF9000F007C117D /* Base */,
245 | );
246 | name = LaunchScreen.storyboard;
247 | sourceTree = "";
248 | };
249 | /* End PBXVariantGroup section */
250 |
251 | /* Begin XCBuildConfiguration section */
252 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
253 | isa = XCBuildConfiguration;
254 | buildSettings = {
255 | ALWAYS_SEARCH_USER_PATHS = NO;
256 | CLANG_ANALYZER_NONNULL = YES;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
262 | CLANG_WARN_BOOL_CONVERSION = YES;
263 | CLANG_WARN_COMMA = YES;
264 | CLANG_WARN_CONSTANT_CONVERSION = YES;
265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266 | CLANG_WARN_EMPTY_BODY = YES;
267 | CLANG_WARN_ENUM_CONVERSION = YES;
268 | CLANG_WARN_INFINITE_RECURSION = YES;
269 | CLANG_WARN_INT_CONVERSION = YES;
270 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
271 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
273 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
274 | CLANG_WARN_STRICT_PROTOTYPES = YES;
275 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
276 | CLANG_WARN_UNREACHABLE_CODE = YES;
277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
279 | COPY_PHASE_STRIP = NO;
280 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
281 | ENABLE_NS_ASSERTIONS = NO;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | GCC_C_LANGUAGE_STANDARD = gnu99;
284 | GCC_NO_COMMON_BLOCKS = YES;
285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
287 | GCC_WARN_UNDECLARED_SELECTOR = YES;
288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
289 | GCC_WARN_UNUSED_FUNCTION = YES;
290 | GCC_WARN_UNUSED_VARIABLE = YES;
291 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
292 | MTL_ENABLE_DEBUG_INFO = NO;
293 | SDKROOT = iphoneos;
294 | TARGETED_DEVICE_FAMILY = "1,2";
295 | VALIDATE_PRODUCT = YES;
296 | };
297 | name = Profile;
298 | };
299 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
300 | isa = XCBuildConfiguration;
301 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
302 | buildSettings = {
303 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
304 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
305 | DEVELOPMENT_TEAM = VD53F6HB6C;
306 | ENABLE_BITCODE = NO;
307 | FRAMEWORK_SEARCH_PATHS = (
308 | "$(inherited)",
309 | "$(PROJECT_DIR)/Flutter",
310 | );
311 | INFOPLIST_FILE = Runner/Info.plist;
312 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
313 | LIBRARY_SEARCH_PATHS = (
314 | "$(inherited)",
315 | "$(PROJECT_DIR)/Flutter",
316 | );
317 | PRODUCT_BUNDLE_IDENTIFIER = com.example.popupMenuExample;
318 | PRODUCT_NAME = "$(TARGET_NAME)";
319 | VERSIONING_SYSTEM = "apple-generic";
320 | };
321 | name = Profile;
322 | };
323 | 97C147031CF9000F007C117D /* Debug */ = {
324 | isa = XCBuildConfiguration;
325 | buildSettings = {
326 | ALWAYS_SEARCH_USER_PATHS = NO;
327 | CLANG_ANALYZER_NONNULL = YES;
328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
329 | CLANG_CXX_LIBRARY = "libc++";
330 | CLANG_ENABLE_MODULES = YES;
331 | CLANG_ENABLE_OBJC_ARC = YES;
332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
333 | CLANG_WARN_BOOL_CONVERSION = YES;
334 | CLANG_WARN_COMMA = YES;
335 | CLANG_WARN_CONSTANT_CONVERSION = YES;
336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
337 | CLANG_WARN_EMPTY_BODY = YES;
338 | CLANG_WARN_ENUM_CONVERSION = YES;
339 | CLANG_WARN_INFINITE_RECURSION = YES;
340 | CLANG_WARN_INT_CONVERSION = YES;
341 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
345 | CLANG_WARN_STRICT_PROTOTYPES = YES;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNREACHABLE_CODE = YES;
348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
350 | COPY_PHASE_STRIP = NO;
351 | DEBUG_INFORMATION_FORMAT = dwarf;
352 | ENABLE_STRICT_OBJC_MSGSEND = YES;
353 | ENABLE_TESTABILITY = YES;
354 | GCC_C_LANGUAGE_STANDARD = gnu99;
355 | GCC_DYNAMIC_NO_PIC = NO;
356 | GCC_NO_COMMON_BLOCKS = YES;
357 | GCC_OPTIMIZATION_LEVEL = 0;
358 | GCC_PREPROCESSOR_DEFINITIONS = (
359 | "DEBUG=1",
360 | "$(inherited)",
361 | );
362 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
363 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
364 | GCC_WARN_UNDECLARED_SELECTOR = YES;
365 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
366 | GCC_WARN_UNUSED_FUNCTION = YES;
367 | GCC_WARN_UNUSED_VARIABLE = YES;
368 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
369 | MTL_ENABLE_DEBUG_INFO = YES;
370 | ONLY_ACTIVE_ARCH = YES;
371 | SDKROOT = iphoneos;
372 | TARGETED_DEVICE_FAMILY = "1,2";
373 | };
374 | name = Debug;
375 | };
376 | 97C147041CF9000F007C117D /* Release */ = {
377 | isa = XCBuildConfiguration;
378 | buildSettings = {
379 | ALWAYS_SEARCH_USER_PATHS = NO;
380 | CLANG_ANALYZER_NONNULL = YES;
381 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
382 | CLANG_CXX_LIBRARY = "libc++";
383 | CLANG_ENABLE_MODULES = YES;
384 | CLANG_ENABLE_OBJC_ARC = YES;
385 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
386 | CLANG_WARN_BOOL_CONVERSION = YES;
387 | CLANG_WARN_COMMA = YES;
388 | CLANG_WARN_CONSTANT_CONVERSION = YES;
389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
390 | CLANG_WARN_EMPTY_BODY = YES;
391 | CLANG_WARN_ENUM_CONVERSION = YES;
392 | CLANG_WARN_INFINITE_RECURSION = YES;
393 | CLANG_WARN_INT_CONVERSION = YES;
394 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
395 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
396 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
397 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
398 | CLANG_WARN_STRICT_PROTOTYPES = YES;
399 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
400 | CLANG_WARN_UNREACHABLE_CODE = YES;
401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
403 | COPY_PHASE_STRIP = NO;
404 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
405 | ENABLE_NS_ASSERTIONS = NO;
406 | ENABLE_STRICT_OBJC_MSGSEND = YES;
407 | GCC_C_LANGUAGE_STANDARD = gnu99;
408 | GCC_NO_COMMON_BLOCKS = YES;
409 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
410 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
411 | GCC_WARN_UNDECLARED_SELECTOR = YES;
412 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
413 | GCC_WARN_UNUSED_FUNCTION = YES;
414 | GCC_WARN_UNUSED_VARIABLE = YES;
415 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
416 | MTL_ENABLE_DEBUG_INFO = NO;
417 | SDKROOT = iphoneos;
418 | TARGETED_DEVICE_FAMILY = "1,2";
419 | VALIDATE_PRODUCT = YES;
420 | };
421 | name = Release;
422 | };
423 | 97C147061CF9000F007C117D /* Debug */ = {
424 | isa = XCBuildConfiguration;
425 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
426 | buildSettings = {
427 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
428 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
429 | DEVELOPMENT_TEAM = VD53F6HB6C;
430 | ENABLE_BITCODE = NO;
431 | FRAMEWORK_SEARCH_PATHS = (
432 | "$(inherited)",
433 | "$(PROJECT_DIR)/Flutter",
434 | );
435 | INFOPLIST_FILE = Runner/Info.plist;
436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
437 | LIBRARY_SEARCH_PATHS = (
438 | "$(inherited)",
439 | "$(PROJECT_DIR)/Flutter",
440 | );
441 | PRODUCT_BUNDLE_IDENTIFIER = com.example.popupMenuExample;
442 | PRODUCT_NAME = "$(TARGET_NAME)";
443 | VERSIONING_SYSTEM = "apple-generic";
444 | };
445 | name = Debug;
446 | };
447 | 97C147071CF9000F007C117D /* Release */ = {
448 | isa = XCBuildConfiguration;
449 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
450 | buildSettings = {
451 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
452 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
453 | DEVELOPMENT_TEAM = VD53F6HB6C;
454 | ENABLE_BITCODE = NO;
455 | FRAMEWORK_SEARCH_PATHS = (
456 | "$(inherited)",
457 | "$(PROJECT_DIR)/Flutter",
458 | );
459 | INFOPLIST_FILE = Runner/Info.plist;
460 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
461 | LIBRARY_SEARCH_PATHS = (
462 | "$(inherited)",
463 | "$(PROJECT_DIR)/Flutter",
464 | );
465 | PRODUCT_BUNDLE_IDENTIFIER = com.example.popupMenuExample;
466 | PRODUCT_NAME = "$(TARGET_NAME)";
467 | VERSIONING_SYSTEM = "apple-generic";
468 | };
469 | name = Release;
470 | };
471 | /* End XCBuildConfiguration section */
472 |
473 | /* Begin XCConfigurationList section */
474 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
475 | isa = XCConfigurationList;
476 | buildConfigurations = (
477 | 97C147031CF9000F007C117D /* Debug */,
478 | 97C147041CF9000F007C117D /* Release */,
479 | 249021D3217E4FDB00AE95B9 /* Profile */,
480 | );
481 | defaultConfigurationIsVisible = 0;
482 | defaultConfigurationName = Release;
483 | };
484 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
485 | isa = XCConfigurationList;
486 | buildConfigurations = (
487 | 97C147061CF9000F007C117D /* Debug */,
488 | 97C147071CF9000F007C117D /* Release */,
489 | 249021D4217E4FDB00AE95B9 /* Profile */,
490 | );
491 | defaultConfigurationIsVisible = 0;
492 | defaultConfigurationName = Release;
493 | };
494 | /* End XCConfigurationList section */
495 | };
496 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
497 | }
498 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | popup_menu_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/lib/gesture_demo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/popup_menu.dart';
3 |
4 | class GestureDemo extends StatefulWidget {
5 | @override
6 | State createState() {
7 | return _GestureDemoState();
8 | }
9 | }
10 |
11 | class _GestureDemoState extends State {
12 | GlobalKey btnKey = GlobalKey();
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Scaffold(
17 | appBar: AppBar(
18 | title: Text('Scroll Gestures'),
19 | ),
20 | body: Stack(
21 | children: [
22 | ListView.builder(
23 | itemCount: 20,
24 | itemBuilder: (context, index) {
25 | return Container(
26 | height: 50.0,
27 | child: Text('test'),
28 | );
29 | },
30 | ),
31 | Positioned(
32 | left: 100.0,
33 | top: 100.0,
34 | width: 100.0,
35 | height: 50.0,
36 | child: MaterialButton(
37 | key: btnKey,
38 | child: Text('show'),
39 | onPressed: onShow,
40 | ),
41 | )
42 | ],
43 | ),
44 | );
45 | }
46 |
47 | void onShow() {
48 | PopupMenu menu = PopupMenu(
49 | // backgroundColor: Colors.teal,
50 | // lineColor: Colors.tealAccent,
51 | // maxColumn: 2,
52 | items: [
53 | MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
54 | MenuItem(
55 | title: 'Home',
56 | // textStyle: TextStyle(fontSize: 10.0, color: Colors.tealAccent),
57 | image: Icon(
58 | Icons.home,
59 | color: Colors.white,
60 | )),
61 | MenuItem(
62 | title: 'Mail',
63 | image: Icon(
64 | Icons.mail,
65 | color: Colors.white,
66 | )),
67 | MenuItem(
68 | title: 'Power',
69 | image: Icon(
70 | Icons.power,
71 | color: Colors.white,
72 | )),
73 | MenuItem(
74 | title: 'Setting',
75 | image: Icon(
76 | Icons.settings,
77 | color: Colors.white,
78 | )),
79 | MenuItem(
80 | title: 'PopupMenu',
81 | image: Icon(
82 | Icons.menu,
83 | color: Colors.white,
84 | ))
85 | ],
86 | onClickMenu: onClickMenu,
87 | // stateChanged: stateChanged,
88 | onDismiss: onDismiss, context: context,
89 | );
90 | menu.show(widgetKey: btnKey);
91 | }
92 |
93 | void onClickMenu(MenuItemProvider item) {}
94 |
95 | void onDismiss() {}
96 | }
97 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/popup_menu.dart';
3 | import 'package:popup_menu_example/gesture_demo.dart';
4 |
5 | void main() => runApp(MyApp());
6 |
7 | class MyApp extends StatelessWidget {
8 | // This widget is the root of your application.
9 | @override
10 | Widget build(BuildContext context) {
11 | return MaterialApp(
12 | title: 'Flutter Demo',
13 | home: MyHomePage(title: 'Popup Menu Example'),
14 | );
15 | }
16 | }
17 |
18 | class MyHomePage extends StatefulWidget {
19 | MyHomePage({required this.title});
20 |
21 | final String title;
22 |
23 | @override
24 | _MyHomePageState createState() => _MyHomePageState();
25 | }
26 |
27 | class _MyHomePageState extends State {
28 | late PopupMenu menu;
29 | GlobalKey btnKey = GlobalKey();
30 | GlobalKey btnKey2 = GlobalKey();
31 | GlobalKey btnKey3 = GlobalKey();
32 | GlobalKey btnKey4 = GlobalKey();
33 |
34 | GlobalKey customWidthKey = GlobalKey();
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | }
40 |
41 | void onClickMenu(MenuItemProvider item) {
42 | print('Click menu -> ${item.menuTitle}');
43 | }
44 |
45 | void onDismiss() {
46 | print('Menu is dismiss');
47 | }
48 |
49 | void onShow() {
50 | print('Menu is show');
51 | }
52 |
53 | @override
54 | Widget build(BuildContext context) {
55 | return Scaffold(
56 | appBar: AppBar(
57 | title: Text(widget.title),
58 | ),
59 | body: Container(
60 | alignment: Alignment.centerRight,
61 | child: Column(
62 | mainAxisAlignment: MainAxisAlignment.start,
63 | children: [
64 | Container(
65 | color: Colors.blue,
66 | child: MaterialButton(
67 | height: 45.0,
68 | key: btnKey,
69 | onPressed: maxColumn,
70 | child: Text('Show Menu'),
71 | ),
72 | ),
73 | Container(
74 | child: MaterialButton(
75 | key: btnKey2,
76 | height: 45.0,
77 | onPressed: customBackground,
78 | child: Text('Custom Background'),
79 | ),
80 | ),
81 | Container(
82 | child: MaterialButton(
83 | key: btnKey3,
84 | height: 45.0,
85 | onPressed: onDismissOnlyBeCalledOnce,
86 | child: Text('Show Menu'),
87 | ),
88 | ),
89 | Container(
90 | child: MaterialButton(
91 | key: btnKey4,
92 | height: 45.0,
93 | onPressed: listMenu,
94 | child: Text('List Menu'),
95 | ),
96 | ),
97 | Container(
98 | child: MaterialButton(
99 | key: customWidthKey,
100 | height: 45.0,
101 | onPressed: customItemWidth,
102 | child: Text('CustomItemWidth'),
103 | ),
104 | ),
105 | Container(
106 | child: MaterialButton(
107 | height: 30.0,
108 | child: Text('Gestures Demo'),
109 | onPressed: onGesturesDemo,
110 | ),
111 | )
112 | ],
113 | ),
114 | ),
115 | );
116 | }
117 |
118 | void onDismissOnlyBeCalledOnce() {
119 | menu = PopupMenu(
120 | context: context,
121 | items: [
122 | // MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
123 | // MenuItem(title: 'Home', image: Icon(Icons.home, color: Colors.white,)),
124 | MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.white)),
125 | MenuItem(title: 'Power', image: Icon(Icons.power, color: Colors.white)),
126 | MenuItem(
127 | title: 'Setting', image: Icon(Icons.settings, color: Colors.white)),
128 | MenuItem(
129 | title: 'PopupMenu', image: Icon(Icons.menu, color: Colors.white))
130 | ],
131 | onClickMenu: onClickMenu,
132 | onDismiss: onDismiss,
133 | );
134 | menu.show(widgetKey: btnKey3);
135 | }
136 |
137 | void onGesturesDemo() {
138 | // return;
139 | Navigator.push(
140 | context,
141 | MaterialPageRoute(builder: (context) => GestureDemo()),
142 | );
143 | }
144 |
145 | void maxColumn() {
146 | PopupMenu menu = PopupMenu(
147 | context: context,
148 | config: MenuConfig(maxColumn: 3),
149 | items: [
150 | MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
151 | MenuItem(title: 'Power', image: Icon(Icons.power, color: Colors.white)),
152 | MenuItem(
153 | title: 'Setting', image: Icon(Icons.settings, color: Colors.white)),
154 | MenuItem(
155 | title: 'PopupMenu', image: Icon(Icons.menu, color: Colors.white))
156 | ],
157 | onClickMenu: onClickMenu,
158 | onDismiss: onDismiss,
159 | );
160 | menu.show(widgetKey: btnKey);
161 | }
162 |
163 | //
164 | void customBackground() {
165 | PopupMenu menu = PopupMenu(
166 | context: context,
167 | config: MenuConfig(
168 | backgroundColor: Colors.deepOrangeAccent,
169 | lineColor: Colors.black26,
170 | textStyle: TextStyle(color: Colors.black, fontSize: 10),
171 | ),
172 | items: [
173 | MenuItem(
174 | title: 'Copy',
175 | image: Image.asset('assets/copy.png', color: Colors.black)),
176 | MenuItem(title: 'Home', image: Icon(Icons.home, color: Colors.black)),
177 | MenuItem(title: 'Mail', image: Icon(Icons.mail, color: Colors.black)),
178 | MenuItem(
179 | title: 'Power', image: Icon(Icons.power, color: Colors.black)),
180 | MenuItem(
181 | title: 'Setting',
182 | textStyle: TextStyle(color: Colors.red, fontSize: 10),
183 | image: Icon(Icons.settings, color: Colors.black)),
184 | MenuItem(
185 | title: 'PopupMenu',
186 | textStyle: TextStyle(color: Colors.blue, fontSize: 10),
187 | image: Icon(Icons.menu, color: Colors.black))
188 | ],
189 | onClickMenu: onClickMenu,
190 | onDismiss: onDismiss);
191 | menu.show(widgetKey: btnKey2);
192 | }
193 |
194 | void listMenu() {
195 | PopupMenu menu = PopupMenu(
196 | context: context,
197 | config: MenuConfig.forList(),
198 | items: [
199 | // MenuItem.forList(
200 | // title: 'Copy', image: Image.asset('assets/copy.png')),
201 | MenuItem.forList(
202 | title: 'Home',
203 | image: Icon(Icons.home, color: Color(0xFF181818), size: 20)),
204 | MenuItem.forList(
205 | title: 'Mail',
206 | image: Icon(Icons.mail, color: Color(0xFF181818), size: 20)),
207 | MenuItem.forList(
208 | title: 'Power',
209 | image: Icon(Icons.power, color: Color(0xFF181818), size: 20)),
210 | MenuItem.forList(
211 | title: 'Setting',
212 | image: Icon(Icons.settings, color: Color(0xFF181818), size: 20)),
213 | MenuItem.forList(
214 | title: 'PopupMenu',
215 | image: Icon(Icons.menu, color: Color(0xFF181818), size: 20))
216 | ],
217 | onClickMenu: onClickMenu,
218 | onShow: onShow,
219 | onDismiss: onDismiss);
220 | menu.show(widgetKey: btnKey4);
221 | }
222 |
223 | void customItemWidth() {
224 | PopupMenu menu = PopupMenu(
225 | context: context,
226 | config: MenuConfig(
227 | maxColumn: 3,
228 | itemWidth: 100,
229 | ),
230 | items: [
231 | MenuItem(title: 'Copy', image: Image.asset('assets/copy.png')),
232 | MenuItem(title: 'Power', image: Icon(Icons.power, color: Colors.white)),
233 | MenuItem(
234 | title: 'Setting', image: Icon(Icons.settings, color: Colors.white)),
235 | MenuItem(
236 | title: 'PopupMenu', image: Icon(Icons.menu, color: Colors.white))
237 | ],
238 | onClickMenu: onClickMenu,
239 | onDismiss: onDismiss,
240 | );
241 | menu.show(widgetKey: customWidthKey);
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
9 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
10 | source: hosted
11 | version: "2.11.0"
12 | boolean_selector:
13 | dependency: transitive
14 | description:
15 | name: boolean_selector
16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
17 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
18 | source: hosted
19 | version: "2.1.1"
20 | characters:
21 | dependency: transitive
22 | description:
23 | name: characters
24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
25 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
26 | source: hosted
27 | version: "1.3.0"
28 | clock:
29 | dependency: transitive
30 | description:
31 | name: clock
32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
33 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
34 | source: hosted
35 | version: "1.1.1"
36 | collection:
37 | dependency: transitive
38 | description:
39 | name: collection
40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
41 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
42 | source: hosted
43 | version: "1.18.0"
44 | cupertino_icons:
45 | dependency: "direct main"
46 | description:
47 | name: cupertino_icons
48 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
49 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
50 | source: hosted
51 | version: "1.0.8"
52 | fake_async:
53 | dependency: transitive
54 | description:
55 | name: fake_async
56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
57 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
58 | source: hosted
59 | version: "1.3.1"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_test:
66 | dependency: "direct dev"
67 | description: flutter
68 | source: sdk
69 | version: "0.0.0"
70 | leak_tracker:
71 | dependency: transitive
72 | description:
73 | name: leak_tracker
74 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
75 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
76 | source: hosted
77 | version: "10.0.5"
78 | leak_tracker_flutter_testing:
79 | dependency: transitive
80 | description:
81 | name: leak_tracker_flutter_testing
82 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
83 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
84 | source: hosted
85 | version: "3.0.5"
86 | leak_tracker_testing:
87 | dependency: transitive
88 | description:
89 | name: leak_tracker_testing
90 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
91 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
92 | source: hosted
93 | version: "3.0.1"
94 | matcher:
95 | dependency: transitive
96 | description:
97 | name: matcher
98 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
99 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
100 | source: hosted
101 | version: "0.12.16+1"
102 | material_color_utilities:
103 | dependency: transitive
104 | description:
105 | name: material_color_utilities
106 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
107 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
108 | source: hosted
109 | version: "0.11.1"
110 | meta:
111 | dependency: transitive
112 | description:
113 | name: meta
114 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
115 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
116 | source: hosted
117 | version: "1.15.0"
118 | path:
119 | dependency: transitive
120 | description:
121 | name: path
122 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
123 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
124 | source: hosted
125 | version: "1.9.0"
126 | popup_menu:
127 | dependency: "direct dev"
128 | description:
129 | path: ".."
130 | relative: true
131 | source: path
132 | version: "2.0.0"
133 | sky_engine:
134 | dependency: transitive
135 | description: flutter
136 | source: sdk
137 | version: "0.0.99"
138 | source_span:
139 | dependency: transitive
140 | description:
141 | name: source_span
142 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
143 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
144 | source: hosted
145 | version: "1.10.0"
146 | stack_trace:
147 | dependency: transitive
148 | description:
149 | name: stack_trace
150 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
151 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
152 | source: hosted
153 | version: "1.11.1"
154 | stream_channel:
155 | dependency: transitive
156 | description:
157 | name: stream_channel
158 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
159 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
160 | source: hosted
161 | version: "2.1.2"
162 | string_scanner:
163 | dependency: transitive
164 | description:
165 | name: string_scanner
166 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
167 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
168 | source: hosted
169 | version: "1.2.0"
170 | term_glyph:
171 | dependency: transitive
172 | description:
173 | name: term_glyph
174 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
175 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
176 | source: hosted
177 | version: "1.2.1"
178 | test_api:
179 | dependency: transitive
180 | description:
181 | name: test_api
182 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
183 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
184 | source: hosted
185 | version: "0.7.2"
186 | vector_math:
187 | dependency: transitive
188 | description:
189 | name: vector_math
190 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
191 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
192 | source: hosted
193 | version: "2.1.4"
194 | vm_service:
195 | dependency: transitive
196 | description:
197 | name: vm_service
198 | sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
199 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
200 | source: hosted
201 | version: "14.2.5"
202 | sdks:
203 | dart: ">=3.3.0 <4.0.0"
204 | flutter: ">=3.18.0-18.0.pre.54"
205 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: popup_menu_example
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.12.0 <4.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | # The following adds the Cupertino Icons font to your application.
24 | # Use with the CupertinoIcons class for iOS style icons.
25 | cupertino_icons:
26 |
27 | dev_dependencies:
28 | flutter_test:
29 | sdk: flutter
30 |
31 | popup_menu:
32 | path: ../
33 |
34 |
35 | # For information on the generic Dart part of this file, see the
36 | # following page: https://dart.dev/tools/pub/pubspec
37 |
38 | # The following section is specific to Flutter.
39 | flutter:
40 |
41 | # The following line ensures that the Material Icons font is
42 | # included with your application, so that you can use the icons in
43 | # the material Icons class.
44 | uses-material-design: true
45 |
46 | # To add assets to your application, add an assets section, like this:
47 | assets:
48 | - assets/copy.png
49 | # - images/a_dot_ham.jpeg
50 |
51 | # An image asset can refer to one or more resolution-specific "variants", see
52 | # https://flutter.dev/assets-and-images/#resolution-aware.
53 |
54 | # For details regarding adding assets from package dependencies, see
55 | # https://flutter.dev/assets-and-images/#from-packages
56 |
57 | # To add custom fonts to your application, add a fonts section here,
58 | # in this "flutter" section. Each entry in this list should have a
59 | # "family" key with the font family name, and a "fonts" key with a
60 | # list giving the asset and other descriptors for the font. For
61 | # example:
62 | # fonts:
63 | # - family: Schyler
64 | # fonts:
65 | # - asset: fonts/Schyler-Regular.ttf
66 | # - asset: fonts/Schyler-Italic.ttf
67 | # style: italic
68 | # - family: Trajan Pro
69 | # fonts:
70 | # - asset: fonts/TrajanPro.ttf
71 | # - asset: fonts/TrajanPro_Bold.ttf
72 | # weight: 700
73 | #
74 | # For details regarding fonts from package dependencies,
75 | # see https://flutter.dev/custom-fonts/#from-packages
76 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter_test/flutter_test.dart';
9 |
10 | void main() {
11 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
12 |
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/lib/popup_menu.dart:
--------------------------------------------------------------------------------
1 | library popup_menu;
2 |
3 | export 'src/popup_menu.dart';
4 | export 'src/menu_config.dart';
5 | export 'src/menu_item.dart';
6 |
--------------------------------------------------------------------------------
/lib/src/grid_menu_layout.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 | import 'dart:ui';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:popup_menu/popup_menu.dart';
6 | import 'package:popup_menu/src/menu_layout.dart';
7 |
8 | import 'menu_item_widget.dart';
9 |
10 | /// Grid menu layout
11 | class GridMenuLayout implements MenuLayout {
12 | final MenuConfig config;
13 | final List items;
14 | final VoidCallback onDismiss;
15 | final BuildContext context;
16 | final MenuClickCallback? onClickMenu;
17 |
18 | GridMenuLayout({
19 | required this.config,
20 | required this.items,
21 | required this.onDismiss,
22 | required this.context,
23 | this.onClickMenu,
24 | }) {
25 | _calculateRowAndCol();
26 | }
27 |
28 | /// row count
29 | int _row = 1;
30 |
31 | /// col count
32 | int _col = 1;
33 |
34 | /// The max column count, default is 4.
35 | int _maxColumn = 4;
36 |
37 | /// calculate the menu row and col count
38 | void _calculateRowAndCol() {
39 | _col = _calculateColCount();
40 | _row = _calculateRowCount();
41 | }
42 |
43 | double menuWidth() {
44 | return config.itemWidth * _col;
45 | }
46 |
47 | // This height exclude the arrow
48 | double menuHeight() {
49 | return config.itemHeight * _row;
50 | }
51 |
52 | // 创建行
53 | List _createRows() {
54 | List rows = [];
55 | for (int i = 0; i < _row; i++) {
56 | Color color =
57 | (i < _row - 1 && _row != 1) ? config.lineColor : Colors.transparent;
58 | Widget rowWidget = Container(
59 | decoration:
60 | BoxDecoration(border: Border(bottom: BorderSide(color: color))),
61 | height: config.itemHeight,
62 | // width: config.itemWidth,
63 | child: Row(
64 | children: _createRowItems(i),
65 | ),
66 | );
67 |
68 | rows.add(rowWidget);
69 | }
70 |
71 | return rows;
72 | }
73 |
74 | // 创建一行的item, row 从0开始算
75 | List _createRowItems(int row) {
76 | List subItems =
77 | items.sublist(row * _col, min(row * _col + _col, items.length));
78 | List itemWidgets = [];
79 | int i = 0;
80 | for (var item in subItems) {
81 | itemWidgets.add(_createMenuItem(
82 | item,
83 | i < (_col - 1),
84 | ));
85 | i++;
86 | }
87 |
88 | return itemWidgets;
89 | }
90 |
91 | // calculate row count
92 | int _calculateRowCount() {
93 | if (items.length == 0) {
94 | debugPrint('error menu items can not be null');
95 | return 0;
96 | }
97 |
98 | int itemCount = items.length;
99 |
100 | if (_calculateColCount() == 1) {
101 | return itemCount;
102 | }
103 |
104 | int row = (itemCount - 1) ~/ _calculateColCount() + 1;
105 |
106 | return row;
107 | }
108 |
109 | // calculate col count
110 | int _calculateColCount() {
111 | assert(items.length > 0, 'error: menu items can not be null');
112 |
113 | int itemCount = items.length;
114 | if (_maxColumn != 4 && _maxColumn > 0) {
115 | return _maxColumn;
116 | }
117 |
118 | if (itemCount == 4) {
119 | // 4个显示成两行
120 | return 2;
121 | }
122 |
123 | if (itemCount <= _maxColumn) {
124 | return itemCount;
125 | }
126 |
127 | if (itemCount == 5) {
128 | return 3;
129 | }
130 |
131 | if (itemCount == 6) {
132 | return 3;
133 | }
134 |
135 | return _maxColumn;
136 | }
137 |
138 | double get screenWidth {
139 | double width = window.physicalSize.width;
140 | double ratio = window.devicePixelRatio;
141 | return width / ratio;
142 | }
143 |
144 | Widget _createMenuItem(MenuItemProvider item, bool showLine) {
145 | return MenuItemWidget(
146 | menuConfig: config,
147 | item: item,
148 | showLine: showLine,
149 | clickCallback: itemClicked,
150 | );
151 | }
152 |
153 | void itemClicked(MenuItemProvider item) {
154 | onClickMenu?.call(item);
155 | onDismiss();
156 | }
157 |
158 | @override
159 | Widget build() {
160 | return Container(
161 | width: menuWidth(),
162 | height: menuHeight(),
163 | child: Column(
164 | children: [
165 | ClipRRect(
166 | borderRadius: BorderRadius.circular(10.0),
167 | child: Container(
168 | width: menuWidth(),
169 | height: menuHeight(),
170 | decoration: BoxDecoration(
171 | color: config.backgroundColor,
172 | borderRadius: BorderRadius.circular(10.0)),
173 | child: Column(
174 | children: _createRows(),
175 | ),
176 | )),
177 | ],
178 | ),
179 | );
180 | }
181 |
182 | @override
183 | double get height => menuHeight();
184 |
185 | @override
186 | double get width => menuWidth();
187 | }
188 |
--------------------------------------------------------------------------------
/lib/src/list_menu_layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/src/menu_layout.dart';
3 |
4 | import 'menu_config.dart';
5 | import 'menu_item.dart';
6 | import 'popup_menu.dart';
7 |
8 | /// list menu layout
9 | class ListMenuLayout implements MenuLayout {
10 | final MenuConfig config;
11 | final List items;
12 | final VoidCallback onDismiss;
13 | final BuildContext context;
14 | final MenuClickCallback? onClickMenu;
15 |
16 | ListMenuLayout({
17 | required this.config,
18 | required this.items,
19 | required this.onDismiss,
20 | required this.context,
21 | this.onClickMenu,
22 | });
23 |
24 | @override
25 | Widget build() {
26 | return Container(
27 | width: width,
28 | height: height,
29 | child: Column(
30 | children: [
31 | ClipRRect(
32 | borderRadius: BorderRadius.circular(10.0),
33 | child: Container(
34 | width: width,
35 | height: height,
36 | decoration: BoxDecoration(
37 | color: config.backgroundColor,
38 | borderRadius: BorderRadius.circular(10.0)),
39 | child: Column(
40 | children: items.map((item) {
41 | return GestureDetector(
42 | onTap: () {
43 | onDismiss();
44 | onClickMenu?.call(item);
45 | },
46 | behavior: HitTestBehavior.translucent,
47 | child: Container(
48 | height: config.itemHeight,
49 | child: Row(
50 | crossAxisAlignment: CrossAxisAlignment.center,
51 | children: [
52 | Container(
53 | margin: const EdgeInsets.only(left: 10),
54 | child: item.menuImage,
55 | ),
56 | Container(
57 | alignment: Alignment.centerLeft,
58 | margin: const EdgeInsets.only(left: 10),
59 | child: Text(
60 | item.menuTitle,
61 | maxLines: 1,
62 | overflow: TextOverflow.ellipsis,
63 | style: item.menuTextStyle ?? config.textStyle,
64 | textAlign: item.menuTextAlign,
65 | ),
66 | )
67 | ],
68 | ),
69 | ),
70 | );
71 | }).toList(),
72 | ),
73 | )),
74 | ],
75 | ),
76 | );
77 | }
78 |
79 | @override
80 | double get height => config.itemHeight * items.length;
81 |
82 | @override
83 | double get width => config.itemWidth;
84 | }
85 |
--------------------------------------------------------------------------------
/lib/src/menu_config.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/src/popup_menu.dart';
3 |
4 | /// 菜单配置
5 | class MenuConfig {
6 | /// 菜单类型
7 | final MenuType type;
8 |
9 | /// 菜单的宽度
10 | final double itemWidth;
11 |
12 | /// 菜单项的高度
13 | final double itemHeight;
14 |
15 | /// 箭头的高度
16 | final double arrowHeight;
17 |
18 | /// Maximum number of columns for grid-type menu.
19 | final int maxColumn;
20 |
21 | /// 背景色
22 | final Color backgroundColor;
23 |
24 | /// The highlight color on click.
25 | final Color highlightColor;
26 |
27 | /// The color of the separator line.
28 | final Color lineColor;
29 |
30 | /// Uniformly setting the TextStyle for MenuItem will be overridden by MenuItem;
31 | /// if MenuItem does not set it, then this Style will be used.
32 | final TextStyle textStyle;
33 |
34 | /// Text alignment, only effective in List Menu.
35 | final TextAlign textAlign;
36 |
37 | const MenuConfig({
38 | this.type = MenuType.grid,
39 | this.itemWidth = 72.0,
40 | this.itemHeight = 65.0,
41 | this.arrowHeight = 10.0,
42 | this.maxColumn = 4,
43 | this.backgroundColor = const Color(0xff232323),
44 | this.highlightColor = const Color(0xff353535),
45 | this.lineColor = const Color(0x55000000),
46 | this.textStyle = const TextStyle(
47 | color: Color(0xffc5c5c5),
48 | fontSize: 10.0,
49 | ),
50 | this.textAlign = TextAlign.center,
51 | });
52 |
53 | factory MenuConfig.forList({
54 | double itemWidth = 120.0,
55 | double itemHeight = 40.0,
56 | double arrowHeight = 10.0,
57 | Color backgroundColor = Colors.white,
58 | Color highlightColor = const Color(0xff353535),
59 | Color lineColor = const Color(0x55000000),
60 | }) {
61 | return MenuConfig(
62 | type: MenuType.list,
63 | itemWidth: itemWidth,
64 | itemHeight: itemHeight,
65 | arrowHeight: arrowHeight,
66 | backgroundColor: backgroundColor,
67 | highlightColor: highlightColor,
68 | lineColor: lineColor,
69 | );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/src/menu_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class MenuItemProvider {
4 | String get menuTitle;
5 | dynamic get menuUserInfo;
6 | Widget? get menuImage;
7 | TextStyle? get menuTextStyle;
8 | TextAlign? get menuTextAlign;
9 | }
10 |
11 | /// Default menu item
12 | class MenuItem extends MenuItemProvider {
13 | final Widget? image;
14 | final String title;
15 | var userInfo; // 额外的菜单荐信息
16 | final TextStyle? textStyle;
17 | final TextAlign? textAlign;
18 |
19 | MenuItem({
20 | this.title = "",
21 | this.image,
22 | this.userInfo,
23 | this.textStyle,
24 | this.textAlign = TextAlign.center,
25 | });
26 |
27 | factory MenuItem.forList({
28 | required String title,
29 | Widget? image,
30 | dynamic userInfo,
31 | TextStyle textStyle = const TextStyle(
32 | color: Color(0xFF181818),
33 | fontSize: 10.0,
34 | ),
35 | TextAlign textAlign = TextAlign.center,
36 | }) {
37 | return MenuItem(
38 | title: title,
39 | image: image,
40 | userInfo: userInfo,
41 | textAlign: textAlign,
42 | textStyle: textStyle,
43 | );
44 | }
45 |
46 | @override
47 | Widget? get menuImage => image;
48 |
49 | @override
50 | String get menuTitle => title;
51 |
52 | @override
53 | dynamic get menuUserInfo => userInfo;
54 |
55 | @override
56 | TextStyle? get menuTextStyle => textStyle;
57 |
58 | @override
59 | TextAlign? get menuTextAlign => textAlign;
60 | }
61 |
--------------------------------------------------------------------------------
/lib/src/menu_item_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/src/popup_menu.dart';
3 |
4 | import 'menu_item.dart';
5 |
6 | class MenuItemWidget extends StatefulWidget {
7 | final MenuItemProvider item;
8 | final MenuConfig menuConfig;
9 | // 是否要显示右边的分隔线
10 | final bool showLine;
11 |
12 | final Function(MenuItemProvider item)? clickCallback;
13 |
14 | MenuItemWidget({
15 | required this.menuConfig,
16 | required this.item,
17 | this.showLine = false,
18 | this.clickCallback,
19 | });
20 |
21 | @override
22 | State createState() {
23 | return _MenuItemWidgetState();
24 | }
25 | }
26 |
27 | class _MenuItemWidgetState extends State {
28 | var highlightColor = Color(0x55000000);
29 | var color = Color(0xff232323);
30 |
31 | @override
32 | void initState() {
33 | color = widget.menuConfig.backgroundColor;
34 | highlightColor = widget.menuConfig.highlightColor;
35 | super.initState();
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return GestureDetector(
41 | onTapDown: (details) {
42 | color = highlightColor;
43 | setState(() {});
44 | },
45 | onTapUp: (details) {
46 | color = widget.menuConfig.backgroundColor;
47 | setState(() {});
48 | },
49 | onLongPressEnd: (details) {
50 | color = widget.menuConfig.backgroundColor;
51 | setState(() {});
52 | },
53 | onTap: () {
54 | if (widget.clickCallback != null) {
55 | widget.clickCallback!(widget.item);
56 | }
57 | },
58 | child: Container(
59 | width: widget.menuConfig.itemWidth,
60 | height: widget.menuConfig.itemHeight,
61 | decoration: BoxDecoration(
62 | color: color,
63 | border: Border(
64 | right: BorderSide(
65 | color: widget.showLine
66 | ? widget.menuConfig.lineColor
67 | : Colors.transparent))),
68 | child: _createContent()),
69 | );
70 | }
71 |
72 | Widget _createContent() {
73 | if (widget.item.menuImage != null) {
74 | // image and text
75 | return Column(
76 | mainAxisAlignment: MainAxisAlignment.center,
77 | children: [
78 | Container(
79 | width: 30.0,
80 | height: 30.0,
81 | child: widget.item.menuImage,
82 | ),
83 | Container(
84 | height: 22.0,
85 | child: Material(
86 | color: Colors.transparent,
87 | child: Text(
88 | widget.item.menuTitle,
89 | style: widget.item.menuTextStyle ?? widget.menuConfig.textStyle,
90 | ),
91 | ),
92 | )
93 | ],
94 | );
95 | } else {
96 | // only text
97 | return Container(
98 | child: Center(
99 | child: Material(
100 | color: Colors.transparent,
101 | child: Text(
102 | widget.item.menuTitle,
103 | style: widget.item.menuTextStyle ?? widget.menuConfig.textStyle,
104 | textAlign:
105 | widget.item.menuTextAlign ?? widget.menuConfig.textAlign,
106 | ),
107 | ),
108 | ),
109 | );
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/src/menu_layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:popup_menu/popup_menu.dart';
3 |
4 | abstract class MenuLayout {
5 | /// 菜单的宽度
6 | double get width;
7 |
8 | /// 菜单的高度,不包含箭头
9 | double get height;
10 |
11 | /// 创建菜单内容,不包含箭头
12 | Widget build();
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/popup_menu.dart:
--------------------------------------------------------------------------------
1 | import 'dart:core';
2 | import 'dart:ui';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:popup_menu/src/grid_menu_layout.dart';
6 | import 'package:popup_menu/src/list_menu_layout.dart';
7 | import 'package:popup_menu/src/menu_config.dart';
8 | import 'package:popup_menu/src/menu_layout.dart';
9 | import 'package:popup_menu/src/triangle_painter.dart';
10 | import 'package:popup_menu/src/utils.dart';
11 | import 'menu_item.dart';
12 |
13 | export 'menu_item.dart';
14 | export 'menu_config.dart';
15 |
16 | enum MenuType {
17 | /// 格子
18 | grid,
19 |
20 | /// 单列
21 | list
22 | }
23 |
24 | typedef MenuClickCallback = void Function(MenuItemProvider item);
25 |
26 | class PopupMenu {
27 | OverlayEntry? _entry;
28 | late List items;
29 |
30 | /// callback
31 | final VoidCallback? onDismiss;
32 | final MenuClickCallback? onClickMenu;
33 | final VoidCallback? onShow;
34 |
35 | /// Cannot be null
36 | BuildContext context;
37 |
38 | /// It's showing or not.
39 | bool _isShow = false;
40 | bool get isShow => _isShow;
41 |
42 | final MenuConfig config;
43 | Size _screenSize = window.physicalSize / window.devicePixelRatio;
44 |
45 | PopupMenu({
46 | required this.context,
47 | required this.items,
48 | this.config = const MenuConfig(),
49 | this.onClickMenu,
50 | this.onDismiss,
51 | this.onShow,
52 | });
53 |
54 | MenuLayout? menuLayout;
55 |
56 | void show({
57 | Rect? rect,
58 | GlobalKey? widgetKey,
59 | }) {
60 | assert(rect != null || widgetKey != null,
61 | "'rect' and 'key' can't be both null");
62 |
63 | final attachRect = rect ?? getWidgetGlobalRect(widgetKey!);
64 |
65 | if (config.type == MenuType.grid) {
66 | menuLayout = GridMenuLayout(
67 | config: config,
68 | items: this.items,
69 | onDismiss: dismiss,
70 | context: context,
71 | onClickMenu: onClickMenu,
72 | );
73 | } else if (config.type == MenuType.list) {
74 | menuLayout = ListMenuLayout(
75 | config: config,
76 | items: items,
77 | onDismiss: dismiss,
78 | context: context,
79 | onClickMenu: onClickMenu,
80 | );
81 | }
82 |
83 | _LayoutP layoutp = _calculateOffset(
84 | context,
85 | attachRect,
86 | menuLayout!.width,
87 | menuLayout!.height,
88 | );
89 |
90 | _entry = OverlayEntry(builder: (context) {
91 | return build(layoutp, menuLayout!);
92 | });
93 |
94 | Overlay.of(context)!.insert(_entry!);
95 | _isShow = true;
96 | onShow?.call();
97 | }
98 |
99 | Widget build(_LayoutP layoutp, MenuLayout menu) {
100 | return GestureDetector(
101 | behavior: HitTestBehavior.translucent,
102 | onTap: () {
103 | dismiss();
104 | },
105 | onVerticalDragStart: (DragStartDetails details) {
106 | dismiss();
107 | },
108 | onHorizontalDragStart: (DragStartDetails details) {
109 | dismiss();
110 | },
111 | child: Material(
112 | color: Colors.transparent,
113 | child: Container(
114 | child: Stack(
115 | children: [
116 | // triangle arrow
117 | Positioned(
118 | left: layoutp.attachRect.left +
119 | layoutp.attachRect.width / 2.0 -
120 | 7.5,
121 | top: layoutp.isDown
122 | ? layoutp.offset.dy + layoutp.height
123 | : layoutp.offset.dy - config.arrowHeight,
124 | child: CustomPaint(
125 | size: Size(15.0, config.arrowHeight),
126 | painter: TrianglePainter(
127 | isDown: layoutp.isDown, color: config.backgroundColor),
128 | ),
129 | ),
130 | // menu content
131 | Positioned(
132 | left: layoutp.offset.dx,
133 | top: layoutp.offset.dy,
134 | child: menu.build(),
135 | )
136 | ],
137 | ),
138 | )),
139 | );
140 | }
141 |
142 | /// 计算布局位置
143 | _LayoutP _calculateOffset(
144 | BuildContext context,
145 | Rect attachRect,
146 | double contentWidth,
147 | double contentHeight,
148 | ) {
149 | double dx = attachRect.left + attachRect.width / 2.0 - contentWidth / 2.0;
150 | if (dx < 10.0) {
151 | dx = 10.0;
152 | }
153 |
154 | if (dx + contentWidth > _screenSize.width && dx > 10.0) {
155 | double tempDx = _screenSize.width - contentWidth - 10;
156 | if (tempDx > 10) {
157 | dx = tempDx;
158 | }
159 | }
160 |
161 | double dy = attachRect.top - contentHeight;
162 | bool isDown = false;
163 | if (dy <= MediaQuery.of(context).padding.top + 10) {
164 | // The have not enough space above, show menu under the widget.
165 | dy = config.arrowHeight + attachRect.height + attachRect.top;
166 | isDown = false;
167 | } else {
168 | dy -= config.arrowHeight;
169 | isDown = true;
170 | }
171 |
172 | return _LayoutP(
173 | width: contentWidth,
174 | height: contentHeight,
175 | attachRect: attachRect,
176 | offset: Offset(dx, dy),
177 | isDown: isDown,
178 | );
179 | }
180 |
181 | void dismiss() {
182 | if (!_isShow) {
183 | // Remove method should only be called once
184 | return;
185 | }
186 |
187 | _entry?.remove();
188 | _isShow = false;
189 | onDismiss?.call();
190 | }
191 | }
192 |
193 | class _LayoutP {
194 | double width;
195 | double height;
196 | Offset offset;
197 | Rect attachRect;
198 | bool isDown;
199 |
200 | _LayoutP({
201 | required this.width,
202 | required this.height,
203 | required this.offset,
204 | required this.attachRect,
205 | required this.isDown,
206 | });
207 | }
208 |
--------------------------------------------------------------------------------
/lib/src/triangle_painter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/rendering.dart';
2 |
3 | // 画弹出菜单下面的三角形
4 | class TrianglePainter extends CustomPainter {
5 | bool isDown;
6 | Color color;
7 |
8 | TrianglePainter({
9 | this.isDown = true,
10 | this.color = const Color.fromARGB(0, 0, 0, 0),
11 | });
12 |
13 | @override
14 | void paint(Canvas canvas, Size size) {
15 | Paint _paint = new Paint();
16 | _paint.strokeWidth = 2.0;
17 | _paint.color = color;
18 | _paint.style = PaintingStyle.fill;
19 |
20 | Path path = new Path();
21 | if (isDown) {
22 | path.moveTo(0.0, -1.0);
23 | path.lineTo(size.width, -1.0);
24 | path.lineTo(size.width / 2.0, size.height);
25 | } else {
26 | path.moveTo(size.width / 2.0, 0.0);
27 | path.lineTo(0.0, size.height + 1);
28 | path.lineTo(size.width, size.height + 1);
29 | }
30 |
31 | canvas.drawPath(path, _paint);
32 | }
33 |
34 | @override
35 | bool shouldRepaint(CustomPainter oldDelegate) {
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | Rect getWidgetGlobalRect(GlobalKey key) {
4 | assert(key.currentContext != null, '');
5 |
6 | RenderBox renderBox = key.currentContext!.findRenderObject() as RenderBox;
7 | var offset = renderBox.localToGlobal(Offset.zero);
8 | return Rect.fromLTWH(
9 | offset.dx, offset.dy, renderBox.size.width, renderBox.size.height);
10 | }
11 |
--------------------------------------------------------------------------------
/popupmenu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinabrant/popup_menu/704309e791c9559209235cb1745d99a9f7497ea7/popupmenu.png
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
9 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
10 | source: hosted
11 | version: "2.11.0"
12 | boolean_selector:
13 | dependency: transitive
14 | description:
15 | name: boolean_selector
16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
17 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
18 | source: hosted
19 | version: "2.1.1"
20 | characters:
21 | dependency: transitive
22 | description:
23 | name: characters
24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
25 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
26 | source: hosted
27 | version: "1.3.0"
28 | clock:
29 | dependency: transitive
30 | description:
31 | name: clock
32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
33 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
34 | source: hosted
35 | version: "1.1.1"
36 | collection:
37 | dependency: transitive
38 | description:
39 | name: collection
40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
41 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
42 | source: hosted
43 | version: "1.18.0"
44 | fake_async:
45 | dependency: transitive
46 | description:
47 | name: fake_async
48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
49 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
50 | source: hosted
51 | version: "1.3.1"
52 | flutter:
53 | dependency: "direct main"
54 | description: flutter
55 | source: sdk
56 | version: "0.0.0"
57 | flutter_test:
58 | dependency: "direct dev"
59 | description: flutter
60 | source: sdk
61 | version: "0.0.0"
62 | leak_tracker:
63 | dependency: transitive
64 | description:
65 | name: leak_tracker
66 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
67 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
68 | source: hosted
69 | version: "10.0.5"
70 | leak_tracker_flutter_testing:
71 | dependency: transitive
72 | description:
73 | name: leak_tracker_flutter_testing
74 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
75 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
76 | source: hosted
77 | version: "3.0.5"
78 | leak_tracker_testing:
79 | dependency: transitive
80 | description:
81 | name: leak_tracker_testing
82 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
83 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
84 | source: hosted
85 | version: "3.0.1"
86 | matcher:
87 | dependency: transitive
88 | description:
89 | name: matcher
90 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
91 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
92 | source: hosted
93 | version: "0.12.16+1"
94 | material_color_utilities:
95 | dependency: transitive
96 | description:
97 | name: material_color_utilities
98 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
99 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
100 | source: hosted
101 | version: "0.11.1"
102 | meta:
103 | dependency: transitive
104 | description:
105 | name: meta
106 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
107 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
108 | source: hosted
109 | version: "1.15.0"
110 | path:
111 | dependency: transitive
112 | description:
113 | name: path
114 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
115 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
116 | source: hosted
117 | version: "1.9.0"
118 | sky_engine:
119 | dependency: transitive
120 | description: flutter
121 | source: sdk
122 | version: "0.0.99"
123 | source_span:
124 | dependency: transitive
125 | description:
126 | name: source_span
127 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
128 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
129 | source: hosted
130 | version: "1.10.0"
131 | stack_trace:
132 | dependency: transitive
133 | description:
134 | name: stack_trace
135 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
136 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
137 | source: hosted
138 | version: "1.11.1"
139 | stream_channel:
140 | dependency: transitive
141 | description:
142 | name: stream_channel
143 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
144 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
145 | source: hosted
146 | version: "2.1.2"
147 | string_scanner:
148 | dependency: transitive
149 | description:
150 | name: string_scanner
151 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
152 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
153 | source: hosted
154 | version: "1.2.0"
155 | term_glyph:
156 | dependency: transitive
157 | description:
158 | name: term_glyph
159 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
160 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
161 | source: hosted
162 | version: "1.2.1"
163 | test_api:
164 | dependency: transitive
165 | description:
166 | name: test_api
167 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
168 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
169 | source: hosted
170 | version: "0.7.2"
171 | vector_math:
172 | dependency: transitive
173 | description:
174 | name: vector_math
175 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
176 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
177 | source: hosted
178 | version: "2.1.4"
179 | vm_service:
180 | dependency: transitive
181 | description:
182 | name: vm_service
183 | sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
184 | url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
185 | source: hosted
186 | version: "14.2.5"
187 | sdks:
188 | dart: ">=3.3.0 <4.0.0"
189 | flutter: ">=3.18.0-18.0.pre.54"
190 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: popup_menu
2 | description: A Flutter popup menu.Writted with pure dart, supported both iOS and Android.
3 | version: 2.1.0
4 | homepage: https://github.com/chinabrant/popup_menu
5 |
6 | environment:
7 | sdk: ">=2.12.0 <4.0.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 |
13 | dev_dependencies:
14 | flutter_test:
15 | sdk: flutter
16 |
17 | # For information on the generic Dart part of this file, see the
18 | # following page: https://dart.dev/tools/pub/pubspec
19 |
20 | # The following section is specific to Flutter.
21 | flutter:
22 |
23 | # To add assets to your package, add an assets section, like this:
24 | # assets:
25 | # - images/a_dot_ham.jpeg
26 | #
27 | # For details regarding assets in packages, see
28 | # https://flutter.dev/assets-and-images/#from-packages
29 | #
30 | # An image asset can refer to one or more resolution-specific "variants", see
31 | # https://flutter.dev/assets-and-images/#resolution-aware.
32 |
33 | # To add custom fonts to your package, add a fonts section here,
34 | # in this "flutter" section. Each entry in this list should have a
35 | # "family" key with the font family name, and a "fonts" key with a
36 | # list giving the asset and other descriptors for the font. For
37 | # example:
38 | # fonts:
39 | # - family: Schyler
40 | # fonts:
41 | # - asset: fonts/Schyler-Regular.ttf
42 | # - asset: fonts/Schyler-Italic.ttf
43 | # style: italic
44 | # - family: Trajan Pro
45 | # fonts:
46 | # - asset: fonts/TrajanPro.ttf
47 | # - asset: fonts/TrajanPro_Bold.ttf
48 | # weight: 700
49 | #
50 | # For details regarding fonts in packages, see
51 | # https://flutter.dev/custom-fonts/#from-packages
52 |
--------------------------------------------------------------------------------
/test/popup_menu_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_test/flutter_test.dart';
2 |
3 | import 'package:popup_menu/src/popup_menu.dart';
4 |
5 | void main() {
6 | test('adds one to input values', () {});
7 | }
8 |
--------------------------------------------------------------------------------