├── .flutter-plugins-dependencies ├── .gitignore ├── .metadata ├── README.md ├── Scheme.md ├── android ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_share │ │ │ │ └── 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 └── settings_aar.gradle ├── assets └── data │ └── users.json ├── images ├── aone.jpg ├── athree.jpg ├── atwo.jpg ├── avatar.jpg ├── barchart.jpg ├── bg.jpg ├── linechart.png └── piechart.jpg ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter.podspec │ └── Release.xcconfig ├── Podfile ├── 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 ├── FutureBuilderProblem │ └── FutureBuilderMain.dart ├── animatedIcon │ └── AnimatedIconPage.dart ├── animatedSwitcher │ ├── AnimatedSwitcherCounterRoute.dart │ └── SlideTransitionX.dart ├── autocomplete │ ├── CountriesField.dart │ └── OverlayMain.dart ├── chartsDisplay │ ├── ChartDispalyMain.dart │ ├── bar_chart.dart │ ├── grades_data.dart │ ├── line_chart.dart │ ├── pie_chart.dart │ ├── population_data.dart │ └── sales_data.dart ├── downloadDemo │ └── DownDemoMain.dart ├── flutterSearch │ └── searchbarview.dart ├── heroAnimation │ ├── HeroAnimPage.dart │ ├── HeroAnimationRouteB.dart │ ├── Photo.dart │ ├── RadialExpansion.dart │ └── RadialExpansionDemo.dart ├── implicitAnimation │ ├── AnimatedContainerDemo.dart │ └── FadeInDemo.dart ├── main.dart ├── navigationrail │ └── NavigationRailMain.dart ├── nestedScrollView │ ├── DemoOne.dart │ └── DemoTwo.dart ├── path │ ├── CircleProgressBarPainter.dart │ ├── Circles.dart │ ├── DashLinePainter.dart │ ├── LinePainter.dart │ ├── PathAdvancedMain.dart │ ├── PathBasicsMain.dart │ ├── PathPainter.dart │ ├── Planets.dart │ ├── Polygon.dart │ └── Spiral.dart ├── perspective │ ├── FlipAnimationMain.dart │ ├── FlipPanel.dart │ ├── FlipWidget.dart │ └── PerspectiveMain.dart ├── refreshData │ └── refresh_data.dart ├── scheme │ ├── home_index.dart │ ├── router.dart │ ├── user_index.dart │ └── web_view_page.dart ├── stateManager │ ├── BasicCounter.dart │ ├── BasicUse │ │ └── provider_basic.dart │ ├── EventProvider.dart │ ├── User.dart │ ├── UserList.dart │ ├── common │ │ └── theme.dart │ ├── index_main.dart │ ├── models │ │ ├── cart.dart │ │ └── catalog.dart │ ├── my_event_page.dart │ ├── my_userpage.dart │ ├── screens │ │ ├── cart.dart │ │ └── catalog.dart │ └── user_provider.dart └── utils │ └── json_config.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_webview_plugin","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.0+2/","dependencies":[]},{"name":"path_provider","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.9/","dependencies":[]},{"name":"simple_permissions","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/simple_permissions-0.1.9/","dependencies":[]},{"name":"uni_links","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/uni_links-0.4.0/","dependencies":[]}],"android":[{"name":"flutter_webview_plugin","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.0+2/","dependencies":[]},{"name":"path_provider","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.9/","dependencies":[]},{"name":"simple_permissions","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/simple_permissions-0.1.9/","dependencies":[]},{"name":"uni_links","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/uni_links-0.4.0/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/wanghaichao/Develop/FlutterSDK/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_macos-0.0.4+3/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_webview_plugin","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"simple_permissions","dependencies":[]},{"name":"uni_links","dependencies":[]}],"date_created":"2021-02-16 11:05:53.962445","version":"1.22.6"} -------------------------------------------------------------------------------- /.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/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /.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: 78cca6250a7104cc1dd89edf1982878530e55ee6 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | flutter sdk 升级为最新版本。 2 | 3 | 打开 Android 项目,同步代码,并迁移至 Androidx。 4 | 5 | 6 | === 7 | 8 | 9 | 10 | [1、RefreshIndicator+FutureBuilder 实现下拉刷新上滑加载数据](https://juejin.im/post/5d6b26755188255d3d29acea) 11 | 12 | [2、NestedScrollView 和 SliverAppBar 的使用](https://juejin.im/post/5d71091a6fb9a06af824fbad) 13 | 14 | [3、Flutter 全局状态管理之 Provider 初探](https://juejin.im/post/5d8f324ee51d45781e0f5dca) 15 | 16 | [4、Flutter showSearch 与 AnimatedIcon 的使用](https://juejin.im/post/5da27fd86fb9a04dd95e846d) 17 | 18 | [5、Flutter Provider 之 FutureProvider 与 StreamProvider](https://juejin.im/post/5dea6259f265da33c14d0951) 19 | 20 | [6、Flutter 图表绘制](https://juejin.im/post/5e7eafc26fb9a03c53517244) 21 | 22 | [7、Flutter 使用 Overlay 实现全局弹窗](https://juejin.im/post/5e87f43051882573cd41a342) 23 | 24 | [8、Flutter 3D 动画](https://juejin.im/post/5e90739ee51d4546fd48169a) 25 | 26 | [9、停止 FutrueBuilder 的重复刷新和执行](https://juejin.im/post/5e9a95f4e51d4546eb52566b) 27 | 28 | [10、Path 基础 ](https://juejin.im/post/5ea2f88851882573be11e082) 29 | 30 | [11、Path 进阶 ](https://juejin.im/post/5eaf85c6e51d454ddc100f97) 31 | 32 | [12、实现文件下载 ](https://juejin.im/post/5eab9b376fb9a0434a2e55a8) 33 | 34 | [13、Flutter 使用 Github 进行 CI/CD](https://juejin.im/post/5ebfaeac6fb9a0435a01e241) 35 | 36 | [14、Flutter NavigationRail Demo](https://juejin.im/post/5ed10da66fb9a0479a800c5e) 37 | 38 | 39 | [15、Flutter 隐式动画](https://juejin.im/post/5eecc7baf265da028e749f47) 40 | 41 | [16、Widget、RenderObject 与 Element](https://juejin.im/post/5eff34c76fb9a07e8b2137f2) 42 | 43 | [17、Hero 动画](https://juejin.im/post/6861533747716554766) 44 | 45 | -------------------------------------------------------------------------------- /Scheme.md: -------------------------------------------------------------------------------- 1 | #### 一、GitHub 上配置一个 html(或者任何本地可以打开的 html 都可以) 2 | 3 | github 上 setting 上 GitHub Pages 可以看到 html 的 访问链接 4 | ``` 5 | 6 | 7 | 8 | 9 | 10 | Scheme 跳转 11 | 17 | 18 | 19 | 20 |

tyfapp://

21 |

22 | 23 | 打开App(tyfapp://) 24 | 25 |

26 |

tyfapp://homepage

27 |

28 | 29 | 打开App首页 30 | 31 |

32 |

tyfapp://userpage

33 |

34 | 35 | 打开App跳转到个人详情页面 36 | 37 |

38 | 39 | 40 | ``` 41 | 42 | 43 | #### 二、flutter 端配置 44 | main 中需要配置 router 45 | ``` 46 | routes: MyRouter().registerRouter(), 47 | ``` 48 | 49 | 外部链接跳转逻辑 50 | ``` 51 | /// 使用[String]链接实现 52 | Future initPlatformStateForStringUniLinks() async { 53 | String initialLink; 54 | // Platform messages may fail, so we use a try/catch PlatformException. 55 | try { 56 | initialLink = await getInitialLink(); 57 | if (initialLink != null) { 58 | // 跳转到指定页面 59 | router.push(context, initialLink); 60 | } 61 | } on PlatformException { 62 | initialLink = 'Failed to get initial link.'; 63 | } on FormatException { 64 | initialLink = 'Failed to parse the initial link as Uri.'; 65 | } 66 | // Attach a listener to the links stream 67 | _sub = getLinksStream().listen((String link) { 68 | if (!mounted || link == null) return; 69 | // 跳转到指定页面 70 | router.push(context, link); 71 | }, onError: (Object err) { 72 | if (!mounted) return; 73 | }); 74 | } 75 | 76 | 77 | ``` 78 | 79 | 80 | 81 | #### 三 、Android 端配置 82 | ``` 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | ``` 96 | 97 | #### 四、iOS 中配置 98 | ios/Runner/info.plist 99 | 100 | 在 dict 内增加下面的配置: 101 | 102 | 103 | ``` 104 | CFBundleURLTypes 105 | 106 | 107 | 108 | 109 | 110 | CFBundleTypeRole 111 | 112 | Editor 113 | 114 | CFBundleURLName 115 | 116 | Two You 117 | 118 | CFBundleURLSchemes 119 | 120 | 121 | 122 | tyfapp 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | ``` -------------------------------------------------------------------------------- /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.flutter_share" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "androidx.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 'androidx.test:runner:1.1.0' 60 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' 61 | } 62 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/flutter_share/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.flutter_share; 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 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { url 'https://maven.aliyun.com/repository/public/' } 4 | maven { 5 | url 'http://download.flutter.io' 6 | } 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.2.1' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | maven { url 'https://maven.aliyun.com/repository/public/' } 19 | google() 20 | jcenter() 21 | maven { 22 | url 'http://download.flutter.io' 23 | } 24 | } 25 | } 26 | 27 | rootProject.buildDir = '../build' 28 | subprojects { 29 | project.buildDir = "${rootProject.buildDir}/${project.name}" 30 | } 31 | subprojects { 32 | project.evaluationDependsOn(':app') 33 | } 34 | 35 | task clean(type: Delete) { 36 | delete rootProject.buildDir 37 | } 38 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | 3 | android.enableR8=true 4 | android.useAndroidX=true 5 | android.enableJetifier=true 6 | 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /assets/data/users.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "first_name": "Douglas", 5 | "last_name": "Tober", 6 | "website": "Codetober.com" 7 | }, 8 | { 9 | "first_name": "Brad", 10 | "last_name": "Traversy", 11 | "website": "traversymedia.com" 12 | }, 13 | { 14 | "first_name": "Bucky", 15 | "last_name": "Roberts", 16 | "website": "lhventures.us" 17 | }, 18 | { 19 | "first_name": "Doug", 20 | "last_name": "Tober", 21 | "website": "j5technology.com" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /images/aone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/aone.jpg -------------------------------------------------------------------------------- /images/athree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/athree.jpg -------------------------------------------------------------------------------- /images/atwo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/atwo.jpg -------------------------------------------------------------------------------- /images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/avatar.jpg -------------------------------------------------------------------------------- /images/barchart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/barchart.jpg -------------------------------------------------------------------------------- /images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/bg.jpg -------------------------------------------------------------------------------- /images/linechart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/linechart.png -------------------------------------------------------------------------------- /images/piechart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/images/piechart.jpg -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 32 | end 33 | 34 | post_install do |installer| 35 | installer.pods_project.targets.each do |target| 36 | flutter_additional_ios_build_settings(target) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcc007/FlutterShare/e1a417df3491722c915ac7bf70190f5803e6d200/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_share 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 | 45 | CFBundleURLTypes 46 | 47 | 48 | 49 | 50 | 51 | CFBundleTypeRole 52 | 53 | Editor 54 | 55 | CFBundleURLName 56 | 57 | Two You 58 | 59 | CFBundleURLSchemes 60 | 61 | 62 | 63 | tyfapp 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/FutureBuilderProblem/FutureBuilderMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:async/async.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_share/perspective/FlipWidget.dart'; 4 | 5 | 6 | class FutureBuilderMain extends StatefulWidget { 7 | @override 8 | _FutureBuilderMainMainState createState() => _FutureBuilderMainMainState(); 9 | } 10 | 11 | class _FutureBuilderMainMainState extends State { 12 | 13 | 14 | bool _switchValue; 15 | final AsyncMemoizer _memoizer = AsyncMemoizer(); 16 | 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | this._switchValue = false; 22 | 23 | } 24 | 25 | 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | 30 | 31 | return new Scaffold( 32 | 33 | body: Column( 34 | mainAxisAlignment: MainAxisAlignment.center, 35 | children: [ 36 | Switch( 37 | value: this._switchValue, 38 | onChanged: (newValue) { 39 | setState(() { 40 | this._switchValue = newValue; 41 | }); 42 | }, 43 | 44 | 45 | 46 | ), 47 | FutureBuilder( 48 | future: this._fetchData(_switchValue), 49 | builder: (context, snapshot) { 50 | switch (snapshot.connectionState) { 51 | case ConnectionState.none: 52 | case ConnectionState.waiting: 53 | return Center( 54 | child: CircularProgressIndicator() 55 | ); 56 | default: 57 | return Center( 58 | child: Text(snapshot.data) 59 | ); 60 | } 61 | } 62 | ), 63 | ], 64 | ), 65 | 66 | ); 67 | 68 | 69 | } 70 | 71 | _fetchData(bool flag) async{ 72 | if(flag){ 73 | return this._memoizer.runOnce(() async { 74 | await Future.delayed(Duration(seconds: 2)); 75 | return 'REMOTE DATA'; 76 | }); 77 | }else{ 78 | await Future.delayed(Duration(seconds: 5)); 79 | return 'REMOTE DATA'; 80 | } 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /lib/animatedIcon/AnimatedIconPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedIconPage extends StatefulWidget { 4 | @override 5 | _AnimatedIconPageState createState() => _AnimatedIconPageState(); 6 | } 7 | 8 | class _AnimatedIconPageState extends State 9 | with SingleTickerProviderStateMixin { 10 | 11 | AnimationController controller; 12 | List _icons; 13 | List _names; 14 | 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | controller = AnimationController(vsync: this) 20 | ..drive(Tween(begin: 0, end: 1)) 21 | ..duration = Duration(milliseconds: 500); 22 | 23 | _names = [ 24 | 'play_pause', 25 | 'add_event', 26 | 'arrow_menu', 27 | 'close_menu', 28 | 'ellipsis_search', 29 | 'event_add', 30 | 'home_menu', 31 | 'list_view', 32 | 'menu_arrow', 33 | 'menu_close', 34 | 'menu_home', 35 | 'pause_play', 36 | 'search_ellipsis', 37 | 'view_list', 38 | ]; 39 | 40 | 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | 46 | _icons = [ 47 | AnimatedIcon( 48 | icon: AnimatedIcons.play_pause, 49 | progress: controller, 50 | size: 35, 51 | semanticLabel: "play_pause", 52 | ), 53 | AnimatedIcon( 54 | icon: AnimatedIcons.add_event, 55 | progress: controller, 56 | size: 35, 57 | ), 58 | AnimatedIcon( 59 | icon: AnimatedIcons.arrow_menu, 60 | progress: controller, 61 | size: 35, 62 | ), 63 | AnimatedIcon( 64 | icon: AnimatedIcons.close_menu, 65 | progress: controller, 66 | size: 35, 67 | ), 68 | AnimatedIcon( 69 | icon: AnimatedIcons.ellipsis_search, 70 | progress: controller, 71 | size: 35, 72 | ), 73 | AnimatedIcon( 74 | icon: AnimatedIcons.event_add, 75 | progress: controller, 76 | size: 35, 77 | ), 78 | AnimatedIcon( 79 | icon: AnimatedIcons.home_menu, 80 | progress: controller, 81 | size: 35, 82 | ), 83 | AnimatedIcon( 84 | icon: AnimatedIcons.list_view, 85 | progress: controller, 86 | size: 35, 87 | ), 88 | AnimatedIcon( 89 | icon: AnimatedIcons.menu_arrow, 90 | progress: controller, 91 | size: 35, 92 | ), 93 | AnimatedIcon( 94 | icon: AnimatedIcons.menu_close, 95 | progress: controller, 96 | size: 35, 97 | ), 98 | AnimatedIcon( 99 | icon: AnimatedIcons.menu_home, 100 | progress: controller, 101 | size: 35, 102 | ), 103 | AnimatedIcon( 104 | icon: AnimatedIcons.pause_play, 105 | progress: controller, 106 | size: 35, 107 | ), 108 | AnimatedIcon( 109 | icon: AnimatedIcons.search_ellipsis, 110 | progress: controller, 111 | size: 35, 112 | ), 113 | AnimatedIcon( 114 | icon: AnimatedIcons.view_list, 115 | progress: controller, 116 | size: 35, 117 | ), 118 | ]; 119 | 120 | 121 | return Scaffold( 122 | appBar: AppBar( 123 | title: Text('AnimatedIconPage'), 124 | ), 125 | //body: _buildPausePlayIcon(), 126 | body: _buildGridView(), 127 | ); 128 | } 129 | 130 | Widget _buildGridView() { 131 | return GridView.builder( 132 | itemCount: _icons.length, 133 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 134 | crossAxisCount: 3, 135 | mainAxisSpacing: 10, 136 | crossAxisSpacing: 10, 137 | ), 138 | itemBuilder: (context, index) { 139 | return Center( 140 | child: Column( 141 | mainAxisSize: MainAxisSize.min, 142 | children: [ 143 | 144 | InkWell( 145 | child: _icons[index], 146 | 147 | onTap: () { 148 | if (controller.status == AnimationStatus.completed) { 149 | controller.reverse(); 150 | } else if (controller.status == AnimationStatus.dismissed) { 151 | controller.forward(); 152 | } 153 | }, 154 | ), 155 | 156 | Padding( 157 | padding: const EdgeInsets.only(top: 20.0), 158 | child: Text(_names[index]), 159 | ), 160 | ], 161 | ), 162 | ); 163 | }, 164 | ); 165 | } 166 | 167 | 168 | @override 169 | void dispose() { 170 | super.dispose(); 171 | controller.dispose(); 172 | } 173 | } -------------------------------------------------------------------------------- /lib/animatedSwitcher/AnimatedSwitcherCounterRoute.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'SlideTransitionX.dart'; 4 | 5 | class AnimatedSwitcherCounterRoute extends StatefulWidget { 6 | const AnimatedSwitcherCounterRoute({Key key}) : super(key: key); 7 | 8 | @override 9 | _AnimatedSwitcherCounterRouteState createState() => _AnimatedSwitcherCounterRouteState(); 10 | } 11 | 12 | class _AnimatedSwitcherCounterRouteState extends State { 13 | int _count = 0; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Center( 18 | child: Column( 19 | mainAxisAlignment: MainAxisAlignment.center, 20 | children: [ 21 | AnimatedSwitcher( 22 | duration: const Duration(milliseconds: 500), 23 | transitionBuilder: (Widget child, Animation animation) { 24 | 25 | ///缩放动画 26 | // return ScaleTransition(child: child, scale: animation); 27 | 28 | ///上下左右平移动画 29 | return SlideTransitionX( 30 | child: child, 31 | direction: AxisDirection.up, //上入下出 32 | position: animation, 33 | ); 34 | 35 | }, 36 | child: Text( 37 | '$_count', 38 | //显示指定key,不同的key会被认为是不同的Text,这样才能执行动画 39 | key: ValueKey(_count), 40 | style: Theme.of(context).textTheme.display1, 41 | ), 42 | ), 43 | 44 | 45 | RaisedButton( 46 | child: const Text('+1',), 47 | onPressed: () { 48 | setState(() { 49 | _count += 1; 50 | }); 51 | }, 52 | ), 53 | 54 | 55 | ], 56 | ), 57 | ); 58 | } 59 | } -------------------------------------------------------------------------------- /lib/animatedSwitcher/SlideTransitionX.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SlideTransitionX extends AnimatedWidget { 4 | SlideTransitionX({ 5 | Key key, 6 | @required Animation position, 7 | this.transformHitTests = true, 8 | this.direction = AxisDirection.down, 9 | this.child, 10 | }) 11 | : assert(position != null), 12 | super(key: key, listenable: position) { 13 | // 偏移在内部处理 14 | switch (direction) { 15 | case AxisDirection.up: 16 | _tween = Tween(begin: Offset(0, 1), end: Offset(0, 0)); 17 | break; 18 | case AxisDirection.right: 19 | _tween = Tween(begin: Offset(-1, 0), end: Offset(0, 0)); 20 | break; 21 | case AxisDirection.down: 22 | _tween = Tween(begin: Offset(0, -1), end: Offset(0, 0)); 23 | break; 24 | case AxisDirection.left: 25 | _tween = Tween(begin: Offset(1, 0), end: Offset(0, 0)); 26 | break; 27 | } 28 | } 29 | 30 | 31 | Animation get position => listenable; 32 | 33 | final bool transformHitTests; 34 | 35 | final Widget child; 36 | 37 | //退场(出)方向 38 | final AxisDirection direction; 39 | 40 | Tween _tween; 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | Offset offset = _tween.evaluate(position); 45 | if (position.status == AnimationStatus.reverse) { 46 | switch (direction) { 47 | case AxisDirection.up: 48 | offset = Offset(offset.dx, -offset.dy); 49 | break; 50 | case AxisDirection.right: 51 | offset = Offset(-offset.dx, offset.dy); 52 | break; 53 | case AxisDirection.down: 54 | offset = Offset(offset.dx, -offset.dy); 55 | break; 56 | case AxisDirection.left: 57 | offset = Offset(-offset.dx, offset.dy); 58 | break; 59 | } 60 | } 61 | return FractionalTranslation( 62 | translation: offset, 63 | transformHitTests: transformHitTests, 64 | child: child, 65 | ); 66 | } 67 | } -------------------------------------------------------------------------------- /lib/autocomplete/CountriesField.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CountriesField extends StatefulWidget { 4 | @override 5 | _CountriesFieldState createState() => _CountriesFieldState(); 6 | } 7 | 8 | class _CountriesFieldState extends State { 9 | 10 | final FocusNode _focusNode = FocusNode(); 11 | 12 | OverlayEntry _overlayEntry; 13 | 14 | final LayerLink _layerLink = LayerLink(); 15 | 16 | TextEditingController controller; 17 | 18 | @override 19 | void initState() { 20 | 21 | controller = new TextEditingController(); 22 | _focusNode.addListener(() { 23 | if (_focusNode.hasFocus) { 24 | 25 | this._overlayEntry = this._createOverlayEntry(); 26 | Overlay.of(context).insert(this._overlayEntry); 27 | 28 | } else { 29 | this._overlayEntry.remove(); 30 | } 31 | }); 32 | } 33 | 34 | 35 | @override 36 | void dispose() { 37 | this._overlayEntry.remove(); 38 | super.dispose(); 39 | } 40 | 41 | 42 | 43 | OverlayEntry _createOverlayEntry() { 44 | 45 | RenderBox renderBox = context.findRenderObject(); 46 | var size = renderBox.size; 47 | 48 | return OverlayEntry( 49 | builder: (context) => Positioned( 50 | width: size.width, 51 | child: CompositedTransformFollower( 52 | link: this._layerLink, 53 | showWhenUnlinked: false, 54 | offset: Offset(0.0, size.height + 5.0), 55 | child: Material( 56 | elevation: 4.0, 57 | child: ListView( 58 | padding: EdgeInsets.zero, 59 | shrinkWrap: true, 60 | children: [ 61 | ListTile( 62 | title: Text('中国'), 63 | onTap: () { 64 | controller.text = "中国"; 65 | this._overlayEntry.remove(); 66 | setState(() { 67 | 68 | }); 69 | }, 70 | ), 71 | ListTile( 72 | title: Text('美国'), 73 | onTap: () { 74 | controller.text = "美国"; 75 | this._overlayEntry.remove(); 76 | setState(() { 77 | 78 | }); 79 | }, 80 | ) 81 | ], 82 | ), 83 | ), 84 | ), 85 | ) 86 | ); 87 | 88 | 89 | } 90 | 91 | @override 92 | Widget build(BuildContext context) { 93 | return CompositedTransformTarget( 94 | link: this._layerLink, 95 | child: TextFormField( 96 | focusNode: this._focusNode, 97 | controller:controller , 98 | decoration: InputDecoration( 99 | labelText: 'Country' 100 | ), 101 | ), 102 | ); 103 | } 104 | } -------------------------------------------------------------------------------- /lib/autocomplete/OverlayMain.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'CountriesField.dart'; 5 | 6 | 7 | class OverlayMain extends StatefulWidget { 8 | @override 9 | _OverlayMainState createState() => _OverlayMainState(); 10 | } 11 | 12 | 13 | class _OverlayMainState extends State { 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | body: Padding( 19 | padding: const EdgeInsets.all(50.0), 20 | child: Form( 21 | child: ListView( 22 | children: [ 23 | 24 | CountriesField( 25 | ), 26 | 27 | TextFormField( 28 | decoration: InputDecoration( 29 | labelText: 'Address', 30 | ), 31 | 32 | ), 33 | 34 | SizedBox(height: 16.0,), 35 | TextFormField( 36 | decoration: InputDecoration( 37 | labelText: 'City' 38 | ), 39 | ), 40 | SizedBox(height: 16.0,), 41 | 42 | SizedBox(height: 16.0,), 43 | RaisedButton( 44 | child: Text('SUBMIT'), 45 | onPressed: () { 46 | Toast.show(context: context, message: "信息已经提交!"); 47 | }, 48 | ) 49 | ], 50 | ), 51 | ), 52 | ), 53 | ); 54 | 55 | 56 | } 57 | 58 | 59 | 60 | 61 | } 62 | 63 | 64 | //通过 Overlay 实现 Toast 65 | class Toast { 66 | static void show({@required BuildContext context, @required String message}) { 67 | 68 | //1、创建 overlayEntry 69 | OverlayEntry overlayEntry = new OverlayEntry(builder: (context) { 70 | return new Positioned( 71 | top: MediaQuery.of(context).size.height * 0.8, 72 | child: new Material( 73 | child: new Container( 74 | width: MediaQuery.of(context).size.width, 75 | alignment: Alignment.center, 76 | child: new Center( 77 | child: new Card( 78 | child: new Padding( 79 | padding: EdgeInsets.all(8), 80 | child: new Text(message), 81 | ), 82 | 83 | color: Colors.grey.withOpacity(0.6), 84 | ), 85 | ), 86 | ), 87 | )); 88 | }); 89 | 90 | 91 | //插入到 Overlay中显示 OverlayEntry 92 | Overlay.of(context).insert(overlayEntry); 93 | 94 | 95 | //延时两秒,移除 OverlayEntry 96 | new Future.delayed(Duration(seconds: 2)).then((value) { 97 | overlayEntry.remove(); 98 | } 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /lib/chartsDisplay/ChartDispalyMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_share/chartsDisplay/pie_chart.dart'; 3 | 4 | import 'bar_chart.dart'; 5 | import 'line_chart.dart'; 6 | 7 | class ChartDispalyMain extends StatefulWidget { 8 | ChartDispalyMain({Key key,}) : super(key: key); 9 | 10 | @override 11 | _ChartDispalyMainState createState() =>_ChartDispalyMainState(); 12 | 13 | } 14 | 15 | class _ChartDispalyMainState extends State { 16 | 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | Widget _buildCard(String assetUrl, String title, int index) { 21 | final double deviceHeight = MediaQuery.of(context).size.height; 22 | return SizedBox( 23 | width: deviceHeight * 0.45, 24 | child: ClipRRect( 25 | borderRadius: BorderRadius.circular(20.0), 26 | child: InkWell( 27 | onTap: () { 28 | if (index == 1) { 29 | Navigator.push( 30 | context, 31 | MaterialPageRoute( 32 | builder: (context) => BarChart() 33 | ) 34 | ); 35 | } else if (index == 2) { 36 | Navigator.push( 37 | context, 38 | MaterialPageRoute( 39 | builder: (context) => LineChart() 40 | ) 41 | ); 42 | } else if (index == 3) { 43 | Navigator.push( 44 | context, 45 | MaterialPageRoute( 46 | builder: (context) => PieChart() 47 | ) 48 | ); 49 | } 50 | }, 51 | child: Stack( 52 | children: [ 53 | Container( 54 | height: deviceHeight * 0.3, 55 | decoration: BoxDecoration( 56 | color: Colors.black, 57 | image: DecorationImage( 58 | fit: BoxFit.fill, 59 | colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.7), BlendMode.dstATop), 60 | image: AssetImage(assetUrl) 61 | ) 62 | ), 63 | ), 64 | Container( 65 | margin: EdgeInsets.only(top: deviceHeight * 0.125), 66 | alignment: Alignment.center, 67 | child: Text( 68 | title, 69 | textAlign: TextAlign.center, 70 | style: TextStyle( 71 | color: Colors.white, 72 | fontWeight: FontWeight.w500, 73 | fontSize: 29 74 | ), 75 | ), 76 | ) 77 | ], 78 | ), 79 | ), 80 | ), 81 | ); 82 | } 83 | 84 | 85 | return Scaffold( 86 | appBar: AppBar(title: Text("图表绘制"), centerTitle: true,), 87 | body: Padding( 88 | padding: const EdgeInsets.all(15.0), 89 | child: ListView( 90 | children: [ 91 | SizedBox(height: 25,), 92 | _buildCard('images/barchart.jpg', 'Bar-Chart Example', 1), 93 | SizedBox(height: 25,), 94 | _buildCard('images/linechart.png', 'Line-Chart Example', 2), 95 | SizedBox(height: 25,), 96 | _buildCard('images/piechart.jpg', 'Pie-Chart Example', 3) 97 | ], 98 | ), 99 | ), 100 | ); 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /lib/chartsDisplay/bar_chart.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:charts_flutter/flutter.dart' as charts; 4 | import 'package:flutter_share/chartsDisplay/population_data.dart'; 5 | 6 | class BarChart extends StatelessWidget { 7 | 8 | // Defining the data 9 | final List data = [ 10 | PopulationData( 11 | year: 1880, 12 | population: 50189209, 13 | barColor: charts.ColorUtil.fromDartColor(Colors.lightBlue) 14 | ), 15 | PopulationData( 16 | year: 1890, 17 | population: 62979766, 18 | barColor: charts.ColorUtil.fromDartColor(Colors.lightBlue) 19 | ), 20 | PopulationData( 21 | year: 1900, 22 | population: 76212168, 23 | barColor: charts.ColorUtil.fromDartColor(Colors.lightBlue) 24 | ), 25 | PopulationData( 26 | year: 1910, 27 | population: 92228496, 28 | barColor: charts.ColorUtil.fromDartColor(Colors.lightBlue) 29 | ), 30 | PopulationData( 31 | year: 1920, 32 | population: 106021537, 33 | barColor: charts.ColorUtil.fromDartColor(Colors.blue) 34 | ), 35 | PopulationData( 36 | year: 1930, 37 | population: 123202624, 38 | barColor: charts.ColorUtil.fromDartColor(Colors.blue) 39 | ), 40 | PopulationData( 41 | year: 1940, 42 | population: 132164569, 43 | barColor: charts.ColorUtil.fromDartColor(Colors.blue) 44 | ), 45 | PopulationData( 46 | year: 1950, 47 | population: 151325798, 48 | barColor: charts.ColorUtil.fromDartColor(Colors.blue) 49 | ), 50 | PopulationData( 51 | year: 1960, 52 | population: 179323175, 53 | barColor: charts.ColorUtil.fromDartColor(Colors.blue) 54 | ), 55 | PopulationData( 56 | year: 1970, 57 | population: 203302031, 58 | barColor: charts.ColorUtil.fromDartColor(Colors.purple) 59 | ), 60 | PopulationData( 61 | year: 1980, 62 | population: 226542199, 63 | barColor: charts.ColorUtil.fromDartColor(Colors.purple) 64 | ), 65 | PopulationData( 66 | year: 1990, 67 | population: 248709873, 68 | barColor: charts.ColorUtil.fromDartColor(Colors.purple) 69 | ), 70 | PopulationData( 71 | year: 2000, 72 | population: 281421906, 73 | barColor: charts.ColorUtil.fromDartColor(Colors.purple) 74 | ), 75 | PopulationData( 76 | year: 2010, 77 | population: 307745538, 78 | barColor: charts.ColorUtil.fromDartColor(Colors.black) 79 | ), 80 | PopulationData( 81 | year: 2017, 82 | population: 323148586, 83 | barColor: charts.ColorUtil.fromDartColor(Colors.black) 84 | ), 85 | 86 | ]; 87 | 88 | _getSeriesData() { 89 | List> series = [ 90 | charts.Series( 91 | id: "Population", 92 | data: data, 93 | domainFn: (PopulationData series, _) => series.year.toString(), 94 | measureFn: (PopulationData series, _) => series.population, 95 | colorFn: (PopulationData series, _) => series.barColor 96 | ) 97 | ]; 98 | return series; 99 | } 100 | 101 | @override 102 | Widget build(BuildContext context) { 103 | return Scaffold( 104 | appBar: AppBar(title: Text('Bar Chart Example'), centerTitle: true,), 105 | body: Center( 106 | child: Container( 107 | height: 400, 108 | padding: EdgeInsets.all(20), 109 | child: Card( 110 | child: Padding( 111 | padding: const EdgeInsets.all(8.0), 112 | child: Column( 113 | children: [ 114 | Text( 115 | "Population of U.S. over the years", 116 | style: TextStyle( 117 | fontWeight: FontWeight.bold 118 | ), 119 | ), 120 | SizedBox(height: 20,), 121 | Expanded( 122 | child: charts.BarChart( 123 | _getSeriesData(), 124 | animate: true, 125 | domainAxis: charts.OrdinalAxisSpec( 126 | renderSpec: charts.SmallTickRendererSpec(labelRotation: 60) 127 | ), 128 | ), 129 | ) 130 | ], 131 | ), 132 | ), 133 | ), 134 | ), 135 | ), 136 | ); 137 | } 138 | } -------------------------------------------------------------------------------- /lib/chartsDisplay/grades_data.dart: -------------------------------------------------------------------------------- 1 | 2 | class GradesData { 3 | final String gradeSymbol; 4 | final int numberOfStudents; 5 | 6 | GradesData(this.gradeSymbol, this.numberOfStudents); 7 | } -------------------------------------------------------------------------------- /lib/chartsDisplay/line_chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'sales_data.dart'; 3 | import 'package:charts_flutter/flutter.dart' as charts; 4 | 5 | class LineChart extends StatelessWidget { 6 | 7 | // Defining the data 8 | final data = [ 9 | new SalesData(0, 1500000), 10 | new SalesData(1, 1735000), 11 | new SalesData(2, 1678000), 12 | new SalesData(3, 1890000), 13 | new SalesData(4, 1907000), 14 | new SalesData(5, 2300000), 15 | new SalesData(6, 2360000), 16 | new SalesData(7, 1980000), 17 | new SalesData(8, 2654000), 18 | new SalesData(9, 2789070), 19 | new SalesData(10, 3020000), 20 | new SalesData(11, 3245900), 21 | new SalesData(12, 4098500), 22 | new SalesData(13, 4500000), 23 | new SalesData(14, 4456500), 24 | new SalesData(15, 3900500), 25 | new SalesData(16, 5123400), 26 | new SalesData(17, 5589000), 27 | new SalesData(18, 5940000), 28 | new SalesData(19, 6367000), 29 | ]; 30 | 31 | _getSeriesData() { 32 | List> series = [ 33 | charts.Series( 34 | id: "Sales", 35 | data: data, 36 | domainFn: (SalesData series, _) => series.year, 37 | measureFn: (SalesData series, _) => series.sales, 38 | colorFn: (SalesData series, _) => charts.MaterialPalette.blue.shadeDefault 39 | ) 40 | ]; 41 | return series; 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | appBar: AppBar( 48 | title: Text('Line Chart Example'), 49 | centerTitle: true, 50 | ), 51 | body: Center( 52 | child: Container( 53 | height: 550, 54 | padding: EdgeInsets.all(10), 55 | child: Card( 56 | child: Padding( 57 | padding: const EdgeInsets.all(8.0), 58 | child: Column( 59 | children: [ 60 | Text( 61 | "Sales of a company over the years", 62 | style: TextStyle( 63 | fontWeight: FontWeight.bold 64 | ), 65 | ), 66 | SizedBox( 67 | height: 20, 68 | ), 69 | Expanded( 70 | child: new charts.LineChart(_getSeriesData(), animate: true,), 71 | ) 72 | ], 73 | ), 74 | ), 75 | ), 76 | ), 77 | ) 78 | ); 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /lib/chartsDisplay/pie_chart.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:charts_flutter/flutter.dart' as charts; 4 | 5 | import 'grades_data.dart'; 6 | 7 | class PieChart extends StatelessWidget { 8 | 9 | 10 | final data = [ 11 | GradesData('A', 190), 12 | GradesData('B', 230), 13 | GradesData('C', 150), 14 | GradesData('D', 73), 15 | GradesData('E', 31), 16 | GradesData('Fail', 13), 17 | ]; 18 | 19 | _getSeriesData() { 20 | List> series = [ 21 | charts.Series( 22 | id: "Grades", 23 | data: data, 24 | labelAccessorFn: (GradesData row, _) => '${row.gradeSymbol}: ${row.numberOfStudents}', 25 | domainFn: (GradesData grades, _) => grades.gradeSymbol, 26 | measureFn: (GradesData grades, _) => grades.numberOfStudents 27 | ) 28 | ]; 29 | return series; 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Scaffold( 35 | appBar: AppBar(title: Text("Pie Chart"), centerTitle: true,), 36 | body: Center( 37 | child: Container( 38 | height: 400, 39 | padding: EdgeInsets.all(10), 40 | child: Card( 41 | child: Padding( 42 | padding: const EdgeInsets.all(8.0), 43 | child: Column( 44 | children: [ 45 | Text( 46 | "Grades of the students of school in the calendar year", 47 | textAlign: TextAlign.center, 48 | style: TextStyle( 49 | fontWeight: FontWeight.bold 50 | ), 51 | ), 52 | SizedBox( 53 | height: 20, 54 | ), 55 | Expanded( 56 | child: new charts.PieChart( 57 | _getSeriesData(), 58 | animate: true, 59 | defaultRenderer: new charts.ArcRendererConfig( 60 | arcWidth: 60, 61 | arcRendererDecorators: [new charts.ArcLabelDecorator()] 62 | ), 63 | ), 64 | ) 65 | ], 66 | ), 67 | ), 68 | ), 69 | ), 70 | ), 71 | ); 72 | } 73 | } -------------------------------------------------------------------------------- /lib/chartsDisplay/population_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_flutter/flutter.dart' as charts; 2 | import 'package:flutter/material.dart'; 3 | 4 | 5 | class PopulationData { 6 | int year; 7 | int population; 8 | charts.Color barColor; 9 | PopulationData({ 10 | @required this.year, 11 | @required this.population, 12 | @required this.barColor 13 | }); 14 | } -------------------------------------------------------------------------------- /lib/chartsDisplay/sales_data.dart: -------------------------------------------------------------------------------- 1 | 2 | class SalesData { 3 | final int year; 4 | final int sales; 5 | 6 | SalesData(this.year, this.sales); 7 | } -------------------------------------------------------------------------------- /lib/downloadDemo/DownDemoMain.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:io'; 3 | import 'dart:math'; 4 | 5 | import 'package:dio/dio.dart'; 6 | import 'package:file_utils/file_utils.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:path_provider/path_provider.dart'; 9 | import 'package:simple_permissions/simple_permissions.dart'; 10 | 11 | 12 | class DownDemoMain extends StatefulWidget { 13 | @override 14 | _DownDemoMainMainState createState() => _DownDemoMainMainState(); 15 | } 16 | 17 | 18 | class _DownDemoMainMainState extends State with SingleTickerProviderStateMixin { 19 | AnimationController _controller; 20 | 21 | final fileURl = "http://music.163.com/song/media/outer/url?id=413829859.mp3"; 22 | bool downloading = false; 23 | double progress ; 24 | var path = "No Data"; 25 | var platformVersion = "Unknown"; 26 | Permission permission1 = Permission.WriteExternalStorage; 27 | var _onPressed; 28 | static final Random random = Random(); 29 | Directory externalDir; 30 | 31 | 32 | @override 33 | void initState() { 34 | super.initState(); 35 | 36 | 37 | //动画时间 5 秒 38 | _controller = new AnimationController(vsync: this, duration: Duration(seconds: 5)); 39 | _controller.addListener(() => setState(() => {})); 40 | onAnimationStart(); 41 | } 42 | 43 | void onAnimationStart() { 44 | _controller.forward(from: 0.0); 45 | } 46 | 47 | @override 48 | void dispose() { 49 | super.dispose(); 50 | _controller.dispose(); 51 | } 52 | 53 | 54 | 55 | Future downloadFile() async { 56 | Dio dio = Dio(); 57 | bool checkPermission1 = 58 | //1、权限检查 59 | await SimplePermissions.checkPermission(permission1); 60 | if (checkPermission1 == false) { 61 | await SimplePermissions.requestPermission(permission1); 62 | checkPermission1 = await SimplePermissions.checkPermission(permission1); 63 | } 64 | 65 | if (checkPermission1 == true) { 66 | String dirloc = ""; 67 | if (Platform.isAndroid) { 68 | dirloc = "/sdcard/download/"; 69 | } else { 70 | dirloc = (await getApplicationDocumentsDirectory()).path; 71 | } 72 | 73 | var randid = random.nextInt(10000); 74 | 75 | try { 76 | 77 | //2、创建文件 78 | FileUtils.mkdir([dirloc]); 79 | 80 | //3、使用 dio 下载文件 81 | await dio.download(fileURl, dirloc + randid.toString() + ".mp3", 82 | onReceiveProgress: (receivedBytes, totalBytes) { 83 | setState(() { 84 | downloading = true; 85 | //4、连接资源成功开始下载后更新状态 86 | progress = (receivedBytes / totalBytes) ; 87 | }); 88 | }); 89 | 90 | } catch (e) { 91 | print(e); 92 | } 93 | 94 | 95 | setState(() { 96 | downloading = false; 97 | progress = 0; 98 | path = dirloc + randid.toString() + ".mp3"; 99 | }); 100 | 101 | 102 | } else { 103 | setState(() { 104 | progress = 0; 105 | _onPressed = () { 106 | downloadFile(); 107 | }; 108 | }); 109 | } 110 | } 111 | 112 | 113 | 114 | 115 | @override 116 | Widget build(BuildContext context) { 117 | final size =MediaQuery.of(context).size; 118 | final width =size.width; 119 | final height =size.height; 120 | 121 | return SingleChildScrollView( 122 | child: Column( 123 | children: [ 124 | 125 | SizedBox( 126 | width: width, 127 | height: 100, 128 | ), 129 | 130 | //线性进度条进度动画 131 | Padding( 132 | padding: EdgeInsets.all(16), 133 | child: LinearProgressIndicator( 134 | backgroundColor: Colors.grey[200], 135 | valueColor: ColorTween(begin: Colors.grey, end: Colors.red) 136 | .animate(_controller), 137 | value: _controller.value, 138 | ), 139 | ), 140 | 141 | 142 | 143 | //线性进度条模糊动画 144 | Padding( 145 | padding: EdgeInsets.all(16), 146 | child: LinearProgressIndicator( 147 | backgroundColor: Colors.grey[200], 148 | valueColor: AlwaysStoppedAnimation(Colors.blue), 149 | ), 150 | ), 151 | 152 | 153 | 154 | Padding( 155 | padding: EdgeInsets.all(16), 156 | child: 157 | // 模糊进度条(会执行一个旋转动画) 158 | CircularProgressIndicator( 159 | backgroundColor: Colors.grey[200], 160 | valueColor: AlwaysStoppedAnimation(Colors.blue), 161 | ), 162 | ), 163 | 164 | 165 | 166 | //精准进度 167 | Padding( 168 | padding: EdgeInsets.all(10), 169 | child: 170 | SizedBox( 171 | width: 150, 172 | height: 150, 173 | child: 174 | CircularProgressIndicator( 175 | backgroundColor: Colors.grey[200], 176 | valueColor: ColorTween(begin: Colors.grey, end: Colors.red) 177 | .animate(_controller), 178 | value: _controller.value, 179 | 180 | ), 181 | ), 182 | 183 | ), 184 | 185 | 186 | 187 | Container( 188 | child: downloading 189 | ? Container( 190 | height: 200.0, 191 | width: 200.0, 192 | child: 193 | Padding( 194 | padding: EdgeInsets.all(10), 195 | child: 196 | SizedBox( 197 | width: 200, 198 | height: 200, 199 | child: 200 | CircularProgressIndicator( 201 | backgroundColor: Colors.grey[200], 202 | value: progress, 203 | ), 204 | ), 205 | ), 206 | 207 | ) 208 | : Column( 209 | mainAxisAlignment: MainAxisAlignment.center, 210 | children: [ 211 | Text("下载文件路径:" + path), 212 | MaterialButton( 213 | child: Text('开始下载文件'), 214 | onPressed: (){ 215 | downloadFile(); 216 | }, 217 | disabledColor: Colors.blueGrey, 218 | color: Colors.pink, 219 | textColor: Colors.white, 220 | height: 40.0, 221 | minWidth: 100.0, 222 | ), 223 | ], 224 | ) 225 | ) 226 | 227 | 228 | ], 229 | ), 230 | ); 231 | 232 | 233 | } 234 | 235 | 236 | 237 | } -------------------------------------------------------------------------------- /lib/flutterSearch/searchbarview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | 4 | class SearchBarView extends StatefulWidget { 5 | @override 6 | _SearchBarViewState createState() => _SearchBarViewState(); 7 | } 8 | 9 | class _SearchBarViewState extends State { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: Text('搜索'), 15 | actions: [ 16 | IconButton( 17 | icon: Icon(Icons.search), 18 | onPressed: (){ 19 | showSearch(context: context, delegate: SearchBarViewDelegate()); 20 | } 21 | ) 22 | ], 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | class SearchBarViewDelegate extends SearchDelegate{ 29 | 30 | String searchHint = "请输入搜索内容..."; 31 | var sourceList = [ 32 | "dart", 33 | "dart 入门", 34 | "flutter", 35 | "flutter 编程", 36 | "flutter 编程开发", 37 | ]; 38 | 39 | var suggestList = [ 40 | "flutter", 41 | "flutter 编程开发" 42 | ]; 43 | 44 | 45 | @override 46 | String get searchFieldLabel => searchHint; 47 | 48 | 49 | @override 50 | List buildActions(BuildContext context) { 51 | 52 | ///显示在最右边的控件列表 53 | return [ 54 | 55 | IconButton( 56 | icon: Icon(Icons.clear), 57 | onPressed: (){ 58 | query = ""; 59 | 60 | ///搜索建议的内容 61 | showSuggestions(context); 62 | }, 63 | ), 64 | IconButton( 65 | icon: Icon(Icons.search), 66 | onPressed: ()=>query = "", 67 | ) 68 | ]; 69 | } 70 | 71 | 72 | ///左侧带动画的控件,一般都是返回 73 | @override 74 | Widget buildLeading(BuildContext context) { 75 | return IconButton( 76 | icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow, progress: transitionAnimation 77 | ), 78 | ///调用 close 关闭 search 界面 79 | onPressed: ()=>close(context,null), 80 | ); 81 | } 82 | 83 | 84 | ///展示搜索结果 85 | @override 86 | Widget buildResults(BuildContext context) { 87 | 88 | List result = List(); 89 | 90 | ///模拟搜索过程 91 | for (var str in sourceList){ 92 | ///query 就是输入框的 TextEditingController 93 | if (query.isNotEmpty && str.contains(query)){ 94 | result.add(str); 95 | } 96 | } 97 | 98 | ///展示搜索结果 99 | return ListView.builder( 100 | itemCount: result.length, 101 | itemBuilder: (BuildContext context, int index)=>ListTile( 102 | title: Text(result[index]), 103 | ), 104 | ); 105 | } 106 | 107 | @override 108 | Widget buildSuggestions(BuildContext context) { 109 | 110 | List suggest = query.isEmpty ? suggestList : sourceList.where((input)=>input.startsWith(query)).toList(); 111 | return ListView.builder( 112 | itemCount: suggest.length, 113 | itemBuilder: (BuildContext context, int index)=> 114 | InkWell( 115 | child: ListTile( 116 | title: RichText( 117 | text: TextSpan( 118 | text: suggest[index].substring(0, query.length), 119 | style: TextStyle(color: Colors.blue,fontWeight: FontWeight.bold), 120 | children: [ 121 | TextSpan( 122 | text: suggest[index].substring(query.length), 123 | style: TextStyle(color: Colors.grey), 124 | ), 125 | ], 126 | ), 127 | ), 128 | ), 129 | onTap: (){ 130 | // query.replaceAll("", suggest[index].toString()); 131 | searchHint = ""; 132 | query = suggest[index].toString(); 133 | showResults(context); 134 | }, 135 | ), 136 | 137 | 138 | ); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/heroAnimation/HeroAnimPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'HeroAnimationRouteB.dart'; 4 | 5 | class Heroanimpage extends StatefulWidget { 6 | Heroanimpage({Key key}) : super(key: key); 7 | 8 | @override 9 | _HeroanimpageState createState() => _HeroanimpageState(); 10 | } 11 | 12 | class _HeroanimpageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | alignment: Alignment.topCenter, 17 | child: InkWell( 18 | child: Hero( 19 | tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同 20 | child:Container( 21 | 22 | margin: EdgeInsets.only(top: 50), 23 | child: ClipOval( 24 | child: Image.asset("images/avatar.jpg", 25 | width: 50.0, 26 | ), 27 | ), 28 | ), 29 | ), 30 | onTap: () { 31 | //打开B路由 32 | Navigator.push(context, PageRouteBuilder( 33 | pageBuilder: (BuildContext context, Animation animation, 34 | Animation secondaryAnimation) { 35 | return new FadeTransition( 36 | opacity: animation, 37 | child: Scaffold( 38 | appBar: AppBar( 39 | title: Text("原图"), 40 | ), 41 | body: HeroAnimationRouteB(), 42 | ), 43 | ); 44 | }) 45 | ); 46 | }, 47 | ), 48 | ); } 49 | } -------------------------------------------------------------------------------- /lib/heroAnimation/HeroAnimationRouteB.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class HeroAnimationRouteB extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Center( 7 | child: Hero( 8 | tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同 9 | child: Image.asset("images/avatar.jpg"), 10 | ), 11 | ); 12 | } 13 | } -------------------------------------------------------------------------------- /lib/heroAnimation/Photo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Photo extends StatelessWidget { 4 | Photo({ Key key, this.photo, this.color, this.onTap }) : super(key: key); 5 | 6 | final String photo; 7 | final Color color; 8 | final VoidCallback onTap; 9 | 10 | Widget build(BuildContext context) { 11 | return new Material( 12 | // Slightly opaque color appears where the image has transparency. 13 | color: Theme.of(context).primaryColor.withOpacity(0.25), 14 | child: new InkWell( 15 | onTap: onTap, 16 | child: new Image.asset( 17 | photo, 18 | fit: BoxFit.contain, 19 | ) 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/heroAnimation/RadialExpansion.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math' as math; 3 | class RadialExpansion extends StatelessWidget { 4 | RadialExpansion({ 5 | Key key, 6 | this.maxRadius, 7 | this.child, 8 | }) : clipRectSize = 2.0 * (maxRadius / math.sqrt2), 9 | super(key: key); 10 | 11 | final double maxRadius; 12 | final clipRectSize; 13 | final Widget child; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return new ClipOval( 18 | child: new Center( 19 | child: new SizedBox( 20 | width: clipRectSize, 21 | height: clipRectSize, 22 | child: new ClipRect( 23 | child: child, // Photo 24 | ), 25 | ), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/heroAnimation/RadialExpansionDemo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'Photo.dart'; 4 | import 'RadialExpansion.dart'; 5 | 6 | class RadialExpansionDemo extends StatelessWidget { 7 | static const double kMinRadius = 32.0; 8 | static const double kMaxRadius = 128.0; 9 | static const opacityCurve = const Interval(0.0, 0.75, curve: Curves.fastOutSlowIn); 10 | 11 | static RectTween _createRectTween(Rect begin, Rect end) { 12 | return MaterialRectCenterArcTween(begin: begin, end: end); 13 | } 14 | 15 | static Widget _buildPage(BuildContext context, String imageName, String description) { 16 | return Container( 17 | color: Theme.of(context).canvasColor, 18 | child: Center( 19 | child: Card( 20 | elevation: 8.0, 21 | child: Column( 22 | mainAxisSize: MainAxisSize.min, 23 | children: [ 24 | SizedBox( 25 | width: kMaxRadius * 2.0, 26 | height: kMaxRadius * 2.0, 27 | child: Hero( 28 | createRectTween: _createRectTween, 29 | tag: imageName, 30 | child: RadialExpansion( 31 | maxRadius: kMaxRadius, 32 | child: Photo( 33 | photo: imageName, 34 | onTap: () { 35 | Navigator.of(context).pop(); 36 | }, 37 | ), 38 | ), 39 | ), 40 | ), 41 | Text( 42 | description, 43 | style: TextStyle(fontWeight: FontWeight.bold), 44 | textScaleFactor: 3.0, 45 | ), 46 | const SizedBox(height: 16.0), 47 | ], 48 | ), 49 | ), 50 | ), 51 | ); 52 | } 53 | 54 | Widget _buildHero(BuildContext context, String imageName, String description) { 55 | return Container( 56 | width: kMinRadius * 2.0, 57 | height: kMinRadius * 2.0, 58 | child: Hero( 59 | createRectTween: _createRectTween, 60 | tag: imageName, 61 | child: RadialExpansion( 62 | maxRadius: kMaxRadius, 63 | child: Photo( 64 | photo: imageName, 65 | onTap: () { 66 | Navigator.of(context).push( 67 | PageRouteBuilder( 68 | pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { 69 | return AnimatedBuilder( 70 | animation: animation, 71 | builder: (BuildContext context, Widget child) { 72 | return Opacity( 73 | opacity: opacityCurve.transform(animation.value), 74 | child: _buildPage(context, imageName, description), 75 | ); 76 | } 77 | ); 78 | }, 79 | ), 80 | ); 81 | }, 82 | ), 83 | ), 84 | ), 85 | ); 86 | } 87 | 88 | @override 89 | Widget build(BuildContext context) { 90 | var timeDilation = 5.0; // 1.0 is normal animation speed. 91 | 92 | return Scaffold( 93 | appBar: AppBar( 94 | title: const Text('Radial Transition Demo'), 95 | ), 96 | body: Container( 97 | padding: const EdgeInsets.all(32.0), 98 | alignment: FractionalOffset.bottomLeft, 99 | child: Row( 100 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 101 | children: [ 102 | _buildHero(context, 'images/aone.jpg', 'Chair'), 103 | _buildHero(context, 'images/atwo.jpg', 'Binoculars'), 104 | _buildHero(context, 'images/athree.jpg', 'Beach ball'), 105 | ], 106 | ), 107 | ), 108 | ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/implicitAnimation/AnimatedContainerDemo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | const _duration = Duration(milliseconds: 400); 6 | 7 | double randomBorderRadius() { 8 | return Random().nextDouble() * 64; 9 | } 10 | 11 | double randomMargin() { 12 | return Random().nextDouble() * 64; 13 | } 14 | 15 | Color randomColor() { 16 | return Color(0xFFFFFFFF & Random().nextInt(0xFFFFFFFF)); 17 | } 18 | 19 | class AnimatedContainerDemo extends StatefulWidget { 20 | _AnimatedContainerDemoState createState() => _AnimatedContainerDemoState(); 21 | } 22 | 23 | class _AnimatedContainerDemoState extends State { 24 | Color color; 25 | double borderRadius; 26 | double margin; 27 | 28 | @override 29 | void initState() { 30 | super.initState(); 31 | color = Colors.deepPurple; 32 | borderRadius = randomBorderRadius(); 33 | margin = randomMargin(); 34 | } 35 | 36 | void change() { 37 | setState(() { 38 | color = randomColor(); 39 | borderRadius = randomBorderRadius(); 40 | margin = randomMargin(); 41 | }); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | body: Center( 48 | child: Column( 49 | mainAxisAlignment: MainAxisAlignment.center, 50 | children: [ 51 | SizedBox( 52 | width: 128, 53 | height: 128, 54 | child: AnimatedContainer( 55 | margin: EdgeInsets.all(margin), 56 | decoration: BoxDecoration( 57 | color: color, 58 | borderRadius: BorderRadius.circular(borderRadius), 59 | ), 60 | duration: _duration, 61 | curve: Curves.easeInOutBack, 62 | ), 63 | ), 64 | MaterialButton( 65 | color: Theme.of(context).primaryColor, 66 | child: Text( 67 | 'change', 68 | style: TextStyle(color: Colors.white), 69 | ), 70 | onPressed: () => change(), 71 | ), 72 | ], 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /lib/implicitAnimation/FadeInDemo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class FadeInDemo extends StatefulWidget { 5 | _FadeInDemoState createState() => _FadeInDemoState(); 6 | } 7 | 8 | class _FadeInDemoState extends State { 9 | double opacity = 0.0; 10 | @override 11 | Widget build(BuildContext context) { 12 | return Column( 13 | crossAxisAlignment: CrossAxisAlignment.center, 14 | mainAxisAlignment: MainAxisAlignment.center, 15 | children: [ 16 | Image.network( 17 | 'https://picsum.photos/250?image=9', 18 | ), 19 | MaterialButton( 20 | child: Text( 21 | 'Show Details', 22 | style: TextStyle(color: Colors.blueAccent), 23 | ), 24 | onPressed: () => setState(() { 25 | opacity = 1; 26 | }), 27 | ), 28 | AnimatedOpacity( 29 | duration: Duration(seconds: 3), 30 | opacity: opacity, 31 | child: Column( 32 | children: [ 33 | Text('Type: Owl'), 34 | Text('Age: 39'), 35 | Text('Employment: None'), 36 | ], 37 | ), 38 | ) 39 | ]); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /lib/navigationrail/NavigationRailMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NanigationRailMain extends StatefulWidget { 4 | @override 5 | NanigationRailMainState createState() => NanigationRailMainState(); 6 | } 7 | 8 | 9 | class NanigationRailMainState extends State { 10 | int _selectedIndex = 0; 11 | final padding = 8.0; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | 16 | // return Scaffold( 17 | // body: Row( 18 | // children: [ 19 | // // Here's the important stuff 20 | // NavigationRail( 21 | // selectedIndex: _selectedIndex, 22 | // onDestinationSelected: (int index) { 23 | // setState(() { 24 | // _selectedIndex = index; 25 | // }); 26 | // }, 27 | // labelType: NavigationRailLabelType.selected, 28 | // destinations: [ 29 | // NavigationRailDestination( 30 | // icon: Icon(Icons.favorite_border), 31 | // selectedIcon: Icon(Icons.favorite), 32 | // label: Text('First'), 33 | // ), 34 | // NavigationRailDestination( 35 | // icon: Icon(Icons.bookmark_border), 36 | // selectedIcon: Icon(Icons.book), 37 | // label: Text('Second'), 38 | // ), 39 | // NavigationRailDestination( 40 | // icon: Icon(Icons.star_border), 41 | // selectedIcon: Icon(Icons.star), 42 | // label: Text('Third'), 43 | // ), 44 | // ], 45 | // ), 46 | // // And now it's not that interesting 47 | // Expanded( 48 | // child: Center( 49 | // child: Container( 50 | // color: Colors.blue, 51 | // child: 52 | // Center(child: Text("Page № ${_selectedIndex.toString()}")), 53 | // ), 54 | // ), 55 | // ) 56 | // ], 57 | // ), 58 | // ); 59 | 60 | return Scaffold( 61 | backgroundColor: Color(0xff28292E), 62 | body: SafeArea( 63 | child: Row( 64 | children: [ 65 | NavigationRail( 66 | minWidth: 56.0, 67 | groupAlignment: 1.0, 68 | backgroundColor: Color(0xff2D3035), 69 | selectedIndex: _selectedIndex, 70 | onDestinationSelected: (int index) { 71 | setState(() { 72 | _selectedIndex = index; 73 | }); 74 | }, 75 | labelType: NavigationRailLabelType.all, 76 | leading: Column( 77 | children: [ 78 | SizedBox( 79 | height: 8, 80 | ), 81 | Center( 82 | child: CircleAvatar( 83 | radius: 16, 84 | backgroundImage: NetworkImage( 85 | "https://t9.baidu.com/it/u=86853839,3576305254&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1591363041&t=58576d535d450f80e9248bd0ee84c8c0"), 86 | ), 87 | ), 88 | SizedBox( 89 | height: 108, 90 | ), 91 | RotatedBox( 92 | quarterTurns: -1, 93 | child: IconButton( 94 | icon: Icon(Icons.tune), 95 | color: Color(0xffFCCFA8), 96 | onPressed: () {}, 97 | ), 98 | ) 99 | ], 100 | ), 101 | selectedLabelTextStyle: TextStyle( 102 | color: Color(0xffFCCFA8), 103 | fontSize: 13, 104 | letterSpacing: 0.8, 105 | decoration: TextDecoration.underline, 106 | decorationThickness: 2.0, 107 | ), 108 | unselectedLabelTextStyle: TextStyle( 109 | fontSize: 13, 110 | letterSpacing: 0.8, 111 | ), 112 | destinations: [ 113 | buildRotatedTextRailDestination("Popular", padding), 114 | buildRotatedTextRailDestination("Favourites", padding), 115 | buildRotatedTextRailDestination("Inspiration", padding), 116 | buildRotatedTextRailDestination("All", padding), 117 | ], 118 | ), 119 | // This is the main content. 120 | ContentSpace(_selectedIndex) 121 | ], 122 | ), 123 | ), 124 | ); 125 | } 126 | } 127 | 128 | NavigationRailDestination buildRotatedTextRailDestination( 129 | String text, double padding) { 130 | return NavigationRailDestination( 131 | icon: SizedBox.shrink(), 132 | label: Padding( 133 | padding: EdgeInsets.symmetric(vertical: padding), 134 | child: RotatedBox( 135 | quarterTurns: -1, 136 | child: Text(text), 137 | ), 138 | ), 139 | ); 140 | } 141 | 142 | class ContentSpace extends StatelessWidget { 143 | final int _selectedIndex; 144 | 145 | ContentSpace(this._selectedIndex); 146 | 147 | final List images = [ 148 | "https://images.unsplash.com/photo-1524758631624-e2822e304c36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80", 149 | "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80", 150 | "https://images.unsplash.com/photo-1538688525198-9b88f6f53126?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1267&q=80", 151 | "https://images.unsplash.com/photo-1513161455079-7dc1de15ef3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80", 152 | "https://images.unsplash.com/photo-1544457070-4cd773b4d71e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=843&q=80", 153 | "https://images.unsplash.com/photo-1532323544230-7191fd51bc1b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80", 154 | "https://images.unsplash.com/photo-1549488344-cbb6c34cf08b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80", 155 | ]; 156 | 157 | final List titles = [ 158 | "Popular\nIdeas", 159 | "Favourites", 160 | "Inspiration\nIdeas", 161 | "All" 162 | ]; 163 | 164 | @override 165 | Widget build(BuildContext context) { 166 | return Expanded( 167 | child: Padding( 168 | padding: const EdgeInsets.fromLTRB(24, 8, 0, 0), 169 | child: MediaQuery.removePadding( 170 | removeTop: true, 171 | context: context, 172 | child: ListView( 173 | children: [ 174 | Row( 175 | mainAxisAlignment: MainAxisAlignment.end, 176 | children: [ 177 | IconButton( 178 | icon: Icon(Icons.search), 179 | onPressed: () {}, 180 | ), 181 | IconButton( 182 | icon: Icon(Icons.calendar_today), 183 | onPressed: () {}, 184 | ), 185 | ], 186 | ), 187 | SizedBox( 188 | height: 24, 189 | ), 190 | Text(titles[_selectedIndex], 191 | style: TextStyle( 192 | color: Color(0xffFCCFA8), 193 | fontSize: 16, 194 | letterSpacing: 0.8, 195 | decoration: TextDecoration.underline, 196 | decorationThickness: 2.0, 197 | ), 198 | 199 | ), 200 | SizedBox( 201 | height: 24, 202 | ), 203 | 204 | for (var i in images) ImageCard(i), 205 | 206 | ], 207 | ), 208 | ), 209 | ), 210 | ); 211 | } 212 | } 213 | 214 | class ImageCard extends StatelessWidget { 215 | final uri; 216 | 217 | @override 218 | Widget build(BuildContext context) { 219 | return Card( 220 | margin: const EdgeInsets.fromLTRB(0, 0, 24, 24), 221 | child: Image.network(uri), 222 | clipBehavior: Clip.antiAliasWithSaveLayer, 223 | elevation: 0.0, 224 | shape: RoundedRectangleBorder( 225 | borderRadius: BorderRadius.circular(16), 226 | 227 | ), 228 | ); 229 | } 230 | 231 | const ImageCard(this.uri); 232 | 233 | } -------------------------------------------------------------------------------- /lib/nestedScrollView/DemoOne.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NestedScrollViewDemoOne extends StatefulWidget { 4 | NestedScrollViewDemoOne({Key key,}) : super(key: key); 5 | 6 | @override 7 | _DemoOnePageState createState() =>_DemoOnePageState(); 8 | 9 | } 10 | 11 | class _DemoOnePageState extends State with SingleTickerProviderStateMixin{ 12 | 13 | TabController _tabController; 14 | ScrollController _scrollviewController; 15 | @override 16 | void initState() { 17 | // TODO: implement initState 18 | super.initState(); 19 | _tabController = TabController(length: 4, vsync: this); 20 | _scrollviewController = ScrollController(initialScrollOffset: 0.0); 21 | } 22 | 23 | @override 24 | void dispose() { 25 | // TODO: implement dispose 26 | super.dispose(); 27 | _tabController.dispose(); 28 | _scrollviewController.dispose(); 29 | } 30 | 31 | 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: NestedScrollView( 37 | controller: _scrollviewController, 38 | headerSliverBuilder: (context, boxIsScrolled) { 39 | 40 | return [ 41 | SliverAppBar( 42 | pinned: true, 43 | floating: true, 44 | elevation: 0.5, 45 | forceElevated: true, 46 | //backgroundColor: Colors.grey, 47 | expandedHeight: 240, 48 | flexibleSpace: FlexibleSpaceBar( 49 | collapseMode: CollapseMode.pin, //视差效果 50 | background: Container( 51 | //color: Colors.grey, 52 | child: Column( 53 | children: [ 54 | Container( 55 | height: 210.0, 56 | width: 420, 57 | color: Colors.blue, 58 | child: Image.asset( 59 | "images/bg.jpg", 60 | fit: BoxFit.fitWidth, 61 | ), 62 | ) 63 | ], 64 | ), 65 | ), 66 | ), 67 | bottom: TabBar(controller: _tabController, tabs: [ 68 | Tab( 69 | text: "首页", 70 | ), 71 | Tab( 72 | text: "消息", 73 | ), 74 | Tab( 75 | text: "购物", 76 | ), 77 | Tab( 78 | text: "我的", 79 | ) 80 | ]), 81 | ), 82 | 83 | 84 | 85 | ]; 86 | 87 | }, 88 | 89 | body: TabBarView( 90 | controller: _tabController, 91 | children: [ 92 | Center( 93 | child: Text("one"), 94 | ), 95 | 96 | Center( 97 | child: Text("two"), 98 | ), 99 | 100 | Center( 101 | child: Text("three"), 102 | ), 103 | 104 | Center( 105 | child: Text("four"), 106 | ), 107 | 108 | ] 109 | 110 | ) 111 | ), 112 | ); 113 | 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /lib/nestedScrollView/DemoTwo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NestedScrollViewDemoTwo extends StatefulWidget { 4 | NestedScrollViewDemoTwo({Key key,}) : super(key: key); 5 | 6 | @override 7 | _DemoTwoPageState createState() =>_DemoTwoPageState(); 8 | 9 | } 10 | 11 | class _DemoTwoPageState extends State { 12 | 13 | 14 | @override 15 | void initState() { 16 | 17 | } 18 | 19 | @override 20 | void dispose() { 21 | super.dispose(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | 27 | 28 | 29 | return Scaffold( 30 | body: NestedScrollView( 31 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { 32 | return [ 33 | 34 | 35 | /* SliverAppBar( 36 | title: Text("标题"), 37 | floating: false, 38 | snap: false, 39 | pinned: true, 40 | ) 41 | */ 42 | 43 | 44 | SliverAppBar( 45 | expandedHeight: 200.0, 46 | floating: true, 47 | snap: false, 48 | pinned: true, 49 | flexibleSpace: FlexibleSpaceBar( 50 | centerTitle: true, 51 | title: Text("标题", 52 | style: TextStyle( 53 | color: Colors.redAccent, 54 | fontSize: 16.0, 55 | )), 56 | background: Image.asset( 57 | "images/bg.jpg", 58 | fit: BoxFit.fill, 59 | ) 60 | ), 61 | ) 62 | 63 | 64 | ]; 65 | }, 66 | body: ListView.builder( 67 | itemBuilder: (BuildContext context, int index) { 68 | return ListTile(title:Text( "标题$index"),); 69 | }, 70 | itemCount: 50, 71 | ), 72 | ), 73 | 74 | ); 75 | 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /lib/path/CircleProgressBarPainter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math' as Math; 3 | 4 | class CircleProgressBarPainter extends CustomPainter { 5 | //背景 6 | Paint _paintBackground; 7 | 8 | //前景 9 | Paint _paintForeground; 10 | 11 | var currentValue; 12 | 13 | CircleProgressBarPainter(this.currentValue) { 14 | 15 | _paintBackground = Paint() 16 | ..color = Colors.blue 17 | ..strokeCap = StrokeCap.round 18 | ..style = PaintingStyle.stroke 19 | ..strokeWidth = 10.0 20 | ..isAntiAlias = true; 21 | 22 | _paintForeground = Paint() 23 | ..color = Colors.red 24 | ..strokeCap = StrokeCap.round 25 | ..style = PaintingStyle.stroke 26 | ..strokeWidth = 10.0 27 | ..isAntiAlias = true; 28 | 29 | } 30 | @override 31 | void paint(Canvas canvas, Size size) { 32 | 33 | //画背景 34 | canvas.drawCircle(Offset(size.width / 2, size.height / 2), size.width / 2, 35 | _paintBackground); 36 | 37 | 38 | Rect rect = Rect.fromCircle( 39 | center: Offset(size.width / 2, size.height / 2), 40 | radius: size.width / 2, 41 | ); 42 | 43 | //画弧形进度 44 | canvas.drawArc(rect, 0.0, currentValue * Math.pi / 180, false, _paintForeground); 45 | } 46 | 47 | 48 | 49 | @override 50 | bool shouldRepaint(CustomPainter oldDelegate) { 51 | return false; 52 | } 53 | } -------------------------------------------------------------------------------- /lib/path/Circles.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class Circles extends StatefulWidget { 7 | @override 8 | _CirclesState createState() => _CirclesState(); 9 | } 10 | 11 | class _CirclesState extends State with SingleTickerProviderStateMixin { 12 | AnimationController _controller; 13 | double circles = 5.0; 14 | bool showDots = false, showPath = true; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | _controller = AnimationController( 20 | vsync: this, 21 | duration: Duration(seconds: 3), 22 | ); 23 | _controller.value = 1.0; 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text('Circles'), 31 | ), 32 | body: SafeArea( 33 | child: Column( 34 | crossAxisAlignment: CrossAxisAlignment.start, 35 | mainAxisSize: MainAxisSize.max, 36 | children: [ 37 | Expanded( 38 | child: AnimatedBuilder( 39 | animation: _controller, 40 | builder: (context, snapshot) { 41 | return Center( 42 | child: CustomPaint( 43 | painter: CirclesPainter( 44 | circles: circles, 45 | progress: _controller.value, 46 | showDots: showDots, 47 | showPath: showPath, 48 | ), 49 | ), 50 | ); 51 | }), 52 | ), 53 | Row( 54 | children: [ 55 | Padding( 56 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 57 | child: Text('Show Dots'), 58 | ), 59 | Switch( 60 | value: showDots, 61 | onChanged: (value) { 62 | setState(() { 63 | showDots = value; 64 | }); 65 | }, 66 | ), 67 | Padding( 68 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 69 | child: Text('Show Path'), 70 | ), 71 | Switch( 72 | value: showPath, 73 | onChanged: (value) { 74 | setState(() { 75 | showPath = value; 76 | }); 77 | }, 78 | ), 79 | ], 80 | ), 81 | Padding( 82 | padding: const EdgeInsets.only(left: 24.0), 83 | child: Text('Circles'), 84 | ), 85 | Slider( 86 | value: circles, 87 | min: 1.0, 88 | max: 10.0, 89 | divisions: 9, 90 | label: circles.toInt().toString(), 91 | onChanged: (value) { 92 | setState(() { 93 | circles = value; 94 | }); 95 | }, 96 | ), 97 | Padding( 98 | padding: const EdgeInsets.only(left: 24.0), 99 | child: Text('Progress'), 100 | ), 101 | Slider( 102 | value: _controller.value, 103 | min: 0.0, 104 | max: 1.0, 105 | onChanged: (value) { 106 | setState(() { 107 | _controller.value = value; 108 | }); 109 | }, 110 | ), 111 | Center( 112 | child: RaisedButton( 113 | child: Text('Animate'), 114 | onPressed: () { 115 | _controller.reset(); 116 | _controller.forward(); 117 | }, 118 | ), 119 | ), 120 | ], 121 | ), 122 | ), 123 | ); 124 | } 125 | } 126 | 127 | class CirclesPainter extends CustomPainter { 128 | CirclesPainter({this.circles, this.progress, this.showDots, this.showPath}); 129 | 130 | final double circles, progress; 131 | bool showDots, showPath; 132 | 133 | var myPaint = Paint() 134 | ..color = Colors.purple 135 | ..style = PaintingStyle.stroke 136 | ..strokeWidth = 5.0; 137 | 138 | double radius = 80; 139 | 140 | @override 141 | void paint(Canvas canvas, Size size) { 142 | var path = createPath(); 143 | PathMetrics pathMetrics = path.computeMetrics(); 144 | for (PathMetric pathMetric in pathMetrics) { 145 | Path extractPath = pathMetric.extractPath( 146 | 0.0, 147 | pathMetric.length * progress, 148 | ); 149 | if (showPath) { 150 | canvas.drawPath(extractPath, myPaint); 151 | } 152 | if (showDots) { 153 | try { 154 | var metric = extractPath.computeMetrics().first; 155 | final offset = metric.getTangentForOffset(metric.length).position; 156 | canvas.drawCircle(offset, 8.0, Paint()); 157 | } catch (e) {} 158 | } 159 | } 160 | } 161 | 162 | Path createPath() { 163 | var path = Path(); 164 | int n = circles.toInt(); 165 | var range = List.generate(n, (i) => i + 1); 166 | double angle = 2 * math.pi / n; 167 | for (int i in range) { 168 | double x = radius * math.cos(i * angle); 169 | double y = radius * math.sin(i * angle); 170 | path.addOval(Rect.fromCircle(center: Offset(x, y), radius: radius)); 171 | } 172 | return path; 173 | } 174 | 175 | @override 176 | bool shouldRepaint(CirclesPainter oldDelegate) { 177 | return true; 178 | } 179 | } -------------------------------------------------------------------------------- /lib/path/DashLinePainter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class DashLinePainter extends CustomPainter { 6 | final double progress; 7 | 8 | DashLinePainter({this.progress}); 9 | 10 | Paint _paint = Paint() 11 | ..color = Colors.black 12 | ..strokeWidth = 4.0 13 | ..style = PaintingStyle.stroke 14 | ..strokeJoin = StrokeJoin.round; 15 | 16 | @override 17 | void paint(Canvas canvas, Size size) { 18 | var path = Path() 19 | ..moveTo(0, size.height / 2) 20 | ..lineTo(size.width * progress, size.height / 2); 21 | 22 | Path dashPath = Path(); 23 | 24 | double dashWidth = 10.0; 25 | double dashSpace = 5.0; 26 | double distance = 0.0; 27 | 28 | for (PathMetric pathMetric in path.computeMetrics()) { 29 | while (distance < pathMetric.length) { 30 | dashPath.addPath( 31 | pathMetric.extractPath(distance, distance + dashWidth), 32 | Offset.zero, 33 | ); 34 | distance += dashWidth; 35 | distance += dashSpace; 36 | } 37 | } 38 | canvas.drawPath(dashPath, _paint); 39 | } 40 | 41 | @override 42 | bool shouldRepaint(DashLinePainter oldDelegate) { 43 | return oldDelegate.progress != progress; 44 | } 45 | } -------------------------------------------------------------------------------- /lib/path/LinePainter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LinePainter extends CustomPainter { 4 | final double progress; 5 | 6 | LinePainter({this.progress}); 7 | 8 | Paint _paint = Paint() 9 | ..color = Colors.black 10 | ..strokeWidth = 4.0 11 | ..style = PaintingStyle.stroke 12 | ..strokeJoin = StrokeJoin.round; 13 | 14 | @override 15 | void paint(Canvas canvas, Size size) { 16 | var path = Path(); 17 | path.moveTo(0, size.height / 2); 18 | path.lineTo(size.width * progress, size.height / 2); 19 | canvas.drawPath(path, _paint); 20 | } 21 | 22 | @override 23 | bool shouldRepaint(LinePainter oldDelegate) { 24 | return oldDelegate.progress != progress; 25 | } 26 | } -------------------------------------------------------------------------------- /lib/path/PathAdvancedMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_share/path/Circles.dart'; 3 | import 'package:flutter_share/path/DashLinePainter.dart'; 4 | import 'package:flutter_share/path/LinePainter.dart'; 5 | 6 | import 'Planets.dart'; 7 | import 'Polygon.dart'; 8 | import 'Spiral.dart'; 9 | 10 | class PathAdvancedMain extends StatefulWidget { 11 | @override 12 | _PathAdvancedMainState createState() => _PathAdvancedMainState(); 13 | } 14 | 15 | class _PathAdvancedMainState extends State { 16 | 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | 22 | } 23 | 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | final size =MediaQuery.of(context).size; 28 | final width =size.width; 29 | final height =size.height; 30 | 31 | 32 | 33 | return ListView( 34 | children: [ 35 | 36 | SizedBox(width: width,height: 20,), 37 | // 38 | // Container( 39 | // width: width, 40 | // height: 50, 41 | // alignment: Alignment.center, 42 | // child: Text("直线(百分之50比例)"), 43 | // ), 44 | // 45 | // CustomPaint( 46 | // painter:LinePainter(progress: 0.5), 47 | // ) , 48 | // 49 | // 50 | // 51 | // Container( 52 | // width: width, 53 | // height: 50, 54 | // alignment: Alignment.center, 55 | // child: Text("虚线"), 56 | // ), 57 | // 58 | // CustomPaint( 59 | // painter:DashLinePainter(progress: 0.9), 60 | // ) 61 | // 62 | 63 | 64 | 65 | FlatButton( 66 | color: Colors.blue, 67 | highlightColor: Colors.blue[700], 68 | colorBrightness: Brightness.dark, 69 | splashColor: Colors.grey, 70 | child: Text("画圆"), 71 | shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), 72 | onPressed: () { 73 | Navigator.push( context, 74 | new MaterialPageRoute(builder: (context) { 75 | return new Scaffold(body: Circles(),); 76 | //return new NestedScrollViewDemoTwo(); 77 | })); 78 | }, 79 | ), 80 | 81 | 82 | 83 | 84 | 85 | FlatButton( 86 | color: Colors.blue, 87 | highlightColor: Colors.blue[700], 88 | colorBrightness: Brightness.dark, 89 | splashColor: Colors.grey, 90 | child: Text("绘制多边形"), 91 | shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), 92 | onPressed: () { 93 | Navigator.push( context, 94 | new MaterialPageRoute(builder: (context) { 95 | return new Scaffold(body: Polygon(),); 96 | //return new NestedScrollViewDemoTwo(); 97 | })); 98 | }, 99 | ), 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | FlatButton( 109 | color: Colors.blue, 110 | highlightColor: Colors.blue[700], 111 | colorBrightness: Brightness.dark, 112 | splashColor: Colors.grey, 113 | child: Text("螺旋曲线"), 114 | shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), 115 | onPressed: () { 116 | Navigator.push( context, 117 | new MaterialPageRoute(builder: (context) { 118 | return new Scaffold(body: Spiral(),); 119 | //return new NestedScrollViewDemoTwo(); 120 | })); 121 | }, 122 | ), 123 | 124 | 125 | 126 | 127 | 128 | FlatButton( 129 | color: Colors.blue, 130 | highlightColor: Colors.blue[700], 131 | colorBrightness: Brightness.dark, 132 | splashColor: Colors.grey, 133 | child: Text("星空动画"), 134 | shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), 135 | onPressed: () { 136 | Navigator.push( context, 137 | new MaterialPageRoute(builder: (context) { 138 | return new Scaffold(body: Planets(),); 139 | //return new NestedScrollViewDemoTwo(); 140 | })); 141 | }, 142 | ), 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | ], 157 | ); 158 | 159 | 160 | } 161 | 162 | 163 | } -------------------------------------------------------------------------------- /lib/path/PathBasicsMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'CircleProgressBarPainter.dart'; 4 | import 'PathPainter.dart'; 5 | 6 | 7 | 8 | class PathBasicsMain extends StatefulWidget { 9 | @override 10 | _PathBasicsMainMainState createState() => _PathBasicsMainMainState(); 11 | } 12 | 13 | class _PathBasicsMainMainState extends State with SingleTickerProviderStateMixin { 14 | 15 | Animation progressAnimation; 16 | AnimationController _controller; 17 | 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | 23 | _controller = AnimationController(vsync: this, duration: Duration(seconds: 2)); 24 | 25 | progressAnimation = Tween(begin: 0.0, end: 360.0).animate(_controller); 26 | 27 | _controller.addListener(() { 28 | this.setState(() {}); 29 | }); 30 | 31 | 32 | 33 | 34 | onAnimationStart(); 35 | } 36 | 37 | void onAnimationStart() { 38 | _controller.forward(from: 0.0); 39 | } 40 | 41 | @override 42 | void dispose() { 43 | super.dispose(); 44 | _controller.dispose(); 45 | } 46 | 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | final size =MediaQuery.of(context).size; 51 | final width =size.width; 52 | final height =size.height; 53 | 54 | 55 | return Container( 56 | width: width, 57 | height: height, 58 | padding: EdgeInsets.all(20), 59 | child: CustomPaint( 60 | 61 | child: Center( 62 | child: Text( 63 | (progressAnimation.value / 3.6).round().toString(), 64 | style: TextStyle(fontSize: 24,color: Colors.blue), 65 | ), 66 | ), 67 | 68 | painter: CircleProgressBarPainter(progressAnimation.value) 69 | 70 | ), 71 | 72 | ); 73 | 74 | } 75 | 76 | 77 | } -------------------------------------------------------------------------------- /lib/path/PathPainter.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'dart:math' as Math; 4 | 5 | class PathPainter extends CustomPainter { 6 | @override 7 | void paint(Canvas canvas, Size size) { 8 | 9 | Paint paint = Paint() 10 | ..color = Colors.red 11 | ..style = PaintingStyle.stroke 12 | ..strokeWidth = 8.0; 13 | 14 | Path path = Path(); 15 | // 从左上角起点到右下角终点 16 | path.relativeMoveTo(size.width/4,size.height/4); 17 | path.relativeLineTo(size.width, size.height); 18 | canvas.drawPath(path, paint); 19 | 20 | 21 | 22 | 23 | } 24 | 25 | @override 26 | bool shouldRepaint(CustomPainter oldDelegate) => true; 27 | } -------------------------------------------------------------------------------- /lib/path/Planets.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class Planets extends StatefulWidget { 7 | @override 8 | _PlanetsState createState() => _PlanetsState(); 9 | } 10 | 11 | class _PlanetsState extends State with TickerProviderStateMixin { 12 | AnimationController _controller; 13 | AnimationController _controller1; 14 | AnimationController _controller2; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | _controller = AnimationController( 20 | vsync: this, 21 | duration: Duration(seconds: 3), 22 | ); 23 | _controller1 = AnimationController( 24 | vsync: this, 25 | duration: Duration(seconds: 4), 26 | ); 27 | _controller2 = AnimationController( 28 | vsync: this, 29 | duration: Duration(seconds: 5), 30 | ); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | backgroundColor: const Color(0xFF6C63FF), 37 | appBar: AppBar( 38 | title: Text('Planets'), 39 | backgroundColor: Colors.transparent, 40 | elevation: 0.0, 41 | ), 42 | body: AnimatedBuilder( 43 | animation: _controller, 44 | builder: (context, snapshot) { 45 | return Center( 46 | child: CustomPaint( 47 | painter: AtomPaint( 48 | value: _controller.value, 49 | value1: _controller1.value, 50 | value2: _controller2.value, 51 | ), 52 | ), 53 | ); 54 | }), 55 | floatingActionButton: FloatingActionButton( 56 | child: Icon(Icons.play_arrow), 57 | onPressed: () { 58 | _controller.reset(); 59 | _controller1.reset(); 60 | _controller2.reset(); 61 | _controller.repeat(); 62 | _controller1.repeat(); 63 | _controller2.repeat(); 64 | }, 65 | ), 66 | ); 67 | } 68 | } 69 | 70 | class AtomPaint extends CustomPainter { 71 | AtomPaint({ 72 | this.value, 73 | this.value1, 74 | this.value2, 75 | }); 76 | 77 | final double value, value1, value2; 78 | 79 | Paint _axisPaint = Paint() 80 | ..color = const Color(0xFFE6E6E6) 81 | ..strokeWidth = 2.0 82 | ..style = PaintingStyle.stroke; 83 | 84 | @override 85 | void paint(Canvas canvas, Size size) { 86 | canvas.drawCircle(Offset(0, 0), 20.0, Paint()..color = Colors.yellow); 87 | drawAxis(value, canvas, 60, Paint()..color = Colors.grey); 88 | drawAxis(value1, canvas, 100, Paint()..color = Colors.brown); 89 | drawAxis(value2, canvas, 140, Paint()..color = Colors.blueAccent); 90 | drawAxis(value, canvas, 180, Paint()..color = Colors.redAccent); 91 | drawAxis(value1, canvas, 220, Paint()..color = Colors.lightGreen); 92 | drawAxis(value2, canvas, 260, Paint()..color = Colors.purpleAccent); 93 | } 94 | 95 | drawAxis(double value, Canvas canvas, double radius, Paint paint) { 96 | var firstAxis = getCirclePath(radius); 97 | canvas.drawPath(firstAxis, _axisPaint); 98 | PathMetrics pathMetrics = firstAxis.computeMetrics(); 99 | for (PathMetric pathMetric in pathMetrics) { 100 | Path extractPath = pathMetric.extractPath( 101 | 0.0, 102 | pathMetric.length * value, 103 | ); 104 | try { 105 | var metric = extractPath.computeMetrics().first; 106 | final offset = metric.getTangentForOffset(metric.length).position; 107 | canvas.drawCircle(offset, 12.0, paint); 108 | } catch (e) {} 109 | } 110 | } 111 | 112 | Path getCirclePath(double radius) => 113 | Path()..addOval(Rect.fromCircle(center: Offset(0, 0), radius: radius)); 114 | 115 | @override 116 | bool shouldRepaint(CustomPainter oldDelegate) { 117 | return true; 118 | } 119 | } -------------------------------------------------------------------------------- /lib/path/Polygon.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'dart:math' as math; 6 | 7 | 8 | class Polygon extends StatefulWidget { 9 | @override 10 | _PolygonState createState() => _PolygonState(); 11 | } 12 | 13 | class _PolygonState extends State with SingleTickerProviderStateMixin { 14 | double sides = 3.0; 15 | bool showDots = false, showPath = true; 16 | AnimationController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = AnimationController( 22 | vsync: this, 23 | duration: Duration(seconds: 3), 24 | ); 25 | _controller.value = 1.0; 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: Text('Polygon'), 34 | ), 35 | body: SafeArea( 36 | child: Column( 37 | crossAxisAlignment: CrossAxisAlignment.start, 38 | mainAxisSize: MainAxisSize.max, 39 | children: [ 40 | Expanded( 41 | child: AnimatedBuilder( 42 | animation: _controller, 43 | builder: (context, snapshot) { 44 | return Center( 45 | child: CustomPaint( 46 | painter: PolygonPainter( 47 | sides: sides, 48 | progress: _controller.value, 49 | showDots: showDots, 50 | showPath: showPath, 51 | ), 52 | ), 53 | ); 54 | }), 55 | ), 56 | Row( 57 | children: [ 58 | Padding( 59 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 60 | child: Text('Show Dots'), 61 | ), 62 | Switch( 63 | value: showDots, 64 | onChanged: (value) { 65 | setState(() { 66 | showDots = value; 67 | }); 68 | }, 69 | ), 70 | Padding( 71 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 72 | child: Text('Show Path'), 73 | ), 74 | Switch( 75 | value: showPath, 76 | onChanged: (value) { 77 | setState(() { 78 | showPath = value; 79 | }); 80 | }, 81 | ), 82 | ], 83 | ), 84 | Padding( 85 | padding: const EdgeInsets.only(left: 24.0), 86 | child: Text('Sides'), 87 | ), 88 | Slider( 89 | value: sides, 90 | min: 3.0, 91 | max: 10.0, 92 | label: sides.toInt().toString(), 93 | divisions: 7, 94 | onChanged: (value) { 95 | setState(() { 96 | sides = value; 97 | }); 98 | }, 99 | ), 100 | Padding( 101 | padding: const EdgeInsets.only(left: 24.0), 102 | child: Text('Progress'), 103 | ), 104 | Slider( 105 | value: _controller.value, 106 | min: 0.0, 107 | max: 1.0, 108 | onChanged: (value) { 109 | setState(() { 110 | _controller.value = value; 111 | }); 112 | }, 113 | ), 114 | Center( 115 | child: RaisedButton( 116 | child: Text('Animate'), 117 | onPressed: () { 118 | _controller.reset(); 119 | _controller.forward(); 120 | }, 121 | ), 122 | ), 123 | ], 124 | ), 125 | ), 126 | ); 127 | } 128 | } 129 | 130 | class PolygonPainter extends CustomPainter { 131 | PolygonPainter({ 132 | this.sides, 133 | this.progress, 134 | this.showPath, 135 | this.showDots, 136 | }); 137 | 138 | final double sides; 139 | final double progress; 140 | bool showDots, showPath; 141 | 142 | final Paint _paint = Paint() 143 | ..color = Colors.purple 144 | ..strokeWidth = 4.0 145 | ..style = PaintingStyle.stroke 146 | ..strokeCap = StrokeCap.round; 147 | 148 | @override 149 | void paint(Canvas canvas, Size size) { 150 | var path = createPath(sides.toInt(), 100); 151 | PathMetric pathMetric = path.computeMetrics().first; 152 | Path extractPath = 153 | pathMetric.extractPath(0.0, pathMetric.length * progress); 154 | if (showPath) { 155 | canvas.drawPath(extractPath, _paint); 156 | } 157 | if (showDots) { 158 | try { 159 | var metric = extractPath.computeMetrics().first; 160 | final offset = metric.getTangentForOffset(metric.length).position; 161 | canvas.drawCircle(offset, 8.0, Paint()); 162 | } catch (e) {} 163 | } 164 | } 165 | 166 | @override 167 | bool shouldRepaint(CustomPainter oldDelegate) { 168 | return true; 169 | } 170 | 171 | Path createPath(int sides, double radius) { 172 | var path = Path(); 173 | var angle = (math.pi * 2) / sides; 174 | path.moveTo(radius * math.cos(0.0), radius * math.sin(0.0)); 175 | for (int i = 1; i <= sides; i++) { 176 | double x = radius * math.cos(angle * i); 177 | double y = radius * math.sin(angle * i); 178 | path.lineTo(x, y); 179 | } 180 | path.close(); 181 | return path; 182 | } 183 | } -------------------------------------------------------------------------------- /lib/path/Spiral.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class Spiral extends StatefulWidget { 7 | @override 8 | _SpiralState createState() => _SpiralState(); 9 | } 10 | 11 | class _SpiralState extends State with SingleTickerProviderStateMixin { 12 | bool showDots = false, showPath = true; 13 | AnimationController _controller; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _controller = AnimationController( 19 | vsync: this, 20 | duration: Duration(seconds: 5), 21 | ); 22 | _controller.value = 1.0; 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text('Spiral'), 30 | ), 31 | body: SafeArea( 32 | child: Column( 33 | crossAxisAlignment: CrossAxisAlignment.start, 34 | mainAxisSize: MainAxisSize.max, 35 | children: [ 36 | AnimatedBuilder( 37 | animation: _controller, 38 | builder: (context, child) { 39 | print('${_controller.value}'); 40 | return Expanded( 41 | child: Center( 42 | child: CustomPaint( 43 | painter: SpiralPainter( 44 | progress: _controller.value, 45 | showPath: showPath, 46 | showDots: showDots, 47 | ), 48 | ), 49 | ), 50 | ); 51 | }, 52 | ), 53 | Row( 54 | children: [ 55 | Padding( 56 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 57 | child: Text('Show Dots'), 58 | ), 59 | Switch( 60 | value: showDots, 61 | onChanged: (value) { 62 | setState(() { 63 | showDots = value; 64 | }); 65 | }, 66 | ), 67 | Padding( 68 | padding: const EdgeInsets.only(left: 24.0, right: 0.0), 69 | child: Text('Show Path'), 70 | ), 71 | Switch( 72 | value: showPath, 73 | onChanged: (value) { 74 | setState(() { 75 | showPath = value; 76 | }); 77 | }, 78 | ), 79 | ], 80 | ), 81 | Padding( 82 | padding: const EdgeInsets.only(left: 24.0), 83 | child: Text('Progress'), 84 | ), 85 | Slider( 86 | value: _controller.value, 87 | min: 0.0, 88 | max: 1.0, 89 | onChanged: (value) { 90 | setState(() { 91 | _controller.value = value; 92 | }); 93 | }, 94 | ), 95 | Center( 96 | child: RaisedButton( 97 | onPressed: () { 98 | _controller.reset(); 99 | _controller.forward(); 100 | }, 101 | child: Text('Animate'), 102 | ), 103 | ), 104 | ], 105 | ), 106 | ), 107 | ); 108 | } 109 | 110 | @override 111 | void dispose() { 112 | _controller.dispose(); 113 | super.dispose(); 114 | } 115 | } 116 | 117 | class SpiralPainter extends CustomPainter { 118 | SpiralPainter({ 119 | this.progress, 120 | this.showPath, 121 | this.showDots, 122 | }); 123 | 124 | final double progress; 125 | bool showDots, showPath; 126 | 127 | Paint _paint = Paint() 128 | ..color = Colors.deepPurple 129 | ..strokeWidth = 4.0 130 | ..style = PaintingStyle.stroke 131 | ..strokeCap = StrokeCap.round; 132 | 133 | @override 134 | void paint(Canvas canvas, Size size) { 135 | Path path = createSpiralPath(size); 136 | PathMetric pathMetric = path.computeMetrics().first; 137 | Path extractPath = 138 | pathMetric.extractPath(0.0, pathMetric.length * progress); 139 | if (showPath) { 140 | canvas.drawPath(extractPath, _paint); 141 | } 142 | if (showDots) { 143 | try { 144 | var metric = extractPath.computeMetrics().first; 145 | final offset = metric.getTangentForOffset(metric.length).position; 146 | canvas.drawCircle(offset, 8.0, Paint()); 147 | } catch (e) {} 148 | } 149 | } 150 | 151 | Path createSpiralPath(Size size) { 152 | double radius = 0, angle = 0; 153 | Path path = Path(); 154 | for (int n = 0; n < 200; n++) { 155 | radius += 0.75; 156 | angle += (math.pi * 2) / 50; 157 | var x = size.width / 2 + radius * math.cos(angle); 158 | var y = size.height / 2 + radius * math.sin(angle); 159 | path.lineTo(x, y); 160 | } 161 | return path; 162 | } 163 | 164 | @override 165 | bool shouldRepaint(CustomPainter oldDelegate) { 166 | return true; 167 | } 168 | } -------------------------------------------------------------------------------- /lib/perspective/FlipAnimationMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_share/perspective/FlipWidget.dart'; 3 | 4 | import 'FlipPanel.dart'; 5 | 6 | class FlipAnimationMain extends StatefulWidget { 7 | @override 8 | _FlipAnimationMainState createState() => _FlipAnimationMainState(); 9 | } 10 | 11 | 12 | class _FlipAnimationMainState extends State { 13 | 14 | final digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]; 15 | 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | 20 | //实现绕 X 轴旋转效果 21 | // return Scaffold( 22 | // body: Center( 23 | // child:FlipWidget( 24 | // child: Container( 25 | // width: 300, 26 | // height: 200, 27 | // // color: Colors.green, 28 | // child: Image.asset( 29 | // "images/bg.jpg", 30 | // fit: BoxFit.fill, 31 | // ), 32 | // ), 33 | // ) 34 | // 35 | // 36 | // ), 37 | // ); 38 | 39 | 40 | 41 | ///实现翻页效果 42 | return new Scaffold( 43 | 44 | body: new Center( 45 | child: FlipPanel.builder( 46 | itemBuilder: (context, index) => Container( 47 | alignment: Alignment.center, 48 | width: 96.0, 49 | height: 128.0, 50 | decoration: BoxDecoration( 51 | color: Colors.black, 52 | borderRadius: BorderRadius.all(Radius.circular(4.0)), 53 | ), 54 | child: Text( 55 | '${digits[index]}', 56 | style: TextStyle( 57 | fontWeight: FontWeight.bold, 58 | fontSize: 80.0, 59 | color: Colors.yellow), 60 | ), 61 | ), 62 | itemsCount: digits.length, 63 | period: Duration(milliseconds: 1000), 64 | loop: -1, 65 | ), 66 | ), 67 | ); 68 | 69 | 70 | 71 | 72 | 73 | } 74 | 75 | 76 | 77 | 78 | } -------------------------------------------------------------------------------- /lib/perspective/FlipPanel.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:async'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | import 'dart:math' as math; 7 | 8 | /// Signature for a function that creates a widget for a given index, e.g., in a 9 | /// list. 10 | typedef Widget IndexedItemBuilder(BuildContext, int); 11 | 12 | /// Signature for a function that creates a widget for a value emitted from a [Stream] 13 | typedef Widget StreamItemBuilder(BuildContext, T); 14 | 15 | /// A widget for flip panel with built-in animation 16 | /// Content of the panel is built from [IndexedItemBuilder] or [StreamItemBuilder] 17 | /// 18 | /// Note: the content size should be equal 19 | enum FlipDirection { up, down } 20 | 21 | class FlipPanel extends StatefulWidget { 22 | final IndexedItemBuilder indexedItemBuilder; 23 | final StreamItemBuilder streamItemBuilder; 24 | final Stream itemStream; 25 | final int itemsCount; 26 | final Duration period; 27 | final Duration duration; 28 | final int loop; 29 | final int startIndex; 30 | final T initValue; 31 | final double spacing; 32 | final FlipDirection direction; 33 | 34 | FlipPanel({ 35 | Key key, 36 | this.indexedItemBuilder, 37 | this.streamItemBuilder, 38 | this.itemStream, 39 | this.itemsCount, 40 | this.period, 41 | this.duration, 42 | this.loop, 43 | this.startIndex, 44 | this.initValue, 45 | this.spacing, 46 | this.direction, 47 | }) : super(key: key); 48 | 49 | /// Create a flip panel from iterable source 50 | /// [itemBuilder] is called periodically in each time of [period] 51 | /// The animation is looped in [loop] times before finished. 52 | /// Setting [loop] to -1 makes flip animation run forever. 53 | /// The [period] should be two times greater than [duration] of flip animation, 54 | /// if not the animation becomes jerky/stuttery. 55 | FlipPanel.builder({ 56 | Key key, 57 | @required IndexedItemBuilder itemBuilder, 58 | @required this.itemsCount, 59 | @required this.period, 60 | this.duration = const Duration(milliseconds: 500), 61 | this.loop = 1, 62 | this.startIndex = 0, 63 | this.spacing = 0.5, 64 | this.direction = FlipDirection.up, 65 | }) : assert(itemBuilder != null), 66 | assert(itemsCount != null), 67 | assert(startIndex < itemsCount), 68 | assert(period == null || 69 | period.inMilliseconds >= 2 * duration.inMilliseconds), 70 | indexedItemBuilder = itemBuilder, 71 | streamItemBuilder = null, 72 | itemStream = null, 73 | initValue = null, 74 | super(key: key); 75 | 76 | /// Create a flip panel from stream source 77 | /// [itemBuilder] is called whenever a new value is emitted from [itemStream] 78 | FlipPanel.stream({ 79 | Key key, 80 | @required this.itemStream, 81 | @required StreamItemBuilder itemBuilder, 82 | this.initValue, 83 | this.duration = const Duration(milliseconds: 500), 84 | this.spacing = 0.5, 85 | this.direction = FlipDirection.up, 86 | }) : assert(itemStream != null), 87 | indexedItemBuilder = null, 88 | streamItemBuilder = itemBuilder, 89 | itemsCount = 0, 90 | period = null, 91 | loop = 0, 92 | startIndex = 0, 93 | super(key: key); 94 | 95 | @override 96 | _FlipPanelState createState() => _FlipPanelState(); 97 | } 98 | 99 | class _FlipPanelState extends State 100 | with TickerProviderStateMixin { 101 | AnimationController _controller; 102 | Animation _animation; 103 | int _currentIndex; 104 | bool _isReversePhase; 105 | bool _isStreamMode; 106 | bool _running; 107 | final _perspective = 0.003; 108 | final _zeroAngle = 0.0001; // There's something wrong in the perspective transform, I use a very small value instead of zero to temporarily get it around. 109 | int _loop; 110 | T _currentValue, _nextValue; 111 | Timer _timer; 112 | StreamSubscription _subscription; 113 | 114 | Widget _child1, _child2; 115 | Widget _upperChild1, _upperChild2; 116 | Widget _lowerChild1, _lowerChild2; 117 | 118 | @override 119 | void initState() { 120 | super.initState(); 121 | _currentIndex = widget.startIndex; 122 | _isStreamMode = widget.itemStream != null; 123 | _isReversePhase = false; 124 | _running = false; 125 | _loop = 0; 126 | 127 | _controller = 128 | new AnimationController(duration: widget.duration, vsync: this) 129 | ..addStatusListener((status) { 130 | if (status == AnimationStatus.completed) { 131 | _isReversePhase = true; 132 | _controller.reverse(); 133 | } 134 | if (status == AnimationStatus.dismissed) { 135 | _currentValue = _nextValue; 136 | _running = false; 137 | } 138 | }) 139 | ..addListener(() { 140 | setState(() { 141 | _running = true; 142 | }); 143 | }); 144 | _animation = Tween(begin: _zeroAngle, end: math.pi / 2).animate(_controller); 145 | 146 | if (widget.period != null) { 147 | _timer = Timer.periodic(widget.period, (_) { 148 | if (widget.loop < 0 || _loop < widget.loop) { 149 | if (_currentIndex + 1 == widget.itemsCount - 2) { 150 | _loop++; 151 | } 152 | _currentIndex = (_currentIndex + 1) % widget.itemsCount; 153 | _child1 = null; 154 | _isReversePhase = false; 155 | _controller.forward(); 156 | } else { 157 | _timer.cancel(); 158 | _currentIndex = (_currentIndex + 1) % widget.itemsCount; 159 | setState(() { 160 | _running = false; 161 | }); 162 | } 163 | }); 164 | } 165 | 166 | if (_isStreamMode) { 167 | _currentValue = widget.initValue; 168 | _subscription = widget.itemStream.distinct().listen((value) { 169 | if (_currentValue == null) { 170 | _currentValue = value; 171 | } else if (value != _currentValue) { 172 | _nextValue = value; 173 | _child1 = null; 174 | _isReversePhase = false; 175 | _controller.forward(); 176 | } 177 | }); 178 | } else if (widget.loop < 0 || _loop < widget.loop) { 179 | _controller.forward(); 180 | } 181 | } 182 | 183 | @override 184 | void dispose() { 185 | _controller.dispose(); 186 | if (_subscription != null) _subscription.cancel(); 187 | if (_timer != null) _timer.cancel(); 188 | super.dispose(); 189 | } 190 | 191 | @override 192 | Widget build(BuildContext context) { 193 | _buildChildWidgetsIfNeed(context); 194 | 195 | return _buildPanel(); 196 | } 197 | 198 | void _buildChildWidgetsIfNeed(BuildContext context) { 199 | Widget makeUpperClip(Widget widget) { 200 | return ClipRect( 201 | child: Align( 202 | alignment: Alignment.topCenter, 203 | heightFactor: 0.5, 204 | child: widget, 205 | ), 206 | ); 207 | } 208 | 209 | Widget makeLowerClip(Widget widget) { 210 | return ClipRect( 211 | child: Align( 212 | alignment: Alignment.bottomCenter, 213 | heightFactor: 0.5, 214 | child: widget, 215 | ), 216 | ); 217 | } 218 | 219 | if (_running) { 220 | if (_child1 == null) { 221 | _child1 = _child2 != null 222 | ? _child2 223 | : _isStreamMode 224 | ? widget.streamItemBuilder(context, _currentValue) 225 | : widget.indexedItemBuilder( 226 | context, _currentIndex % widget.itemsCount); 227 | _child2 = null; 228 | _upperChild1 = 229 | _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); 230 | _lowerChild1 = 231 | _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); 232 | } 233 | if (_child2 == null) { 234 | _child2 = _isStreamMode 235 | ? widget.streamItemBuilder(context, _nextValue) 236 | : widget.indexedItemBuilder( 237 | context, (_currentIndex + 1) % widget.itemsCount); 238 | _upperChild2 = makeUpperClip(_child2); 239 | _lowerChild2 = makeLowerClip(_child2); 240 | } 241 | } else { 242 | _child1 = _child2 != null 243 | ? _child2 244 | : _isStreamMode 245 | ? widget.streamItemBuilder(context, _currentValue) 246 | : widget.indexedItemBuilder( 247 | context, _currentIndex % widget.itemsCount); 248 | _upperChild1 = 249 | _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); 250 | _lowerChild1 = 251 | _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); 252 | } 253 | } 254 | 255 | Widget _buildUpperFlipPanel() => widget.direction == FlipDirection.up 256 | ? Stack( 257 | children: [ 258 | Transform( 259 | alignment: Alignment.bottomCenter, 260 | transform: Matrix4.identity() 261 | ..setEntry(3, 2, _perspective) 262 | ..rotateX(_zeroAngle), 263 | child: _upperChild1 264 | ), 265 | Transform( 266 | alignment: Alignment.bottomCenter, 267 | transform: Matrix4.identity() 268 | ..setEntry(3, 2, _perspective) 269 | ..rotateX(_isReversePhase ? _animation.value : math.pi / 2), 270 | child: _upperChild2, 271 | ), 272 | ], 273 | ) 274 | : Stack( 275 | children: [ 276 | Transform( 277 | alignment: Alignment.bottomCenter, 278 | transform: Matrix4.identity() 279 | ..setEntry(3, 2, _perspective) 280 | ..rotateX(_zeroAngle), 281 | child: _upperChild2 282 | ), 283 | Transform( 284 | alignment: Alignment.bottomCenter, 285 | transform: Matrix4.identity() 286 | ..setEntry(3, 2, _perspective) 287 | ..rotateX(_isReversePhase ? math.pi / 2 : _animation.value), 288 | child: _upperChild1, 289 | ), 290 | ], 291 | ); 292 | 293 | Widget _buildLowerFlipPanel() => widget.direction == FlipDirection.up 294 | ? Stack( 295 | children: [ 296 | Transform( 297 | alignment: Alignment.topCenter, 298 | transform: Matrix4.identity() 299 | ..setEntry(3, 2, _perspective) 300 | ..rotateX(_zeroAngle), 301 | child: _lowerChild2 302 | ), 303 | Transform( 304 | alignment: Alignment.topCenter, 305 | transform: Matrix4.identity() 306 | ..setEntry(3, 2, _perspective) 307 | ..rotateX(_isReversePhase ? math.pi / 2 : -_animation.value), 308 | child: _lowerChild1, 309 | ) 310 | ], 311 | ) 312 | : Stack( 313 | children: [ 314 | Transform( 315 | alignment: Alignment.topCenter, 316 | transform: Matrix4.identity() 317 | ..setEntry(3, 2, _perspective) 318 | ..rotateX(_zeroAngle), 319 | child: _lowerChild1 320 | ), 321 | Transform( 322 | alignment: Alignment.topCenter, 323 | transform: Matrix4.identity() 324 | ..setEntry(3, 2, _perspective) 325 | ..rotateX(_isReversePhase ? -_animation.value : math.pi / 2), 326 | child: _lowerChild2, 327 | ) 328 | ], 329 | ); 330 | 331 | Widget _buildPanel() { 332 | return _running 333 | ? Column( 334 | mainAxisSize: MainAxisSize.min, 335 | mainAxisAlignment: MainAxisAlignment.center, 336 | crossAxisAlignment: CrossAxisAlignment.center, 337 | children: [ 338 | _buildUpperFlipPanel(), 339 | Padding( 340 | padding: EdgeInsets.only(top: widget.spacing), 341 | ), 342 | _buildLowerFlipPanel(), 343 | ], 344 | ) 345 | : _isStreamMode && _currentValue == null 346 | ? Container() 347 | : Column( 348 | mainAxisSize: MainAxisSize.min, 349 | mainAxisAlignment: MainAxisAlignment.center, 350 | crossAxisAlignment: CrossAxisAlignment.center, 351 | children: [ 352 | Transform( 353 | alignment: Alignment.bottomCenter, 354 | transform: Matrix4.identity() 355 | ..setEntry(3, 2, _perspective) 356 | ..rotateX(_zeroAngle), 357 | child: _upperChild1 358 | ), 359 | Padding( 360 | padding: EdgeInsets.only(top: widget.spacing), 361 | ), 362 | Transform( 363 | alignment: Alignment.topCenter, 364 | transform: Matrix4.identity() 365 | ..setEntry(3, 2, _perspective) 366 | ..rotateX(_zeroAngle), 367 | child: _lowerChild1 368 | ) 369 | ], 370 | ); 371 | } 372 | } -------------------------------------------------------------------------------- /lib/perspective/FlipWidget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class FlipWidget extends StatelessWidget { 6 | Widget child; 7 | 8 | FlipWidget({Key key, this.child}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Column( 13 | mainAxisSize: MainAxisSize.min, 14 | children: [ 15 | 16 | Transform( 17 | transform: Matrix4.identity()..setEntry(3, 2, 0.006)..rotateX(pi / 4), 18 | alignment: Alignment.bottomCenter, 19 | child: ClipRect( 20 | child: Align( 21 | alignment: Alignment.topCenter, 22 | heightFactor: 0.5, 23 | child: child, 24 | )), 25 | ), 26 | 27 | 28 | // ClipRect( 29 | // child: Align( 30 | // alignment: Alignment.topCenter, 31 | // heightFactor: 0.5, 32 | // child: child, 33 | // )), 34 | // 35 | 36 | 37 | Padding( 38 | padding: EdgeInsets.only(top: 2.0), 39 | ), 40 | ClipRect( 41 | child: Align( 42 | alignment: Alignment.bottomCenter, 43 | heightFactor: 0.5, 44 | child: child, 45 | )), 46 | ], 47 | ); 48 | } 49 | } -------------------------------------------------------------------------------- /lib/perspective/PerspectiveMain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PerspectiveMain extends StatefulWidget { 4 | @override 5 | _PerspectiveMainState createState() => _PerspectiveMainState(); 6 | } 7 | 8 | 9 | class _PerspectiveMainState extends State { 10 | 11 | 12 | int _counter = 0; 13 | Offset _offset = Offset(0.4, 0.7); // new 14 | 15 | void _incrementCounter() { 16 | setState(() { 17 | _counter++; 18 | }); 19 | } 20 | 21 | 22 | _defaultApp(BuildContext context) { // new 23 | return Scaffold( 24 | appBar: AppBar( 25 | title: Text('The Matrix 3D'), // changed 26 | ), 27 | body: Center( 28 | child: Column( 29 | mainAxisAlignment: MainAxisAlignment.center, 30 | children: [ 31 | Text( 32 | 'You have pushed the button this many times:', 33 | ), 34 | Text( 35 | '$_counter', 36 | style: Theme.of(context).textTheme.display1, 37 | ), 38 | ], 39 | ), 40 | ), 41 | floatingActionButton: FloatingActionButton( 42 | onPressed: _incrementCounter, 43 | tooltip: 'Increment', 44 | child: Icon(Icons.add), 45 | ), 46 | ); 47 | } 48 | 49 | 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | return Transform( // Transform widget 54 | transform: Matrix4.identity() 55 | ..setEntry(3, 2, 0.001) // perspective 56 | ..rotateX(0.01 * _offset.dy) // changed 57 | ..rotateY(-0.01 * _offset.dx), // changed 58 | alignment: FractionalOffset.center, 59 | child: GestureDetector( // new 60 | onPanUpdate: (details) => setState(() => _offset += details.delta), 61 | onDoubleTap: () => setState(() => _offset = Offset.zero), 62 | child: _defaultApp(context), 63 | ) 64 | ); 65 | 66 | 67 | } 68 | 69 | 70 | 71 | 72 | } -------------------------------------------------------------------------------- /lib/refreshData/refresh_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class RefreshDataPage extends StatefulWidget { 5 | 6 | RefreshDataPage({Key key, this.title}) : super(key: key); 7 | final String title; 8 | 9 | @override 10 | _RefreshDataPageState createState() => _RefreshDataPageState(); 11 | } 12 | 13 | 14 | 15 | ///最新消息 16 | const String LAST_NEWS = "https://news-at.zhihu.com/api/4/news/latest"; 17 | 18 | ///历史消息 19 | const String HISTORY_NEWS = "https://news-at.zhihu.com/api/4/news/before/"; 20 | 21 | class _RefreshDataPageState extends State { 22 | 23 | 24 | ///网络请求 25 | Response response; 26 | Dio dio = new Dio(); 27 | 28 | Future getDataFuture; 29 | 30 | bool isShowProgress = false; 31 | 32 | //当前日期 33 | String currentDate = ""; 34 | 35 | ScrollController _scrollController = ScrollController(); 36 | 37 | List items = new List(); 38 | 39 | 40 | 41 | 42 | @override 43 | void initState() { 44 | super.initState(); 45 | getDataFuture = getItemNews(); 46 | _scrollController.addListener(() { 47 | if (_scrollController.position.pixels == 48 | _scrollController.position.maxScrollExtent) { 49 | print("get more"); 50 | _getMore(currentDate); 51 | } 52 | }); 53 | 54 | } 55 | ///获取最新消息 56 | Future > getItemNews() async{ 57 | items.clear(); 58 | 59 | print("开始获取最新消息."); 60 | response = await dio.get(LAST_NEWS); 61 | currentDate = response.data["date"].toString(); 62 | 63 | if(response.data["stories"] != null){ 64 | items.addAll(response.data["stories"]); 65 | } 66 | 67 | if(items.length < 6){ 68 | _getMore(currentDate); 69 | } 70 | 71 | 72 | return items; 73 | } 74 | 75 | 76 | 77 | _getMore(String date) async{ 78 | if(date == "") 79 | return; 80 | 81 | setState(() { 82 | isShowProgress = true; 83 | }); 84 | 85 | Map historyMap ; 86 | response = await dio.get(HISTORY_NEWS + date); 87 | historyMap = response.data; 88 | 89 | if(historyMap != null && historyMap.length > 0){ 90 | List stories = historyMap["stories"]; 91 | if(stories != null && stories.length > 0){ 92 | currentDate = historyMap["date"].toString(); 93 | } 94 | 95 | 96 | if(response.data["stories"] != null){ 97 | items.addAll(response.data["stories"]); 98 | } 99 | 100 | 101 | } 102 | 103 | setState(() { 104 | isShowProgress = false; 105 | }); 106 | 107 | } 108 | 109 | 110 | @override 111 | Widget build(BuildContext context) { 112 | return Scaffold( 113 | appBar: AppBar( 114 | title: Text("下拉刷新上滑加载数据"), 115 | ), 116 | 117 | body: RefreshIndicator( 118 | onRefresh: getItemNews, 119 | child: FutureBuilder>( 120 | future: getDataFuture, 121 | builder: (context,AsyncSnapshot> async){ 122 | ///正在请求时的视图 123 | if (async.connectionState == ConnectionState.active || async.connectionState == ConnectionState.waiting) { 124 | return Center( 125 | child: Text("loading..."), 126 | ); 127 | } 128 | ///发生错误时的视图 129 | if (async.connectionState == ConnectionState.done) { 130 | if (async.hasError) { 131 | return Center( 132 | child: Text("error"), 133 | ); 134 | } else if (async.hasData && async.data != null && async.data.length > 0) { 135 | 136 | List resultList = async.data; 137 | 138 | return ListView.builder( 139 | controller: _scrollController, 140 | itemCount: resultList.length + 1, 141 | itemExtent: 100.0, 142 | itemBuilder: (BuildContext context, int index) { 143 | return index < async.data.length ? Container( 144 | child: Card( 145 | child: Row( 146 | children: [ 147 | Expanded( 148 | child: Container( 149 | child: Text(resultList[index]["title"].toString(),style: TextStyle(fontSize:20),), 150 | padding: EdgeInsets.symmetric(horizontal: 10), 151 | ), 152 | flex: 2, 153 | ), 154 | 155 | Expanded( 156 | child: Container( 157 | child:Image.network(resultList[index]["images"][0].toString()), 158 | padding: EdgeInsets.all(5), 159 | ), 160 | flex: 1, 161 | ), 162 | 163 | ], 164 | ), 165 | ), 166 | height: 50, 167 | ): Center( 168 | child: isShowProgress? CircularProgressIndicator( 169 | strokeWidth: 2.0, 170 | ):Container(), 171 | ); 172 | 173 | } 174 | ); 175 | 176 | }else{ 177 | return Center( 178 | child: Text("error"), 179 | ); 180 | } 181 | } 182 | return Center( 183 | child: Text("error"), 184 | ); 185 | }, 186 | ), 187 | 188 | ), 189 | 190 | ); 191 | } 192 | 193 | 194 | @override 195 | void dispose() { 196 | super.dispose(); 197 | _scrollController.dispose(); 198 | } 199 | 200 | 201 | } -------------------------------------------------------------------------------- /lib/scheme/home_index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 首页 4 | class HomePageIndex extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | // TODO: implement build 8 | return Text('I am home page'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/scheme/router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_share/scheme/user_index.dart'; 3 | import 'package:flutter_share/scheme/web_view_page.dart'; 4 | import 'package:flutter_share/stateManager/screens/cart.dart'; 5 | import 'package:flutter_share/stateManager/screens/catalog.dart'; 6 | 7 | import 'home_index.dart'; 8 | 9 | /// app 协议头 10 | const String appScheme = "tyfapp"; 11 | 12 | /// action mapping 13 | const Map> paramsMapping = { 14 | 'homepage' : null, 15 | 'userpage' : ['userId'] 16 | }; 17 | 18 | /// 处理APP内的跳转 19 | class MyRouter { 20 | /// 根据url处理获得需要跳转的action页面以及需要携带的参数 21 | Widget _getPage(String url, Map urlParseRet) { 22 | if (url.startsWith('https://') || url.startsWith('http://')) { 23 | return CommonWebViewPage(url: url); 24 | } else if(url.startsWith(appScheme)) { 25 | // 判断是否解析出 path action,并且能否在路由配置中找到 26 | String pathAction = urlParseRet['action'].toString(); 27 | switch (pathAction) { 28 | case "homepage": { 29 | return _buildPage(HomePageIndex()); 30 | } 31 | case "userpage": { 32 | // 必要性检查,如果没有参数则不做任何处理 33 | if(urlParseRet['params']['user_id'].toString() == null) { 34 | return null; 35 | } 36 | return _buildPage( 37 | UserPageIndex( 38 | userId: urlParseRet['params']['user_id'].toString() 39 | ) 40 | ); 41 | } 42 | default: { 43 | return _buildPage(HomePageIndex()); 44 | } 45 | } 46 | } 47 | return null; 48 | } 49 | 50 | /// 执行页面跳转 51 | void push(BuildContext context, String url) { 52 | Map urlParseRet = _parseUrl(url); 53 | 54 | Navigator.pushNamedAndRemoveUntil( 55 | context, 56 | urlParseRet['action'].toString(), (route) { 57 | if(route.settings.name == 58 | urlParseRet['action'].toString()) { 59 | return false; 60 | } 61 | return true; 62 | }, arguments: urlParseRet['params']); 63 | } 64 | 65 | /// 解析跳转的url,并且分析其内部参数 66 | Map _parseUrl(String url) { 67 | if(url.startsWith(appScheme)) { 68 | url = url.substring(9); 69 | } 70 | 71 | int placeIndex = url.indexOf('?'); 72 | 73 | if(url == '' || url == null) { 74 | return {'action': '/', 'params': null}; 75 | } 76 | if (placeIndex < 0) { 77 | return {'action': url, 'params': null}; 78 | } 79 | 80 | String action = url.substring(0, placeIndex); 81 | String paramStr = url.substring(placeIndex + 1); 82 | 83 | if (paramStr == null) { 84 | return {'action': action, 'params': null}; 85 | } 86 | 87 | Map params = {}; 88 | List paramsStrArr = paramStr.split('&'); 89 | for (String singleParamsStr in paramsStrArr) { 90 | List singleParamsArr = singleParamsStr.split('='); 91 | if(paramsMapping[action].indexOf(singleParamsArr[0]) > -1) { 92 | params[singleParamsArr[0]] = singleParamsArr[1]; 93 | } 94 | } 95 | return {'action': action, 'params': params}; 96 | } 97 | 98 | /// 增加 scaffold 99 | Widget _buildPage(Widget widgetPage) { 100 | return Scaffold( 101 | appBar: AppBar( 102 | title: Text('Two You'), // 页面名字 103 | ), 104 | body: Center( 105 | child: widgetPage, 106 | ) 107 | ); 108 | } 109 | 110 | /// 注册路由事件 111 | Map registerRouter () { 112 | return { 113 | 'homepage' : (context) => _buildPage(HomePageIndex()), 114 | 'userpage' : (context) => _buildPage(UserPageIndex()), 115 | '/catalog': (context) => MyCatalog(), ///类别 116 | '/cart': (context) => MyCart(), 117 | }; 118 | } 119 | 120 | // /// 设置路由跳转逻辑 121 | // MaterialPageRoute generateRoute(String pathAction, Object params) { 122 | // Map paramsMap = {}; 123 | // if(params != null) { 124 | // paramsMap = jsonDecode(JsonCodec().encode(params)) as Map; 125 | // } 126 | // switch (pathAction) { 127 | // case 'userpage' : { 128 | // return MaterialPageRoute( 129 | // builder: (context) => _buildPage( 130 | // UserPageIndex( 131 | // userId: paramsMap['userId'].toString() 132 | // ) 133 | // ) 134 | // ); 135 | // } 136 | // case 'homepage' : { 137 | // return MaterialPageRoute( 138 | // builder: (context) => _buildPage(HomePageIndex()) 139 | // ); 140 | // } 141 | // default: { 142 | // return MaterialPageRoute( 143 | // builder: (context) => _buildPage(HomePageIndex()) 144 | // ); 145 | // } 146 | // } 147 | // } 148 | } -------------------------------------------------------------------------------- /lib/scheme/user_index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_share/utils/json_config.dart'; 3 | 4 | /// 首页 5 | class UserPageIndex extends StatelessWidget { 6 | /// 用户 ID 信息 7 | final String userId; 8 | 9 | /// 构造函数 10 | const UserPageIndex({Key key, this.userId}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | 15 | //通过这种方式刷新页面 16 | Map dataInfo = JsonConfig.objectToMap( 17 | ModalRoute.of(context).settings.arguments 18 | ); 19 | 20 | // TODO: implement build 21 | return Text('I am use page ${dataInfo['userId']}'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/scheme/web_view_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 3 | 4 | /// 通用跳转逻辑 5 | class CommonWebViewPage extends StatelessWidget { 6 | /// url 地址 7 | final String url; 8 | 9 | /// 构造函数 10 | CommonWebViewPage({Key key, this.url}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | 15 | return WebviewScaffold( 16 | url: url, 17 | appBar: AppBar( 18 | backgroundColor: Colors.blue, 19 | ), 20 | ); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /lib/stateManager/BasicCounter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class BasicCounter with ChangeNotifier { 7 | int _counter; 8 | 9 | BasicCounter(this._counter); 10 | 11 | getCounter() => _counter; 12 | setCounter(int counter) => _counter = counter; 13 | 14 | void increment() { 15 | _counter++; 16 | notifyListeners(); 17 | } 18 | 19 | void decrement() { 20 | _counter--; 21 | notifyListeners(); 22 | } 23 | } -------------------------------------------------------------------------------- /lib/stateManager/BasicUse/provider_basic.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | void main() { 5 | runApp( 6 | ///使用 ChangeNotifierProvider ,这个 Provider 将数据 model 粘合在一起,数据改变时,保证 MyApp 或者其子 Widget ui 更新。 7 | ChangeNotifierProvider( 8 | // Initialize the model in the builder. That way, Provider 9 | // can own Counter's lifecycle, making sure to call `dispose` 10 | // when not needed anymore. 11 | ///builder 会指定数据 model 并初始化。 12 | builder: (context) => Counter(), 13 | child: MyApp(), 14 | ), 15 | ); 16 | } 17 | 18 | /// Simplest possible model, with just one field. 19 | /// 20 | /// [ChangeNotifier] is a class in `flutter:foundation`. [Counter] does 21 | /// _not_ depend on Provider. 22 | /// 23 | /// 24 | class Counter with ChangeNotifier { 25 | ///这个 model 只管理一个变量。 26 | int value = 0; 27 | 28 | ///操作变量 29 | void increment() { 30 | value += 1; 31 | notifyListeners(); 32 | } 33 | } 34 | 35 | class MyApp extends StatelessWidget { 36 | @override 37 | Widget build(BuildContext context) { 38 | return MaterialApp( 39 | title: 'Flutter Demo', 40 | theme: ThemeData( 41 | primarySwatch: Colors.blue, 42 | ), 43 | home: MyHomePage(), 44 | ); 45 | } 46 | } 47 | 48 | class MyHomePage extends StatelessWidget { 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | ///通过 Provider.of 方式获取 model 53 | final _counter = Provider.of(context); 54 | 55 | return Scaffold( 56 | appBar: AppBar( 57 | title: Text('Flutter Demo Home Page'), 58 | ), 59 | body: Center( 60 | child: Column( 61 | mainAxisAlignment: MainAxisAlignment.center, 62 | children: [ 63 | Text('使用 Consumer 获取 model:'), 64 | // Consumer looks for an ancestor Provider widget 65 | // and retrieves its model (Counter, in this case). 66 | // Then it uses that model to build widgets, and will trigger 67 | // rebuilds if the model is updated. 68 | 69 | ///Consumer 回向上寻找 Provider 类型的父类 Widget,并且取出 Provider 关联的 Model,根据这个 model 来构建 widget 70 | ///并且当 model 数据发生改变时,回触发更新。 71 | /// 72 | 73 | Consumer( 74 | builder: (context, counter, child) => Text( 75 | '${counter.value}', 76 | style: Theme.of(context).textTheme.display1, 77 | ), 78 | ), 79 | 80 | Text('使用 Provider.of 方式 获取 model:'), 81 | Text('${_counter.value}',), 82 | ], 83 | ), 84 | ), 85 | floatingActionButton: FloatingActionButton( 86 | /// listen 为 false 表示不监听状态改变,默认时 true 87 | onPressed: () => Provider.of(context, listen: false).increment(), 88 | tooltip: 'Increment', 89 | child: Icon(Icons.add), 90 | ), 91 | 92 | 93 | ///需要修改 Model 同样可以使用 Consumer 的方式 94 | // floatingActionButton: Consumer( 95 | // builder: (context, Counter counter, child) => FloatingActionButton( 96 | // onPressed: counter.increment, 97 | // child: child, 98 | // ), 99 | // child: Icon(Icons.add), 100 | // ), 101 | 102 | 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/stateManager/EventProvider.dart: -------------------------------------------------------------------------------- 1 | // EventProvider (Stream) 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | import '../main.dart'; 6 | 7 | class EventProvider { 8 | 9 | Stream intStream() { 10 | Duration interval = Duration(seconds: 2); 11 | // ThemeData themeData = _themeData == ThemeData.light()?ThemeData.dark():ThemeData.light() 12 | return Stream.periodic(interval, (int _count) => _count %2 == 0?ThemeData.light():ThemeData.dark() ); 13 | //return Stream.periodic(interval, (int _count) => _count %2 == 0? 11: 22 ); 14 | // return Stream.periodic(interval, (int _count) => _count++); 15 | 16 | } 17 | 18 | 19 | } -------------------------------------------------------------------------------- /lib/stateManager/User.dart: -------------------------------------------------------------------------------- 1 | 2 | // User Model 3 | class User { 4 | final String firstName, lastName, website; 5 | const User(this.firstName, this.lastName, this.website); 6 | 7 | User.fromJson(Map json): 8 | this.firstName = json['first_name'], 9 | this.lastName = json['last_name'], 10 | this.website = json['website']; 11 | 12 | Map toJson() => { 13 | "first_name": this.firstName, 14 | "last_name": this.lastName, 15 | "website": this.website 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /lib/stateManager/UserList.dart: -------------------------------------------------------------------------------- 1 | // User List Model 2 | import 'User.dart'; 3 | 4 | class UserList { 5 | final List users; 6 | UserList(this.users); 7 | 8 | UserList.fromJson(List usersJson) : 9 | users = usersJson.map((user) => User.fromJson(user)).toList(); 10 | } -------------------------------------------------------------------------------- /lib/stateManager/common/theme.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Flutter team. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | final appTheme = ThemeData( 8 | primarySwatch: Colors.yellow, 9 | textTheme: TextTheme( 10 | display4: TextStyle( 11 | fontFamily: 'Corben', 12 | fontWeight: FontWeight.w700, 13 | fontSize: 24, 14 | color: Colors.black, 15 | ), 16 | ), 17 | ); 18 | -------------------------------------------------------------------------------- /lib/stateManager/index_main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_share/stateManager/user_provider.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | import 'BasicCounter.dart'; 8 | import 'EventProvider.dart'; 9 | import 'my_event_page.dart'; 10 | import 'my_userpage.dart'; 11 | 12 | void main() => runApp( 13 | // MyApp() 14 | MultiProvider( 15 | providers: [ 16 | ChangeNotifierProvider(builder: (_) => BasicCounter(0)), 17 | FutureProvider(builder: (_) => UserProvider().loadUserData()), 18 | StreamProvider(builder: (_) => EventProvider().intStream(), initialData:ThemeData.light()) 19 | ], 20 | child: MyApp() 21 | ) 22 | ); 23 | 24 | class MyApp extends StatelessWidget { 25 | @override 26 | Widget build(BuildContext context) { 27 | 28 | 29 | 30 | return MaterialApp( 31 | title: 'Flutter Demo', 32 | // theme: ThemeData.light(), 33 | // theme: themeData, 34 | theme: Provider.of(context), 35 | 36 | 37 | home: DefaultTabController( 38 | length: 3, 39 | child: DefaultTabController( 40 | length: 3, 41 | child: Scaffold( 42 | appBar: AppBar( 43 | title: Text("Provider Demo:" ), 44 | bottom: TabBar( 45 | tabs: [ 46 | Tab(icon: Icon(Icons.add)), 47 | Tab(icon: Icon(Icons.person)), 48 | Tab(icon: Icon(Icons.message)), 49 | ], 50 | ), 51 | ), 52 | body: TabBarView( 53 | children: [ 54 | HomePage(), 55 | MyUserPage(), 56 | MyEventPage(), 57 | ], 58 | ), 59 | ), 60 | ) 61 | ) 62 | 63 | ); 64 | } 65 | } 66 | 67 | 68 | 69 | 70 | class HomePage extends StatelessWidget { 71 | @override 72 | Widget build(BuildContext context) { 73 | final counter = Provider.of(context); 74 | return Scaffold( 75 | appBar: AppBar( 76 | title: Text("Provider Demo"), 77 | ), 78 | body: Center( 79 | child: Column( 80 | mainAxisAlignment: MainAxisAlignment.center, 81 | children: [ 82 | Text( 83 | 'You have pushed the button this many times:', 84 | ), 85 | Text( 86 | '${counter.getCounter()}', 87 | style: Theme.of(context).textTheme.display1, 88 | ), 89 | ], 90 | ), 91 | ), 92 | floatingActionButton: Column( 93 | mainAxisAlignment: MainAxisAlignment.end, 94 | children: [ 95 | FloatingActionButton( 96 | onPressed: counter.increment, 97 | tooltip: 'Increment', 98 | child: Icon(Icons.add), 99 | ), 100 | SizedBox(height: 10), 101 | FloatingActionButton( 102 | onPressed: counter.decrement, 103 | tooltip: 'Increment', 104 | child: Icon(Icons.remove), 105 | ) 106 | ], 107 | ), 108 | ); 109 | } 110 | } 111 | 112 | 113 | -------------------------------------------------------------------------------- /lib/stateManager/models/cart.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Flutter team. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/foundation.dart'; 6 | 7 | import 'catalog.dart'; 8 | 9 | class CartModel extends ChangeNotifier { 10 | /// The current catalog. Used to construct items from numeric ids. 11 | final CatalogModel _catalog; 12 | 13 | /// 购物车中存放商品的 list,只存 id 就行 14 | final List _itemIds; 15 | 16 | /// Construct a CartModel instance that is backed by a [CatalogModel] and 17 | /// an optional previous state of the cart. 18 | /// 19 | /// If [previous] is not `null`, it's items are copied to the newly 20 | /// constructed instance. 21 | CartModel(this._catalog, CartModel previous) 22 | : assert(_catalog != null), 23 | _itemIds = previous?._itemIds ?? []; 24 | 25 | 26 | 27 | /// 将存放商品 id 的数组转换为存放商品的数值,函数式编程。 28 | List get items => _itemIds.map((id) => _catalog.getById(id)).toList(); 29 | 30 | /// 获取价格总和,dart 中的 List 中有两个累加的方法 reduce 和 fold,fold 可以提供一个初始值。 31 | int get totalPrice => 32 | items.fold(0, (total, current) => total + current.price); 33 | 34 | ///添加商品,这个方法时外界可以修改 list 的唯一途径 35 | void add(Item item) { 36 | _itemIds.add(item.id); 37 | // This line tells [Model] that it should rebuild the widgets that 38 | // depend on it. 39 | notifyListeners(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/stateManager/models/catalog.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Flutter team. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | /// A proxy of the catalog of items the user can buy. 8 | /// 9 | /// In a real app, this might be backed by a backend and cached on device. 10 | /// In this sample app, the catalog is procedurally generated and infinite. 11 | /// 12 | /// For simplicity, the catalog is expected to be immutable (no products are 13 | /// expected to be added, removed or changed during the execution of the app). 14 | class CatalogModel { 15 | static const _itemNames = [ 16 | 'Code Smell', 17 | 'Control Flow', 18 | 'Interpreter', 19 | 'Recursion', 20 | 'Sprint', 21 | 'Heisenbug', 22 | 'Spaghetti', 23 | 'Hydra Code', 24 | 'Off-By-One', 25 | 'Scope', 26 | 'Callback', 27 | 'Closure', 28 | 'Automata', 29 | 'Bit Shift', 30 | 'Currying', 31 | ]; 32 | 33 | /// Get item by [id]. 34 | /// 35 | /// In this sample, the catalog is infinite, looping over [_itemNames]. 36 | Item getById(int id) => Item(id, _itemNames[id % _itemNames.length]); 37 | 38 | /// Get item by its position in the catalog. 39 | Item getByPosition(int position) { 40 | // In this simplified case, an item's position in the catalog 41 | // is also its id. 42 | return getById(position); 43 | } 44 | } 45 | 46 | @immutable 47 | class Item { 48 | final int id; 49 | final String name; 50 | final Color color; 51 | final int price = 42; 52 | 53 | Item(this.id, this.name) 54 | // To make the sample app look nicer, each item is given one of the 55 | // Material Design primary colors. 56 | : color = Colors.primaries[id % Colors.primaries.length]; 57 | 58 | @override 59 | int get hashCode => id; 60 | 61 | @override 62 | bool operator ==(Object other) => other is Item && other.id == id; 63 | } 64 | -------------------------------------------------------------------------------- /lib/stateManager/my_event_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | class MyEventPage extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | //var _value = Provider.of(context); 8 | var _value =0; 9 | return Container( 10 | child: Center( 11 | child: Column( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | children: [ 14 | Text('StreamProvider Example'), 15 | SizedBox(height: 150), 16 | Text('${_value.toString()}', 17 | style: Theme.of(context).textTheme.display1 18 | ) 19 | ], 20 | ) 21 | ) 22 | ); 23 | } 24 | } -------------------------------------------------------------------------------- /lib/stateManager/my_userpage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | import 'User.dart'; 6 | 7 | class MyUserPage extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | var _users = Provider.of>(context); 11 | return Column( 12 | children: [ 13 | Padding( 14 | padding: EdgeInsets.all(10.0), 15 | child: Text( 16 | 'FutureProvider Example, users loaded from a File' 17 | ), 18 | ), 19 | Expanded( 20 | child: _users == null ? Container(child: CupertinoActivityIndicator(radius: 50.0)) : 21 | ListView.builder( 22 | itemCount: _users.length, 23 | itemBuilder: (context, index){ 24 | return Container( 25 | height: 50, 26 | color: Colors.grey[(index*200) % 400], 27 | child: Center( 28 | child: Text( 29 | '${_users[index].firstName} ${_users[index].lastName} | ${_users[index].website}' 30 | ) 31 | ) 32 | ); 33 | } 34 | ) 35 | ) 36 | ], 37 | ); 38 | } 39 | } -------------------------------------------------------------------------------- /lib/stateManager/screens/cart.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Flutter team. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_share/stateManager/models/cart.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | class MyCart extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: Text('Cart', style: Theme.of(context).textTheme.display4), 15 | backgroundColor: Colors.white, 16 | ), 17 | body: Container( 18 | color: Colors.yellow, 19 | child: Column( 20 | children: [ 21 | Expanded( 22 | child: Padding( 23 | padding: const EdgeInsets.all(32), 24 | child: _CartList(), 25 | ), 26 | ), 27 | Divider(height: 4, color: Colors.black), 28 | ///价格 29 | _CartTotal() 30 | ], 31 | ), 32 | ), 33 | ); 34 | } 35 | } 36 | 37 | class _CartList extends StatelessWidget { 38 | @override 39 | Widget build(BuildContext context) { 40 | var itemNameStyle = Theme.of(context).textTheme.title; 41 | 42 | ///使用 Provider.of 方式获取 CartModel 43 | var cart = Provider.of(context); 44 | 45 | return ListView.builder( 46 | itemCount: cart.items.length, 47 | itemBuilder: (context, index) => ListTile( 48 | leading: Icon(Icons.done), 49 | title: Text( 50 | cart.items[index].name, 51 | style: itemNameStyle, 52 | ), 53 | ), 54 | ); 55 | } 56 | } 57 | 58 | class _CartTotal extends StatelessWidget { 59 | @override 60 | Widget build(BuildContext context) { 61 | var hugeStyle = Theme.of(context).textTheme.display4.copyWith(fontSize: 48); 62 | 63 | return SizedBox( 64 | height: 200, 65 | child: Center( 66 | child: Row( 67 | mainAxisAlignment: MainAxisAlignment.center, 68 | children: [ 69 | ///使用 Consumer 方式使用 CartModel 70 | Consumer( 71 | builder: (context, cart, child) => 72 | Text('\$${cart.totalPrice}', style: hugeStyle)), 73 | SizedBox(width: 24), 74 | FlatButton( 75 | onPressed: () { 76 | Scaffold.of(context).showSnackBar( 77 | SnackBar(content: Text('Buying not supported yet.'))); 78 | }, 79 | color: Colors.white, 80 | child: Text('BUY'), 81 | ), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/stateManager/screens/catalog.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Flutter team. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_share/stateManager/models/cart.dart'; 7 | import 'package:flutter_share/stateManager/models/catalog.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | 11 | class MyCatalog extends StatelessWidget { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | body: CustomScrollView( 16 | slivers: [ 17 | _MyAppBar(), 18 | ///上间距 19 | SliverToBoxAdapter(child: SizedBox(height: 12)), 20 | SliverList( 21 | delegate: SliverChildBuilderDelegate( 22 | (context, index) => _MyListItem(index) 23 | , 24 | childCount: 25 ///本来时无限加载的,这里加上数量限制。 25 | ), 26 | ), 27 | ], 28 | ), 29 | ); 30 | } 31 | } 32 | 33 | class _AddButton extends StatelessWidget { 34 | final Item item; 35 | 36 | const _AddButton({Key key, @required this.item}) : super(key: key); 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | 41 | ///通过 Provider.of 方式使用 CartModel 42 | var cart = Provider.of(context); 43 | 44 | return FlatButton( 45 | ///判断是否为空,不为空 list 中添加 item 46 | onPressed: cart.items.contains(item) ? null : () => cart.add(item), 47 | splashColor: Theme.of(context).primaryColor, 48 | child: cart.items.contains(item) 49 | ? Icon(Icons.check, semanticLabel: 'ADDED') 50 | : Text('ADD'), 51 | ); 52 | } 53 | } 54 | 55 | class _MyAppBar extends StatelessWidget { 56 | @override 57 | Widget build(BuildContext context) { 58 | return SliverAppBar( 59 | title: Text('Catalog', style: Theme.of(context).textTheme.display4), 60 | floating: true, 61 | actions: [ 62 | IconButton( 63 | icon: Icon(Icons.shopping_cart), 64 | onPressed: () => Navigator.pushNamed(context, '/cart'), 65 | ), 66 | ], 67 | ); 68 | } 69 | } 70 | 71 | class _MyListItem extends StatelessWidget { 72 | final int index; 73 | 74 | _MyListItem(this.index, {Key key}) : super(key: key); 75 | 76 | @override 77 | Widget build(BuildContext context) { 78 | 79 | ///Provider.of 方式获取 model 80 | var catalog = Provider.of(context); 81 | var item = catalog.getByPosition(index); 82 | var textTheme = Theme.of(context).textTheme.title; 83 | 84 | return Padding( 85 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), 86 | child: LimitedBox( 87 | maxHeight: 48, 88 | child: Row( 89 | children: [ 90 | AspectRatio( 91 | aspectRatio: 1, 92 | child: Container( 93 | color: item.color, 94 | ), 95 | ), 96 | SizedBox(width: 24), 97 | Expanded( 98 | child: Text(item.name, style: textTheme), 99 | ), 100 | SizedBox(width: 24), 101 | _AddButton(item: item), 102 | ], 103 | ), 104 | ), 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/stateManager/user_provider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/services.dart'; 4 | 5 | import 'User.dart'; 6 | import 'UserList.dart'; 7 | 8 | class UserProvider { 9 | final String _dataPath = "assets/data/users.json"; 10 | List users; 11 | 12 | Future> loadUserData( ) async { 13 | var dataString = await loadAsset(); 14 | Map jsonUserData = jsonDecode(dataString); 15 | users = UserList.fromJson(jsonUserData['users']).users; 16 | print('done loading user!' + jsonEncode(users)); 17 | return users; 18 | } 19 | 20 | Future loadAsset() async { 21 | return await Future.delayed(Duration(seconds: 10), () async { 22 | return await rootBundle.loadString('assets/data/users.json'); 23 | }); 24 | } 25 | } -------------------------------------------------------------------------------- /lib/utils/json_config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/services.dart' show rootBundle; 4 | 5 | /// 缓存配置信息,避免多次读取文件 6 | const Map cache = {}; 7 | 8 | /// 获取 json 配置文件 9 | /// 10 | /// 在使用该方法前,需要在 pubspec.yaml 中增加 assets 的配置引入 11 | class JsonConfig { 12 | /// 读取 json 配置文件,并解析返回 13 | static Future getConfig(String fileName) async { 14 | if(cache[fileName] != null){ 15 | return cache[fileName]; 16 | } 17 | final jsonString = await rootBundle.loadString('assets/json/${fileName}.dart'); 18 | try { 19 | var jsonRet = json.decode(jsonString); 20 | cache[fileName] = jsonRet; 21 | return jsonRet; 22 | } catch (err){ 23 | // @todo add report log 24 | return false; 25 | } 26 | } 27 | 28 | /// object convert to map data 29 | static Map objectToMap(Object data) { 30 | return jsonDecode(JsonCodec().encode(data)) as Map; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: "direct main" 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.5.0-nullsafety.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.1.0-nullsafety.1" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.1.0-nullsafety.3" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.2.0-nullsafety.1" 32 | charts_common: 33 | dependency: transitive 34 | description: 35 | name: charts_common 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "0.9.0" 39 | charts_flutter: 40 | dependency: "direct main" 41 | description: 42 | name: charts_flutter 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "0.9.0" 46 | clock: 47 | dependency: transitive 48 | description: 49 | name: clock 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.1.0-nullsafety.1" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "1.15.0-nullsafety.3" 60 | cupertino_icons: 61 | dependency: "direct main" 62 | description: 63 | name: cupertino_icons 64 | url: "https://pub.flutter-io.cn" 65 | source: hosted 66 | version: "0.1.2" 67 | dio: 68 | dependency: "direct main" 69 | description: 70 | name: dio 71 | url: "https://pub.flutter-io.cn" 72 | source: hosted 73 | version: "3.0.9" 74 | fake_async: 75 | dependency: transitive 76 | description: 77 | name: fake_async 78 | url: "https://pub.flutter-io.cn" 79 | source: hosted 80 | version: "1.2.0-nullsafety.1" 81 | file_utils: 82 | dependency: "direct main" 83 | description: 84 | name: file_utils 85 | url: "https://pub.flutter-io.cn" 86 | source: hosted 87 | version: "0.1.4" 88 | flutter: 89 | dependency: "direct main" 90 | description: flutter 91 | source: sdk 92 | version: "0.0.0" 93 | flutter_test: 94 | dependency: "direct dev" 95 | description: flutter 96 | source: sdk 97 | version: "0.0.0" 98 | flutter_webview_plugin: 99 | dependency: "direct main" 100 | description: 101 | name: flutter_webview_plugin 102 | url: "https://pub.flutter-io.cn" 103 | source: hosted 104 | version: "0.3.0+2" 105 | globbing: 106 | dependency: transitive 107 | description: 108 | name: globbing 109 | url: "https://pub.flutter-io.cn" 110 | source: hosted 111 | version: "0.3.1" 112 | http_parser: 113 | dependency: transitive 114 | description: 115 | name: http_parser 116 | url: "https://pub.flutter-io.cn" 117 | source: hosted 118 | version: "3.1.4" 119 | intl: 120 | dependency: transitive 121 | description: 122 | name: intl 123 | url: "https://pub.flutter-io.cn" 124 | source: hosted 125 | version: "0.16.1" 126 | logging: 127 | dependency: transitive 128 | description: 129 | name: logging 130 | url: "https://pub.flutter-io.cn" 131 | source: hosted 132 | version: "0.11.4" 133 | matcher: 134 | dependency: transitive 135 | description: 136 | name: matcher 137 | url: "https://pub.flutter-io.cn" 138 | source: hosted 139 | version: "0.12.10-nullsafety.1" 140 | meta: 141 | dependency: transitive 142 | description: 143 | name: meta 144 | url: "https://pub.flutter-io.cn" 145 | source: hosted 146 | version: "1.3.0-nullsafety.3" 147 | path: 148 | dependency: transitive 149 | description: 150 | name: path 151 | url: "https://pub.flutter-io.cn" 152 | source: hosted 153 | version: "1.8.0-nullsafety.1" 154 | path_provider: 155 | dependency: "direct main" 156 | description: 157 | name: path_provider 158 | url: "https://pub.flutter-io.cn" 159 | source: hosted 160 | version: "1.6.9" 161 | path_provider_macos: 162 | dependency: transitive 163 | description: 164 | name: path_provider_macos 165 | url: "https://pub.flutter-io.cn" 166 | source: hosted 167 | version: "0.0.4+3" 168 | path_provider_platform_interface: 169 | dependency: transitive 170 | description: 171 | name: path_provider_platform_interface 172 | url: "https://pub.flutter-io.cn" 173 | source: hosted 174 | version: "1.0.2" 175 | platform: 176 | dependency: transitive 177 | description: 178 | name: platform 179 | url: "https://pub.flutter-io.cn" 180 | source: hosted 181 | version: "2.2.1" 182 | plugin_platform_interface: 183 | dependency: transitive 184 | description: 185 | name: plugin_platform_interface 186 | url: "https://pub.flutter-io.cn" 187 | source: hosted 188 | version: "1.0.2" 189 | provider: 190 | dependency: "direct main" 191 | description: 192 | name: provider 193 | url: "https://pub.flutter-io.cn" 194 | source: hosted 195 | version: "3.1.0" 196 | simple_permissions: 197 | dependency: "direct main" 198 | description: 199 | name: simple_permissions 200 | url: "https://pub.flutter-io.cn" 201 | source: hosted 202 | version: "0.1.9" 203 | sky_engine: 204 | dependency: transitive 205 | description: flutter 206 | source: sdk 207 | version: "0.0.99" 208 | source_span: 209 | dependency: transitive 210 | description: 211 | name: source_span 212 | url: "https://pub.flutter-io.cn" 213 | source: hosted 214 | version: "1.8.0-nullsafety.2" 215 | stack_trace: 216 | dependency: transitive 217 | description: 218 | name: stack_trace 219 | url: "https://pub.flutter-io.cn" 220 | source: hosted 221 | version: "1.10.0-nullsafety.1" 222 | stream_channel: 223 | dependency: transitive 224 | description: 225 | name: stream_channel 226 | url: "https://pub.flutter-io.cn" 227 | source: hosted 228 | version: "2.1.0-nullsafety.1" 229 | string_scanner: 230 | dependency: transitive 231 | description: 232 | name: string_scanner 233 | url: "https://pub.flutter-io.cn" 234 | source: hosted 235 | version: "1.1.0-nullsafety.1" 236 | term_glyph: 237 | dependency: transitive 238 | description: 239 | name: term_glyph 240 | url: "https://pub.flutter-io.cn" 241 | source: hosted 242 | version: "1.2.0-nullsafety.1" 243 | test_api: 244 | dependency: transitive 245 | description: 246 | name: test_api 247 | url: "https://pub.flutter-io.cn" 248 | source: hosted 249 | version: "0.2.19-nullsafety.2" 250 | typed_data: 251 | dependency: transitive 252 | description: 253 | name: typed_data 254 | url: "https://pub.flutter-io.cn" 255 | source: hosted 256 | version: "1.3.0-nullsafety.3" 257 | uni_links: 258 | dependency: "direct main" 259 | description: 260 | name: uni_links 261 | url: "https://pub.flutter-io.cn" 262 | source: hosted 263 | version: "0.4.0" 264 | vector_math: 265 | dependency: transitive 266 | description: 267 | name: vector_math 268 | url: "https://pub.flutter-io.cn" 269 | source: hosted 270 | version: "2.1.0-nullsafety.3" 271 | sdks: 272 | dart: ">=2.10.0-110 <2.11.0" 273 | flutter: ">=1.12.13+hotfix.5 <2.0.0" 274 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_share 2 | description: A new Flutter application. 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.1.0 <3.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: ^0.1.2 26 | 27 | #网络请求 28 | dio: ^3.0.9 29 | 30 | #provider 全局状态管理 31 | provider: ^3.0.1 32 | 33 | #图形图表绘制 34 | charts_flutter: ^0.9.0 35 | 36 | #异步依赖 37 | async: ^2.3.0 38 | 39 | #文件路径管理 40 | path_provider: ^1.6.9 41 | 42 | #权限检查 43 | simple_permissions: ^0.1.9 44 | 45 | #文件管理 46 | file_utils: ^0.1.3 47 | 48 | 49 | #scheme 实用 50 | flutter_webview_plugin: 0.3.0+2 51 | uni_links: ^0.4.0 52 | 53 | 54 | 55 | 56 | dev_dependencies: 57 | flutter_test: 58 | sdk: flutter 59 | 60 | 61 | # For information on the generic Dart part of this file, see the 62 | # following page: https://dart.dev/tools/pub/pubspec 63 | 64 | # The following section is specific to Flutter. 65 | flutter: 66 | 67 | # The following line ensures that the Material Icons font is 68 | # included with your application, so that you can use the icons in 69 | # the material Icons class. 70 | uses-material-design: true 71 | 72 | assets: 73 | - images/bg.jpg 74 | - assets/data/users.json 75 | - images/ 76 | 77 | 78 | # To add assets to your application, add an assets section, like this: 79 | # assets: 80 | # - images/a_dot_burr.jpeg 81 | # - images/a_dot_ham.jpeg 82 | 83 | # An image asset can refer to one or more resolution-specific "variants", see 84 | # https://flutter.dev/assets-and-images/#resolution-aware. 85 | 86 | # For details regarding adding assets from package dependencies, see 87 | # https://flutter.dev/assets-and-images/#from-packages 88 | 89 | # To add custom fonts to your application, add a fonts section here, 90 | # in this "flutter" section. Each entry in this list should have a 91 | # "family" key with the font family name, and a "fonts" key with a 92 | # list giving the asset and other descriptors for the font. For 93 | # example: 94 | # fonts: 95 | # - family: Schyler 96 | # fonts: 97 | # - asset: fonts/Schyler-Regular.ttf 98 | # - asset: fonts/Schyler-Italic.ttf 99 | # style: italic 100 | # - family: Trajan Pro 101 | # fonts: 102 | # - asset: fonts/TrajanPro.ttf 103 | # - asset: fonts/TrajanPro_Bold.ttf 104 | # weight: 700 105 | # 106 | # For details regarding fonts from package dependencies, 107 | # see https://flutter.dev/custom-fonts/#from-packages 108 | -------------------------------------------------------------------------------- /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/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_share/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------