├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ └── Project.xml ├── dictionaries │ ├── lizhuoyuan.xml │ └── zhuoy.xml ├── flutter_study.iml ├── libraries │ ├── Dart_Packages.xml │ ├── Dart_SDK.xml │ └── Flutter_Plugins.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .metadata ├── README.md ├── android ├── .gitignore ├── .idea │ ├── gradle.xml │ ├── misc.xml │ └── modules.xml ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── app │ ├── .classpath │ ├── .project │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── flutterapp │ │ │ └── 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 │ │ ├── string.xml │ │ └── styles.xml │ │ └── xml │ │ └── filepaths.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── flutter_app.iml ├── flutter_app_android.iml ├── images ├── a.png ├── beauty.jpg ├── home.png ├── jay.jpg ├── login.png ├── pavlova.png ├── pic1.jpg ├── pic2.jpg ├── pic3.jpg └── timg.jpg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter.podspec │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── 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 ├── bean │ ├── number_attribution.dart │ └── picker_data.dart ├── common │ └── constant.dart ├── locale │ ├── i18n_en.json │ ├── i18n_zh.json │ └── translations_delegate.dart ├── main.dart ├── model │ ├── AppModel.dart │ └── note.dart ├── page │ ├── ChipPage.dart │ ├── ExpansionTilePage.dart │ ├── FavoriteWidget.dart │ ├── FutureBuilderPage.dart │ ├── GridViewPage.dart │ ├── ImagePage.dart │ ├── KeepAlivePage.dart │ ├── MyHomePage.dart │ ├── PavlovaPage.dart │ ├── RandomWords.dart │ ├── ScreenUtilTest.dart │ ├── StateWidgetPage.dart │ ├── SwiperPage.dart │ ├── Transform3D.dart │ ├── alive_home_page.dart │ ├── animation_page.dart │ ├── animation_two.dart │ ├── backdrop_page.dart │ ├── cupertino_action_sheet_page.dart │ ├── custom_animation_page.dart │ ├── custom_scrollview_page.dart │ ├── draggable_dragtargets.dart │ ├── draggable_scrollable_sheet_page.dart │ ├── extension_page.dart │ ├── flutter_native_web.dart │ ├── flutter_picker_page.dart │ ├── fractionally_sized_box_page.dart │ ├── login_page.dart │ ├── map_search_page.dart │ ├── modal_page.dart │ ├── repaint_boundary_page.dart │ ├── route_page.dart │ ├── search_page.dart │ ├── share_page.dart │ ├── sliver_page.dart │ ├── sqflite_page.dart │ ├── stepper_page.dart │ ├── tab_page.dart │ ├── textField.dart │ ├── theme_page.dart │ ├── tree_page.dart │ ├── video_player.dart │ └── wrap_page.dart ├── routes.dart ├── rxdart │ ├── bloc_provider.dart │ └── theme_select.dart ├── theme │ └── app_theme.dart ├── utils │ ├── HttpUtil.dart │ ├── dbHelper.dart │ ├── image_util.dart │ └── share_util.dart └── widget │ ├── backdrop.dart │ ├── node.dart │ ├── searchbar_delegate.dart │ ├── transform_animation_widget.dart │ └── verification_code.dart ├── pubspec.lock ├── pubspec.yaml └── test ├── study.dart └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/flutter 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=flutter 3 | 4 | # IntelliJ related 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .idea/ 9 | 10 | ### Flutter ### 11 | # Flutter/Dart/Pub related 12 | **/doc/api/ 13 | .dart_tool/ 14 | .flutter-plugins 15 | .flutter-plugins-dependencies 16 | .packages 17 | .pub-cache/ 18 | .pub/ 19 | build/ 20 | lib/generated_plugin_registrant.dart 21 | 22 | # Android related 23 | **/android/**/gradle-wrapper.jar 24 | **/android/.gradle 25 | **/android/captures/ 26 | **/android/gradlew 27 | **/android/gradlew.bat 28 | **/android/key.properties 29 | **/android/local.properties 30 | **/android/**/GeneratedPluginRegistrant.java 31 | 32 | # iOS/XCode related 33 | **/ios/**/*.mode1v3 34 | **/ios/**/*.mode2v3 35 | **/ios/**/*.moved-aside 36 | **/ios/**/*.pbxuser 37 | **/ios/**/*.perspectivev3 38 | **/ios/**/*sync/ 39 | **/ios/**/.sconsign.dblite 40 | **/ios/**/.tags* 41 | **/ios/**/.vagrant/ 42 | **/ios/**/DerivedData/ 43 | **/ios/**/Icon? 44 | **/ios/**/Pods/ 45 | **/ios/**/.symlinks/ 46 | **/ios/**/profile 47 | **/ios/**/xcuserdata 48 | **/ios/.generated/ 49 | **/ios/Flutter/App.framework 50 | **/ios/Flutter/Flutter.framework 51 | **/ios/Flutter/Flutter.podspec 52 | **/ios/Flutter/Generated.xcconfig 53 | **/ios/Flutter/app.flx 54 | **/ios/Flutter/app.zip 55 | **/ios/Flutter/flutter_assets/ 56 | **/ios/Flutter/flutter_export_environment.sh 57 | **/ios/ServiceDefinitions.json 58 | **/ios/Runner/GeneratedPluginRegistrant.* 59 | 60 | # Exceptions to above rules. 61 | !**/ios/**/default.mode1v3 62 | !**/ios/**/default.mode2v3 63 | !**/ios/**/default.pbxuser 64 | !**/ios/**/default.perspectivev3 65 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 66 | 67 | # End of https://www.toptal.com/developers/gitignore/api/flutter -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/dictionaries/lizhuoyuan.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | screenutil 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/dictionaries/zhuoy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | baidu 5 | uint 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.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: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b 8 | channel: beta 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_app 2 | 3 | [相关内容的flutter专栏](https://zhuoyuan.blog.csdn.net/column/info/27607) 4 | 5 | [国际化教程](https://github.com/lizhuoyuan/flutter_intl_example) 6 | 7 | ![效果](./images/a.png) 8 | ![login](./images/login.png) 9 | ![home](./images/home.png) 10 | ![pavlova](./images/pavlova.png) 11 | ## Getting Started 12 | 13 | For help getting started with Flutter, view our online 14 | [documentation](https://flutter.io/). 15 | 16 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.class 3 | .gradle 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /captures 10 | GeneratedPluginRegistrant.java 11 | -------------------------------------------------------------------------------- /android/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 43 | 44 | -------------------------------------------------------------------------------- /android/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /android/.idea/modules.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /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 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | 17 | 18 | android { 19 | compileSdkVersion 28 20 | 21 | lintOptions { 22 | disable 'InvalidPackage' 23 | } 24 | 25 | aaptOptions { 26 | noCompress "webp" 27 | } 28 | 29 | defaultConfig { 30 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 31 | applicationId "com.example.flutterapp" 32 | minSdkVersion 18 33 | targetSdkVersion 29 34 | versionCode 1 35 | versionName "1.0" 36 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 37 | multiDexEnabled true 38 | 39 | } 40 | 41 | signingConfigs { 42 | 43 | } 44 | 45 | buildTypes { 46 | 47 | } 48 | } 49 | 50 | flutter { 51 | source '../..' 52 | } 53 | 54 | dependencies { 55 | testImplementation 'junit:junit:4.12' 56 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' 57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' 58 | implementation 'com.android.support:multidex:1.0.3' 59 | } 60 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 11 | 12 | 17 | 22 | 29 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 63 | 66 | 67 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/flutterapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.flutterapp; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 343254889799245 4 | flutter study. 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/filepaths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:4.0.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1536M 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 20 17:26:01 CST 2020 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-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /flutter_app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /flutter_app_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /images/a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/a.png -------------------------------------------------------------------------------- /images/beauty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/beauty.jpg -------------------------------------------------------------------------------- /images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/home.png -------------------------------------------------------------------------------- /images/jay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/jay.jpg -------------------------------------------------------------------------------- /images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/login.png -------------------------------------------------------------------------------- /images/pavlova.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/pavlova.png -------------------------------------------------------------------------------- /images/pic1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/pic1.jpg -------------------------------------------------------------------------------- /images/pic2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/pic2.jpg -------------------------------------------------------------------------------- /images/pic3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/pic3.jpg -------------------------------------------------------------------------------- /images/timg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/images/timg.jpg -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/app.flx 37 | /Flutter/app.zip 38 | /Flutter/flutter_assets/ 39 | /Flutter/App.framework 40 | /Flutter/Flutter.framework 41 | /Flutter/Generated.xcconfig 42 | /ServiceDefinitions.json 43 | 44 | Pods/ 45 | .symlinks/ 46 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 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/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/lizhuoyuan/Development/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/lizhuoyuan/Development/Project/flutter_study" 5 | export "FLUTTER_TARGET=lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Users/lizhuoyuan/Development/flutter/bin/cache/artifacts/engine/ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | -------------------------------------------------------------------------------- /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 parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | # Flutter Pod 37 | 38 | copied_flutter_dir = File.join(__dir__, 'Flutter') 39 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 40 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 41 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 42 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 43 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 44 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 45 | 46 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 47 | unless File.exist?(generated_xcode_build_settings_path) 48 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 49 | end 50 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 51 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 52 | 53 | unless File.exist?(copied_framework_path) 54 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 55 | end 56 | unless File.exist?(copied_podspec_path) 57 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 58 | end 59 | end 60 | 61 | # Keep pod path relative so it can be checked into Podfile.lock. 62 | pod 'Flutter', :path => 'Flutter' 63 | 64 | # Plugin Pods 65 | 66 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 67 | # referring to absolute paths on developers' machines. 68 | system('rm -rf .symlinks') 69 | system('mkdir -p .symlinks/plugins') 70 | plugin_pods = parse_KV_file('../.flutter-plugins') 71 | plugin_pods.each do |name, path| 72 | symlink = File.join('.symlinks', 'plugins', name) 73 | File.symlink(path, symlink) 74 | pod name, :path => File.join(symlink, 'ios') 75 | end 76 | end 77 | 78 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 79 | install! 'cocoapods', :disable_input_output_paths => true 80 | 81 | post_install do |installer| 82 | installer.pods_project.targets.each do |target| 83 | target.build_configurations.each do |config| 84 | config.build_settings['ENABLE_BITCODE'] = 'NO' 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /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 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuoyuan/flutter_study/1dd31f1267d37c11c56a6af3e998026543968b9c/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 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_app 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 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 | 46 | -------------------------------------------------------------------------------- /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/bean/number_attribution.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/11/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 号码归属地信息的实体类 5 | */ 6 | 7 | class NumberAttribution { 8 | String province; 9 | String city; 10 | String areacode; 11 | String zip; 12 | String company; 13 | String card; 14 | 15 | NumberAttribution( 16 | {this.province, 17 | this.city, 18 | this.areacode, 19 | this.zip, 20 | this.company, 21 | this.card}); 22 | 23 | NumberAttribution.fromJson(Map json) { 24 | province = json['province']; 25 | city = json['city']; 26 | areacode = json['areacode']; 27 | zip = json['zip']; 28 | company = json['company']; 29 | card = json['card']; 30 | } 31 | 32 | Map toJson() { 33 | final Map data = new Map(); 34 | data['province'] = this.province; 35 | data['city'] = this.city; 36 | data['areacode'] = this.areacode; 37 | data['zip'] = this.zip; 38 | data['company'] = this.company; 39 | data['card'] = this.card; 40 | return data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/bean/picker_data.dart: -------------------------------------------------------------------------------- 1 | const PickerData = ''' 2 | [ 3 | { 4 | "a": [ 5 | { 6 | "a1": [ 7 | 1, 8 | 2, 9 | 3, 10 | 4 11 | ] 12 | }, 13 | { 14 | "a2": [ 15 | 5, 16 | 6, 17 | 7, 18 | 8, 19 | 555, 20 | 666, 21 | 999 22 | ] 23 | }, 24 | { 25 | "a3": [ 26 | 9, 27 | 10, 28 | 11, 29 | 12 30 | ] 31 | } 32 | ] 33 | }, 34 | { 35 | "b": [ 36 | { 37 | "b1": [ 38 | 11, 39 | 22, 40 | 33, 41 | 44 42 | ] 43 | }, 44 | { 45 | "b2": [ 46 | 55, 47 | 66, 48 | 77, 49 | 88, 50 | 99, 51 | 1010, 52 | 1111, 53 | 1212, 54 | 1313, 55 | 1414, 56 | 1515, 57 | 1616 58 | ] 59 | }, 60 | { 61 | "b3": [ 62 | 1010, 63 | 1111, 64 | 1212, 65 | 1313, 66 | 1414, 67 | 1515, 68 | 1616 69 | ] 70 | } 71 | ] 72 | }, 73 | { 74 | "c": [ 75 | { 76 | "c1": [ 77 | "a", 78 | "b", 79 | "c" 80 | ] 81 | }, 82 | { 83 | "c2": [ 84 | "aa", 85 | "bb", 86 | "cc" 87 | ] 88 | }, 89 | { 90 | "c3": [ 91 | "aaa", 92 | "bbb", 93 | "ccc" 94 | ] 95 | }, 96 | { 97 | "c4": [ 98 | "a1", 99 | "b1", 100 | "c1", 101 | "d1" 102 | ] 103 | } 104 | ] 105 | } 106 | ] 107 | '''; 108 | 109 | const PickerData2 = ''' 110 | [ 111 | [ 112 | 1, 113 | 2, 114 | 3, 115 | 4 116 | ], 117 | [ 118 | 11, 119 | 22, 120 | 33, 121 | 44 122 | ], 123 | [ 124 | "aaa", 125 | "bbb", 126 | "ccc" 127 | ] 128 | ] 129 | '''; -------------------------------------------------------------------------------- /lib/common/constant.dart: -------------------------------------------------------------------------------- 1 | const PLACES_API_KEY = 'AIzaSyA17XB_P_TwEdg_MWQFZvKuyWYmaQunmdY'; 2 | -------------------------------------------------------------------------------- /lib/locale/i18n_en.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_title": "My Application Title", 3 | "main_title": "My Main Title", 4 | "homePage":"Home Page" 5 | } 6 | -------------------------------------------------------------------------------- /lib/locale/i18n_zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_title": "我的应用标题", 3 | "main_title": "我的主要标题", 4 | "homePage":"主页面" 5 | 6 | } 7 | -------------------------------------------------------------------------------- /lib/locale/translations_delegate.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/11/22. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'dart:convert'; 8 | import 'dart:async'; 9 | 10 | import 'package:flutter/material.dart'; 11 | import 'package:flutter/services.dart'; 12 | 13 | class Translations { 14 | Locale locale; 15 | static Map _localizedValues; 16 | 17 | Translations(Locale locale) { 18 | this.locale = locale; 19 | _localizedValues = null; 20 | } 21 | 22 | static Translations of(BuildContext context) => 23 | Localizations.of(context, Translations); 24 | 25 | String get(String key) => _localizedValues[key] ?? '** $key not found'; 26 | 27 | static Future load(Locale locale) async { 28 | Translations translations = new Translations(locale); 29 | String jsonContent = 30 | await rootBundle.loadString('lib/locale/i18n_${locale.languageCode}.json'); 31 | _localizedValues = json.decode(jsonContent); 32 | return translations; 33 | } 34 | 35 | get currentLanguage => locale.languageCode; 36 | } 37 | 38 | class TranslationsDelegate extends LocalizationsDelegate { 39 | const TranslationsDelegate(); 40 | 41 | ///验证支持的语言 42 | @override 43 | bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode); 44 | 45 | @override 46 | Future load(Locale locale) => Translations.load(locale); 47 | 48 | @override 49 | bool shouldReload(LocalizationsDelegate old) => false; 50 | } 51 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_app/locale/translations_delegate.dart'; 5 | import 'package:flutter_app/routes.dart'; 6 | import 'package:flutter_app/rxdart/bloc_provider.dart'; 7 | import 'package:flutter_app/theme/app_theme.dart'; 8 | import 'package:flutter_localizations/flutter_localizations.dart'; 9 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 10 | 11 | bool get isInDebugMode { 12 | bool inDebugMode = false; 13 | assert(inDebugMode = true); 14 | return inDebugMode; 15 | } 16 | 17 | /// Reports [error] along with its [stackTrace] to Sentry.io. 18 | Future _reportError(dynamic error, dynamic stackTrace) async { 19 | print('-Caught error: $error'); 20 | 21 | // Errors thrown in development mode are unlikely to be interesting. You can 22 | // check if you are running in dev mode using an assertion and omit sending 23 | // the report. 24 | if (isInDebugMode) { 25 | print(stackTrace); 26 | print('In dev mode. Not sending report to Sentry.io.'); 27 | return; 28 | } 29 | 30 | print('Reporting to Sentry.io...'); 31 | 32 | print('Success! Event ID: '); 33 | } 34 | 35 | Future main() async { 36 | WidgetsFlutterBinding.ensureInitialized(); 37 | 38 | // This captures errors reported by the Flutter framework. 39 | FlutterError.onError = (FlutterErrorDetails details) async { 40 | if (isInDebugMode) { 41 | // In development mode simply print to console. 42 | FlutterError.dumpErrorToConsole(details); 43 | } else { 44 | // In production mode report to the application zone to report to 45 | // Sentry. 46 | Zone.current.handleUncaughtError(details.exception, details.stack); 47 | } 48 | }; 49 | runApp(BlocProvider(child: const MyApp())); 50 | // 51 | // runZonedGuarded>(() async { 52 | // runApp(BlocProvider(child: const MyApp())); 53 | // }, (error, stackTrace) async { 54 | // await _reportError(error, stackTrace); 55 | // }); 56 | } 57 | 58 | class MyApp extends StatelessWidget { 59 | const MyApp(); 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | //AppModel appModel = AppModel(); 64 | final themeSelect = BlocProvider.of(context); 65 | return StreamBuilder( 66 | builder: _builder, 67 | stream: themeSelect.value, 68 | initialData: false, 69 | ); 70 | } 71 | 72 | Widget _builder(BuildContext context, AsyncSnapshot snapshot) { 73 | return ScreenUtilInit( 74 | allowFontScaling: false, 75 | designSize: Size(360, 720), 76 | child: MaterialApp( 77 | title: 'Welcome to Flutter_study', 78 | theme: snapshot.data ? AppTheme().darkTheme : AppTheme().lightTheme, 79 | localizationsDelegates: [ 80 | const TranslationsDelegate(), 81 | GlobalMaterialLocalizations.delegate, 82 | GlobalWidgetsLocalizations.delegate, 83 | ], 84 | supportedLocales: [Locale("zh"), Locale("en")], 85 | initialRoute: '/', 86 | routes: routes, 87 | onGenerateRoute: onGenerateRoute, 88 | navigatorObservers: [ 89 | Ob1(), 90 | ], 91 | )); 92 | } 93 | } 94 | 95 | class Ob1 extends NavigatorObserver { 96 | @override 97 | void didPush(Route route, Route previousRoute) { 98 | super.didPush(route, previousRoute); 99 | print('从${previousRoute?.settings?.name}到${route?.settings?.name}'); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /lib/model/AppModel.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/10/8. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:scoped_model/scoped_model.dart'; 9 | 10 | class AppModel extends Model { 11 | bool _isNight = false; 12 | ThemeData _darkTheme = ThemeData( 13 | backgroundColor: Colors.black, 14 | primaryColor: Colors.black, 15 | brightness: Brightness.dark); 16 | 17 | ThemeData _lightTheme = ThemeData( 18 | backgroundColor: Colors.white, 19 | primaryColor: Colors.green, 20 | primarySwatch: Colors.blue, 21 | brightness: Brightness.light); 22 | 23 | get theme => _isNight ? _darkTheme : _lightTheme; 24 | 25 | get isNight => _isNight; 26 | 27 | ///true为夜间模式 28 | void changeTheme(bool value) { 29 | _isNight = value; 30 | notifyListeners(); 31 | } 32 | 33 | static AppModel of(BuildContext context) => ScopedModel.of(context); 34 | } 35 | -------------------------------------------------------------------------------- /lib/model/note.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/3/12. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | class Note { 8 | int _pointID; 9 | String _image; 10 | int _contractId; 11 | int _publicationId; 12 | double _pointLng; 13 | double _pointLat; 14 | 15 | Note(this._pointID, this._image, this._contractId, this._publicationId, 16 | this._pointLng, this._pointLat); 17 | 18 | int get pointID => _pointID; 19 | 20 | String get image => _image; 21 | 22 | int get contractId => _contractId; 23 | 24 | int get publicationId => _publicationId; 25 | 26 | double get pointLng => _pointLng; 27 | 28 | double get pointLat => _pointLat; 29 | 30 | Map toMap() { 31 | var map = new Map(); 32 | map['pointid'] = _pointID; 33 | map['image'] = _image; 34 | map['contractId'] = _contractId; 35 | map['publicationId'] = _publicationId; 36 | map['pointLng'] = _pointLng; 37 | map['pointLat'] = _pointLat; 38 | return map; 39 | } 40 | 41 | Note.fromMap(Map map) { 42 | this._publicationId = map['publicationId']; 43 | this._pointID = map['pointid']; 44 | this._image = map['image']; 45 | this._contractId = map['contractId']; 46 | this._pointLng = map['pointLng']; 47 | this._pointLat = map['pointLat']; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/page/ChipPage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/10/9. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/bean/number_attribution.dart'; 9 | 10 | class ChipPage extends StatefulWidget { 11 | @override 12 | State createState() => ChipState(); 13 | } 14 | 15 | class ChipState extends State { 16 | List list = List.generate(10, (index) => 'index:$index'); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | formatJson(); 21 | return Scaffold( 22 | appBar: AppBar( 23 | title: Text('chip'), 24 | actions: [ 25 | const RightTopIconButton(), 26 | ], 27 | ), 28 | body: Wrap( 29 | spacing: 10.0, 30 | children: list 31 | .map((i) => Chip( 32 | label: Text(i.toString()), 33 | onDeleted: () { 34 | setState(() { 35 | list.remove(i); 36 | }); 37 | }, 38 | avatar: Icon( 39 | Icons.hourglass_full, 40 | color: Colors.red, 41 | ), 42 | )) 43 | .toList(), 44 | ), 45 | ); 46 | } 47 | 48 | void formatJson() { 49 | var jsons = { 50 | "province": "浙江", 51 | "city": "杭州", 52 | "areacode": "0571", 53 | "zip": "310000", 54 | "company": "中国移动", 55 | "card": "" 56 | }; 57 | NumberAttribution numberAttribution = NumberAttribution.fromJson(jsons); 58 | var toJ = numberAttribution.toJson(); 59 | print(toJ); 60 | } 61 | } 62 | 63 | class RightTopIconButton extends StatelessWidget { 64 | const RightTopIconButton(); 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | print('buildIconButton'); 69 | return IconButton( 70 | icon: Icon(Icons.add), 71 | onPressed: null, 72 | /*onPressed: () { 73 | setState(() { 74 | list.add('index:${list.length}'); 75 | }); 76 | }*/ 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/page/ExpansionTilePage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/10/9. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | 9 | class ExpansionTilePage extends StatefulWidget { 10 | @override 11 | State createState() => ExpandsionState(); 12 | } 13 | 14 | class ExpandsionState extends State 15 | with SingleTickerProviderStateMixin { 16 | Animation animation; 17 | AnimationController animationController; 18 | 19 | var _iconColor; 20 | 21 | List list = [ 22 | {'index': 1, 'opened': true}, 23 | {'index': 2, 'opened': false}, 24 | {'index': 3, 'opened': false}, 25 | ]; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | animationController = 31 | AnimationController(vsync: this, duration: Duration(milliseconds: 200)); 32 | animation = Tween(begin: 0.0, end: 0.125).animate(animationController); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return Scaffold( 38 | appBar: AppBar( 39 | title: Text('ExpansionTile'), 40 | ), 41 | body: ListView(children: [ 42 | ExpansionTile( 43 | title: Text('title'), 44 | leading: Icon(Icons.title), 45 | trailing: RotationTransition( 46 | turns: animation, 47 | child: Icon( 48 | Icons.add, 49 | color: _iconColor, 50 | ), 51 | ), 52 | onExpansionChanged: (bool value) { 53 | print(value); 54 | setState(() { 55 | if (value) { 56 | animationController.forward(); 57 | _iconColor = Colors.red; 58 | } else { 59 | animationController.reverse(); 60 | _iconColor = Colors.green; 61 | } 62 | }); 63 | }, 64 | children: [ 65 | ListTile( 66 | title: Text('1'), 67 | leading: Icon(Icons.map), 68 | ) 69 | ], 70 | ), 71 | ExpansionPanelList.radio( 72 | expansionCallback: (int i, bool opened) { 73 | print(i); 74 | print(opened); 75 | setState(() { 76 | list[i]['opened'] = !opened; 77 | }); 78 | }, 79 | children: list 80 | .map((item) => ExpansionPanelRadio( 81 | value: item, 82 | headerBuilder: (context, opened) { 83 | return ListTile( 84 | title: Text("更多内容+${item['index']}"), 85 | ); 86 | }, 87 | body: Text('aa${item['index']}'))) 88 | .toList(), 89 | ) 90 | ])); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/page/FavoriteWidget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FavoriteWidget extends StatefulWidget { 4 | @override 5 | State createState() => FavoriteWidgetState(); 6 | } 7 | 8 | class FavoriteWidgetState extends State { 9 | bool _isFavorited = true; 10 | int _favoriteCount = 41; 11 | 12 | void _toggleFavorite() { 13 | setState(() { 14 | // If the lake is currently favorited, unfavorite it. 15 | if (_isFavorited) { 16 | _favoriteCount -= 1; 17 | _isFavorited = false; 18 | // Otherwise, favorite it. 19 | } else { 20 | _favoriteCount += 1; 21 | _isFavorited = true; 22 | } 23 | }); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Row( 29 | mainAxisSize: MainAxisSize.min, 30 | children: [ 31 | Container( 32 | child: IconButton( 33 | icon: _isFavorited ? Icon(Icons.star) : Icon(Icons.star_border), 34 | color: Colors.green, 35 | onPressed: _toggleFavorite), 36 | ), 37 | SizedBox( 38 | width: 20.0, 39 | child: new Container( 40 | child: new Text('$_favoriteCount'), 41 | ), 42 | ), 43 | ], 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/page/FutureBuilderPage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/30. 3 | * email: zhuoyuan93@gmail.com 4 | * 关于状态改变引起的不必要的页面刷新: 5 | * https://github.com/flutter/flutter/issues/11426#issuecomment-414047398 6 | * 7 | * 2019/8/8 豆瓣api已挂...择日更新代码 8 | */ 9 | 10 | import 'dart:async'; 11 | 12 | import 'package:async/async.dart'; 13 | import 'package:flutter/material.dart'; 14 | import 'package:flutter_app/utils/HttpUtil.dart'; 15 | 16 | class FutureBuilderPage extends StatefulWidget { 17 | @override 18 | State createState() => FutureBuilderState(); 19 | } 20 | 21 | class FutureBuilderState extends State { 22 | String title = 'FutureBuilder使用'; 23 | AsyncMemoizer _memoizer = AsyncMemoizer(); 24 | 25 | _gerData() { 26 | return _memoizer.runOnce(() async { 27 | return await HttpUtil() 28 | .get('http://rap2api.taobao.org/app/mock/162762/skill/dragoon'); 29 | }); 30 | } 31 | 32 | Future _refreshData() async { 33 | setState(() { 34 | _memoizer = AsyncMemoizer(); 35 | }); 36 | } 37 | 38 | /* @override 39 | void initState() { 40 | super.initState(); 41 | _testGet(); 42 | } 43 | 44 | Future _testGet() async { 45 | var response = await HttpUtil().get('https://www.apiopen.top/novelApi'); 46 | 47 | print(response['data']); 48 | }*/ 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return Scaffold( 53 | appBar: AppBar( 54 | title: Text(title), 55 | ), 56 | floatingActionButton: FloatingActionButton( 57 | onPressed: () { 58 | setState(() { 59 | title = title + '.'; 60 | }); 61 | }, 62 | child: Icon(Icons.title), 63 | ), 64 | body: RefreshIndicator( 65 | onRefresh: _refreshData, 66 | child: FutureBuilder( 67 | builder: _buildFuture, 68 | future: _gerData(), // 用户定义的需要异步执行的代码,类型为Future或者null的变量或函数 69 | ), 70 | ), 71 | ); 72 | } 73 | 74 | ///snapshot就是_calculation在时间轴上执行过程的状态快照 75 | Widget _buildFuture(BuildContext context, AsyncSnapshot snapshot) { 76 | switch (snapshot.connectionState) { 77 | case ConnectionState.none: 78 | print('还没有开始网络请求'); 79 | return Text('还没有开始网络请求'); 80 | case ConnectionState.active: 81 | print('active'); 82 | return Text('ConnectionState.active'); 83 | case ConnectionState.waiting: 84 | print('waiting'); 85 | return Center( 86 | child: CircularProgressIndicator(), 87 | ); 88 | case ConnectionState.done: 89 | print('done'); 90 | if (snapshot.hasError) return Text('Error: ${snapshot.error}'); 91 | return _createListView(context, snapshot); 92 | default: 93 | return Text('还没有开始网络请求'); 94 | } 95 | } 96 | 97 | Widget _createListView(BuildContext context, AsyncSnapshot snapshot) { 98 | List movies = snapshot.data['data']; 99 | return ListView.builder( 100 | itemBuilder: (context, index) => _itemBuilder(context, index, movies), 101 | itemCount: movies.length * 2, 102 | ); 103 | } 104 | 105 | Widget _itemBuilder(BuildContext context, int index, skills) { 106 | if (index.isOdd) { 107 | return Divider(); 108 | } 109 | index = index ~/ 2; 110 | return ListTile( 111 | title: Text(skills[index]['name']), 112 | leading: Text(skills[index]['type']), 113 | trailing: Text(skills[index]['slv']), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/page/GridViewPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app/page/MyHomePage.dart'; 3 | import 'package:flutter_appavailability/flutter_appavailability.dart'; 4 | import 'package:url_launcher/url_launcher.dart'; 5 | 6 | class GridViewPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return GridViewState(); 10 | } 11 | } 12 | 13 | class GridViewState extends State { 14 | final List listData = []; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | for (int i = 0; i < 20; i++) { 20 | listData.add(new ListItem("我是测试标题$i", Icons.cake)); 21 | } 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | appBar: AppBar( 28 | title: Text('GridView'), 29 | ), 30 | body: GridView.builder( 31 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 32 | crossAxisCount: 2, //每行2个 33 | mainAxisSpacing: 10.0, //主轴(竖直)方向间距 34 | crossAxisSpacing: 10.0, //纵轴(水平)方向间距 35 | childAspectRatio: 1.0 //纵轴缩放比例 36 | ), 37 | itemCount: listData.length, 38 | itemBuilder: (BuildContext context, int index) { 39 | return ListItemWidget(listData[index], index); 40 | }, 41 | ), 42 | ); 43 | } 44 | } 45 | 46 | class ListItem { 47 | final String title; 48 | final IconData iconData; 49 | 50 | ListItem(this.title, this.iconData); 51 | } 52 | 53 | class ListItemWidget extends StatelessWidget { 54 | final ListItem listItem; 55 | final int index; 56 | 57 | ListItemWidget(this.listItem, this.index); 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | return GestureDetector( 62 | child: Container( 63 | color: Colors.green, 64 | child: Column( 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | children: [ 67 | Hero( 68 | tag: listItem.title, 69 | child: Image( 70 | image: AssetImage(index == 5 ? 'images/jay.jpg' : 'images/pic3.jpg'), 71 | width: 150.0, 72 | height: 150.0, 73 | fit: BoxFit.fill, 74 | /*listItem.iconData, 75 | size: 50.0, 76 | color: Colors.white,*/ 77 | )), 78 | Text( 79 | listItem.title, 80 | style: TextStyle(color: Colors.white), 81 | ) 82 | ], 83 | ), 84 | ), 85 | onTap: () async { 86 | /*Scaffold.of(context).showSnackBar(new SnackBar( 87 | content: new Text(listItem.title), 88 | ));*/ 89 | /*Navigator.of(context).push(PageRouteBuilder(pageBuilder: 90 | (BuildContext context, Animation animation, 91 | Animation secondaryAnimation) { 92 | return MyHomePage(tag: listItem.title); 93 | }));*/ 94 | 95 | print(await AppAvailability.checkAvailability("com.whatsapp")); 96 | 97 | print(await AppAvailability.checkAvailability("com.facebook.katana")); 98 | print(await AppAvailability.checkAvailability("com.twitter.android")); 99 | print(await AppAvailability.checkAvailability("com.instagram.android")); 100 | 101 | // print(await canLaunch(FB_PAGE)); 102 | 103 | // const url = "https://wa.me/?text=Your Message here"; 104 | 105 | var url = 'https://www.instagram.com/juno.horoscopes/'; 106 | 107 | if (await canLaunch(url)) { 108 | await launch(url); 109 | } else { 110 | throw 'There was a problem to open the url: $url'; 111 | } 112 | // print(await canLaunch(encoded)); 113 | }, 114 | ); 115 | } 116 | static const String FACEBOOK_URL = 117 | 'https://www.facebook.com/%E6%B5%8B%E6%B5%8B%E5%9B%BD%E9%99%85%E7%89%88-617960732190357'; 118 | static const String FB_PAGE = 'fb://page/617960732190357'; 119 | } 120 | -------------------------------------------------------------------------------- /lib/page/ImagePage.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:dio/dio.dart'; 4 | 5 | class ImagePage extends StatefulWidget { 6 | @override 7 | createState() => ImageState(); 8 | } 9 | 10 | class ImageState extends State { 11 | var image = "images/beauty.jpg"; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text('Image使用示例'), 18 | ), 19 | body: ListView( 20 | children: [ 21 | Image.asset( 22 | "images/beauty.jpg", 23 | width: 200.0, 24 | height: 200.0, 25 | fit: BoxFit.contain, 26 | color: Colors.greenAccent, 27 | colorBlendMode: BlendMode.colorBurn, 28 | alignment: Alignment.bottomRight, 29 | ), 30 | //资源图片 31 | 32 | new Directionality( 33 | textDirection: TextDirection.ltr, 34 | child: Image.asset( 35 | image, 36 | width: 200.0, 37 | height: 200.0, 38 | fit: BoxFit.contain, 39 | ), 40 | ), 41 | 42 | InkWell( 43 | child: Text( 44 | '点击切换图片', 45 | textAlign: TextAlign.center, 46 | style: TextStyle(fontWeight: FontWeight.bold), 47 | ), 48 | onTap: () { 49 | setState(() { 50 | if (image == 'images/beauty.jpg') 51 | image = "images/jay.jpg"; 52 | else 53 | image = 'images/beauty.jpg'; 54 | }); 55 | }, 56 | ), 57 | RaisedButton( 58 | onPressed: _getData, 59 | child: Text( 60 | 'getdata', 61 | style: TextStyle(color: Colors.white), 62 | ), 63 | color: Colors.green, 64 | ), 65 | ], 66 | ), 67 | ); 68 | } 69 | 70 | Future _getData() async { 71 | print('开始请求'); 72 | Dio dio = new Dio(); 73 | //Response response = await dio.get("http://api.douban.com/v2/movie/top250"); 74 | Response response = await dio 75 | .post("http://test.hadoop.network/loan/get_supported_operators"); 76 | var data = response.data; 77 | print(data); 78 | print(data['data']); 79 | 80 | print('请求结束'); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/page/KeepAlivePage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/page/alive_home_page.dart'; 9 | 10 | class KeepAliveDemo extends StatefulWidget { 11 | @override 12 | _KeepAliveDemoState createState() => _KeepAliveDemoState(); 13 | } 14 | 15 | class _KeepAliveDemoState extends State 16 | with SingleTickerProviderStateMixin { 17 | TabController _controller; 18 | 19 | @override 20 | void initState() { 21 | // TODO: implement initState 22 | super.initState(); 23 | _controller = TabController(length: 3, vsync: this); 24 | } 25 | 26 | @override 27 | void dispose() { 28 | print('dispose'); 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | appBar: AppBar( 37 | bottom: TabBar( 38 | controller: _controller, 39 | tabs: [ 40 | Tab(icon: Icon(Icons.directions_car)), 41 | Tab(icon: Icon(Icons.directions_transit)), 42 | Tab(icon: Icon(Icons.directions_bike)), 43 | ], 44 | ), 45 | title: Text('Keep Alive Demo'), 46 | ), 47 | body: TabBarView( 48 | controller: _controller, 49 | children: [ 50 | AliveHomePage( 51 | title: 'Keep Alive demo', 52 | ), 53 | AliveHomePage( 54 | title: 'Keep Alive demo', 55 | ), 56 | AliveHomePage( 57 | title: 'Keep Alive demo', 58 | ), 59 | ], 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/page/MyHomePage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'FavoriteWidget.dart'; 4 | 5 | class MyHomePage extends StatelessWidget { 6 | final String tag; 7 | 8 | MyHomePage({this.tag, Key key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | 13 | Widget titleSection = Container( 14 | padding: const EdgeInsets.all(32.0), 15 | child: Row( 16 | children: [ 17 | Expanded( 18 | child: new Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Container( 22 | padding: const EdgeInsets.only(bottom: 8.0), 23 | child: Text( 24 | 'Oeschinen Lake Campground', 25 | style: TextStyle(fontWeight: FontWeight.bold), 26 | ), 27 | ), 28 | Text( 29 | 'Kandersteg, Switzerland', 30 | style: TextStyle(color: Colors.grey[500]), 31 | ) 32 | ], 33 | ), 34 | ), 35 | FavoriteWidget() 36 | ], 37 | ), 38 | ); 39 | 40 | Column buildButtonColumn(IconData icon, String label) { 41 | Color color = Theme.of(context).primaryColor; 42 | return new Column( 43 | mainAxisSize: MainAxisSize.min, 44 | mainAxisAlignment: MainAxisAlignment.center, 45 | children: [ 46 | new Icon(icon, color: color), 47 | new Container( 48 | margin: const EdgeInsets.only(top: 8.0), 49 | child: new Text( 50 | label, 51 | style: new TextStyle( 52 | fontSize: 12.0, 53 | fontWeight: FontWeight.w400, 54 | color: color, 55 | ), 56 | ), 57 | ), 58 | ], 59 | ); 60 | } 61 | 62 | Widget buttonSection = Container( 63 | child: Row( 64 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 65 | children: [ 66 | buildButtonColumn(Icons.call, 'CALL'), 67 | buildButtonColumn(Icons.near_me, 'ROUTE'), 68 | buildButtonColumn(Icons.share, 'SHARE'), 69 | ], 70 | ), 71 | ); 72 | Widget textSection = new Container( 73 | padding: const EdgeInsets.symmetric(vertical: 22.0, horizontal: 32.0), 74 | child: new Text( 75 | ''' 76 | Lake1 Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. 77 | ''', 78 | softWrap: true, 79 | ), 80 | ); 81 | 82 | FloatingActionButton floatBtn = FloatingActionButton( 83 | foregroundColor: Colors.red, 84 | onPressed: _floatOnPress, 85 | tooltip: '长按显示', 86 | child: Icon(Icons.favorite), 87 | backgroundColor: Colors.transparent, 88 | ); 89 | 90 | RaisedButton btn = new RaisedButton( 91 | onPressed: () { 92 | Navigator.of(context).pushNamed('Pavlova'); 93 | }, 94 | color: Colors.green, 95 | child: new Text('go to Pavlova', 96 | style: new TextStyle(color: Colors.white))); 97 | return Scaffold( 98 | appBar: 99 | AppBar(title: Text('Startup Name Generator'), actions: []), 100 | body: ListView( 101 | children: [ 102 | Hero( 103 | tag: tag ?? 'hero', 104 | child: Image.asset( 105 | 'images/jay.jpg', 106 | width: 600.0, 107 | height: 240.0, 108 | fit: BoxFit.cover, 109 | ), 110 | ), 111 | titleSection, 112 | buttonSection, 113 | textSection, 114 | Container( 115 | padding: EdgeInsets.symmetric(horizontal: 32.0), 116 | child: btn, 117 | ) 118 | ], 119 | ), 120 | floatingActionButton: floatBtn, 121 | ); 122 | } 123 | 124 | void _floatOnPress() { 125 | print('add asda'); 126 | //routes['asda'] = (_) => AliveHomePage(); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/page/PavlovaPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app/locale/translations_delegate.dart'; 4 | 5 | class PavlovaPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return PavlovaState(); 9 | } 10 | } 11 | 12 | class PavlovaState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | Container ratings = Container( 16 | decoration: BoxDecoration( 17 | color: Colors.white70, 18 | border: Border.all(width: 1.0, color: Colors.red), 19 | borderRadius: BorderRadius.all(Radius.circular(20.0)), 20 | ), 21 | padding: EdgeInsets.all(20.0), 22 | child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ 23 | Row( 24 | mainAxisSize: MainAxisSize.min, 25 | children: [ 26 | Icon(Icons.star, color: Colors.green[500]), 27 | Icon(Icons.star, color: Colors.green[500]), 28 | Icon(Icons.star, color: Colors.green[500]), 29 | Icon(Icons.star, color: Colors.grey), 30 | Icon(Icons.star, color: Colors.grey), 31 | ], 32 | ), 33 | Text('170 Reviews', 34 | style: TextStyle( 35 | color: Colors.black, 36 | fontWeight: FontWeight.w800, 37 | fontFamily: 'Roboto', 38 | letterSpacing: 0.5, 39 | fontSize: 20.0, 40 | )) 41 | ])); 42 | 43 | var descTextStyle = new TextStyle( 44 | color: Colors.black, 45 | fontWeight: FontWeight.w800, 46 | fontFamily: 'Roboto', 47 | letterSpacing: 0.5, 48 | fontSize: 18.0, 49 | height: 2.0, 50 | ); 51 | 52 | var threeColumn = DefaultTextStyle.merge( 53 | style: descTextStyle, 54 | child: Container( 55 | padding: new EdgeInsets.all(20.0), 56 | child: Row( 57 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 58 | children: [ 59 | Column( 60 | crossAxisAlignment: CrossAxisAlignment.center, 61 | children: [ 62 | Icon( 63 | Icons.kitchen, 64 | color: Colors.green, 65 | ), 66 | Text('PREP'), 67 | Text('25 min'), 68 | ], 69 | ), 70 | Column( 71 | children: [ 72 | Icon( 73 | Icons.timer, 74 | color: Colors.green, 75 | ), 76 | Text('COOK'), 77 | Text('1 hr'), 78 | ], 79 | ), 80 | Column( 81 | children: [ 82 | Icon( 83 | Icons.restaurant, 84 | color: Colors.green, 85 | ), 86 | Text('FEEDS'), 87 | Text('4 - 6'), 88 | ], 89 | ) 90 | ], 91 | ), 92 | )); 93 | 94 | var titleText = 95 | Text('ADSAD SA;DKJJ AS;KDA', style: TextStyle(fontSize: 22.0)); 96 | var subTitle = Container( 97 | padding: EdgeInsets.symmetric(vertical: 20.0), 98 | child: Text( 99 | 'aaaaaaaaaaadsa ;kasdlka;sda sdaljdh ljahd ashd kahs dkaj hsld hasljd hals hdah '), 100 | ); 101 | var ratIcon = Container( 102 | padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0), 103 | child: Column( 104 | children: [titleText, subTitle, ratings, threeColumn], 105 | )); 106 | return Scaffold( 107 | appBar: AppBar(title: Text('Pavlova')), 108 | body: Container( 109 | child: Column( 110 | children: [ 111 | ratIcon, 112 | Hero( 113 | tag: '${Translations.of(context).get('homePage')}', 114 | child: Image.network( 115 | 'http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg', 116 | height: 230.0, 117 | width: double.infinity), 118 | ), 119 | 120 | /* Image.asset( 121 | 'images/beauty.jpg', 122 | height: 230.0, 123 | width: double.infinity, 124 | )*/ 125 | ], 126 | ), 127 | )); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lib/page/RandomWords.dart: -------------------------------------------------------------------------------- 1 | import 'package:english_words/english_words.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | 5 | class RandomWords extends StatefulWidget { 6 | @override 7 | createState() => RandomWordsState(); 8 | } 9 | 10 | class RandomWordsState extends State { 11 | final _suggestions = []; 12 | final _biggerFont = const TextStyle(fontSize: 18.0); 13 | final _saved = new Set(); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar(title: Text('Startup Name Generator'), actions: [ 19 | IconButton( 20 | icon: Icon(Icons.list), 21 | onPressed: _pushSaved, 22 | ) 23 | ]), 24 | body: _buildSuggestions(), 25 | ); 26 | } 27 | 28 | Widget _buildSuggestions() { 29 | return ListView.builder( 30 | itemBuilder: (context, i) { 31 | if (i.isOdd) return Divider(); 32 | final index = i ~/ 2; 33 | if (index >= _suggestions.length) { 34 | _suggestions.addAll(generateWordPairs().take(10)); 35 | } 36 | return _buildRow(_suggestions[index], i); 37 | }, 38 | padding: const EdgeInsets.all(16.0), 39 | ); 40 | } 41 | 42 | Widget _buildRow(WordPair pair, int i) { 43 | final alreadySaved = _saved.contains(pair); 44 | 45 | return ListTile( 46 | title: Text(pair.asPascalCase, style: _biggerFont), 47 | trailing: Icon( 48 | alreadySaved ? Icons.favorite : Icons.favorite_border, 49 | color: alreadySaved ? Colors.red : null, 50 | ), 51 | onTap: () { 52 | print(i); 53 | setState(() { 54 | if (alreadySaved) { 55 | _saved.remove(pair); 56 | } else { 57 | _saved.add(pair); 58 | } 59 | }); 60 | }, 61 | ); 62 | } 63 | 64 | void _pushSaved() { 65 | Navigator.of(context).push(MaterialPageRoute(builder: (context) { 66 | final tiles = _saved.map((pair) { 67 | return ListTile( 68 | title: Text(pair.asPascalCase, style: _biggerFont), 69 | ); 70 | }); 71 | final divided = 72 | ListTile.divideTiles(tiles: tiles, context: context).toList(); 73 | return Scaffold( 74 | appBar: AppBar( 75 | title: Text('Saved Suggestions'), 76 | ), 77 | body: ListView(children: divided), 78 | ); 79 | })); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/page/ScreenUtilTest.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/29. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 9 | 10 | class ScreenUtilTest extends StatefulWidget { 11 | final String title; 12 | 13 | const ScreenUtilTest({Key key, this.title}) : super(key: key); 14 | 15 | @override 16 | _MyHomePageState createState() => new _MyHomePageState(); 17 | } 18 | 19 | class _MyHomePageState extends State { 20 | @override 21 | Widget build(BuildContext context) { 22 | printScreenInformation(); 23 | return Scaffold( 24 | appBar: AppBar( 25 | title: Text(widget.title), 26 | ), 27 | body: SingleChildScrollView( 28 | child: Column( 29 | crossAxisAlignment: CrossAxisAlignment.center, 30 | children: [ 31 | Row( 32 | children: [ 33 | Container( 34 | padding: EdgeInsets.all(ScreenUtil().setWidth(10)), 35 | width: 180.w, 36 | height: 200.h, 37 | color: Colors.red, 38 | child: Text( 39 | '我的实际宽度:${0.5.sw}dp \n' 40 | '我的实际高度:${ScreenUtil().setHeight(200)}dp', 41 | style: TextStyle(color: Colors.white, fontSize: ScreenUtil().setSp(12)), 42 | ), 43 | ), 44 | Container( 45 | padding: EdgeInsets.all(ScreenUtil().setWidth(10)), 46 | width: ScreenUtil().setWidth(180), 47 | height: ScreenUtil().setHeight(200), 48 | color: Colors.blue, 49 | child: Text( 50 | '我的设计稿宽度: 180dp \n' 51 | '我的设计稿高度: 200dp', 52 | style: TextStyle(color: Colors.white, fontSize: ScreenUtil().setSp(12))), 53 | ), 54 | ], 55 | ), 56 | Container( 57 | padding: EdgeInsets.all(ScreenUtil().setWidth(10)), 58 | width: 100.r, 59 | height: 100.r, 60 | color: Colors.green, 61 | child: Text( 62 | '我是正方形,边长是100', 63 | style: TextStyle( 64 | color: Colors.white, 65 | fontSize: ScreenUtil().setSp(12), 66 | ), 67 | ), 68 | ), 69 | Text('设备宽度:${ScreenUtil().screenWidth}dp'), 70 | Text('设备高度:${ScreenUtil().screenHeight}dp'), 71 | Text('设备的像素密度:${ScreenUtil().pixelRatio}'), 72 | Text('底部安全区距离:${ScreenUtil().bottomBarHeight}dp'), 73 | Text('状态栏高度:${ScreenUtil().statusBarHeight}dp'), 74 | Text( 75 | '实际宽度与设计稿的比例:${ScreenUtil().scaleWidth}', 76 | textAlign: TextAlign.center, 77 | ), 78 | Text( 79 | '实际高度与设计稿的比例:${ScreenUtil().scaleHeight}', 80 | textAlign: TextAlign.center, 81 | ), 82 | SizedBox( 83 | height: 50.h, 84 | ), 85 | Text('系统的字体缩放比例:${ScreenUtil().textScaleFactor}'), 86 | Column( 87 | crossAxisAlignment: CrossAxisAlignment.start, 88 | children: [ 89 | Text( 90 | '我的文字大小在设计稿上是16dp,不会随着系统的文字缩放比例变化', 91 | style: TextStyle( 92 | color: Colors.black, 93 | fontSize: 16.sp, 94 | ), 95 | ), 96 | Text( 97 | '我的文字大小在设计稿上是16dp,会随着系统的文字缩放比例变化', 98 | style: TextStyle( 99 | color: Colors.black, 100 | fontSize: 16.ssp, 101 | ), 102 | ), 103 | ], 104 | ) 105 | ], 106 | ), 107 | ), 108 | ); 109 | } 110 | 111 | void printScreenInformation() { 112 | print('设备宽度:${1.sw}dp'); 113 | print('设备高度:${1.sh}dp'); 114 | print('设备的像素密度:${ScreenUtil().pixelRatio}'); 115 | print('底部安全区距离:${ScreenUtil().bottomBarHeight}dp'); 116 | print('状态栏高度:${ScreenUtil().statusBarHeight}dp'); 117 | print('实际宽度的dp与设计稿px的比例:${ScreenUtil().scaleWidth}'); 118 | print('实际高度的dp与设计稿px的比例:${ScreenUtil().scaleHeight}'); 119 | print('宽度和字体相对于设计稿放大的比例:${ScreenUtil().scaleWidth * ScreenUtil().pixelRatio}'); 120 | print('高度相对于设计稿放大的比例:${ScreenUtil().scaleHeight * ScreenUtil().pixelRatio}'); 121 | print('系统的字体缩放比例:${ScreenUtil().textScaleFactor}'); 122 | print('屏幕宽度的0.5:${0.5.sw}dp'); 123 | print('屏幕高度的0.5:${0.5.sh}dp'); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/page/StateWidgetPage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | 父组件管理子组件状态(控制背景色和文字) 3 | 子组件控制自己的状态(按下和抬起的边框高亮) 4 | */ 5 | 6 | import 'dart:io'; 7 | 8 | import 'package:flutter/material.dart'; 9 | 10 | class StateWidgetPage extends StatefulWidget { 11 | @override 12 | State createState() { 13 | return StateWidgetState(); 14 | } 15 | } 16 | 17 | class StateWidgetState extends State { 18 | bool _active = false; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: Text('state'), 25 | ), 26 | body: Container( 27 | child: TabBox(active: _active, onClick: _onclick), 28 | ), 29 | ); 30 | } 31 | 32 | _onclick() { 33 | setState(() { 34 | _active = !_active; 35 | }); 36 | } 37 | } 38 | 39 | class TabBox extends StatefulWidget { 40 | TabBox({Key key, this.active: false, @required this.onClick}) 41 | : super(key: key); 42 | final bool active; 43 | final onClick; 44 | 45 | @override 46 | State createState() { 47 | return TabBoxState(); 48 | } 49 | } 50 | 51 | class TabBoxState extends State { 52 | bool _highlight = false; 53 | 54 | Widget build(BuildContext context) { 55 | return GestureDetector( 56 | onTapDown: _handleTapDown, 57 | // Handle the tap events in the order that 58 | onTapUp: _handleTapUp, 59 | // they occur: down, up, tap, cancel 60 | onTap: _handleTap, 61 | onTapCancel: _handleTapCancel, 62 | 63 | child: Container( 64 | child: Center( 65 | child: Text( 66 | widget.active ? 'Active' : 'Inactive', 67 | style: TextStyle( 68 | fontSize: 32.0, 69 | color: Colors.white, 70 | decorationColor: Colors.yellow), 71 | ), 72 | ), 73 | width: 200.0, 74 | height: 200.0, 75 | decoration: BoxDecoration( 76 | color: widget.active ? Colors.lightGreen[700] : Colors.grey[600], 77 | border: _highlight 78 | ? Border.all( 79 | color: Colors.yellow[700], 80 | width: 10.0, 81 | ) 82 | : null, 83 | ), 84 | ), 85 | ); 86 | } 87 | 88 | void _handleTapDown(TapDownDetails details) { 89 | setState(() { 90 | _highlight = true; 91 | }); 92 | } 93 | 94 | void _handleTapUp(TapUpDetails details) { 95 | _highlight = false; 96 | } 97 | 98 | void _handleTap() { 99 | widget.onClick(); 100 | } 101 | 102 | void _handleTapCancel() { 103 | _highlight = false; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/page/SwiperPage.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_swiper/flutter_swiper.dart'; 9 | import 'package:url_launcher/url_launcher.dart'; 10 | 11 | class SwiperPage extends StatefulWidget { 12 | @override 13 | SwiperPageState createState() { 14 | return SwiperPageState(); 15 | } 16 | } 17 | 18 | class SwiperPageState extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | appBar: AppBar( 23 | title: Text('轮播组件'), 24 | ), 25 | body: Container( 26 | width: MediaQuery.of(context).size.width, 27 | height: 200.0, 28 | child: Swiper( 29 | itemBuilder: _swiperBuilder, 30 | itemCount: 3, 31 | pagination: new SwiperPagination( 32 | builder: DotSwiperPaginationBuilder( 33 | color: Colors.black54, 34 | activeColor: Colors.white, 35 | )), 36 | control: new SwiperControl(), 37 | scrollDirection: Axis.horizontal, 38 | autoplay: true, 39 | onTap: _goOtherApp, 40 | )), 41 | ); 42 | } 43 | 44 | Widget _swiperBuilder(BuildContext context, int index) { 45 | return (Image.network( 46 | "http://via.placeholder.com/350x150", 47 | fit: BoxFit.fill, 48 | )); 49 | } 50 | 51 | void _goOtherApp(int index) async { 52 | const url = 'flutter://li.zhuoyuan'; //这个url就是由scheme和host组成的 :scheme://host 53 | if (await canLaunch(url)) { 54 | await launch(url); 55 | } else { 56 | throw 'Could not launch $url'; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/page/alive_home_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 实现原理,使用AutomaticKeepAliveClientMixin,并重写wantKeepAlive方法,让状态不被回收掉。 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:url_launcher/url_launcher.dart'; 9 | 10 | class AliveHomePage extends StatefulWidget { 11 | AliveHomePage({Key key, this.title}) : super(key: key); 12 | final String title; 13 | 14 | @override 15 | _MyHomePageState createState() => new _MyHomePageState(); 16 | } 17 | 18 | class _MyHomePageState extends State with AutomaticKeepAliveClientMixin { 19 | int _counter = 0; 20 | static const String OFFICIAL_WEBSITE = 'https://www.junohoro.com/'; 21 | 22 | @override 23 | bool get wantKeepAlive => true; 24 | 25 | void _incrementCounter() async { 26 | const text = 'Juno:您身邊的星座專家,占星、塔羅、合盤全都有!$OFFICIAL_WEBSITE'; 27 | 28 | String url = "whatsapp://send?text=$text"; 29 | if (await canLaunch(url)) { 30 | await launch(url); 31 | } else { 32 | print('Could not launch $url'); 33 | } 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | super.build(context); 39 | return new Scaffold( 40 | body: new Center( 41 | child: new Column( 42 | mainAxisAlignment: MainAxisAlignment.center, 43 | children: [ 44 | new Text( 45 | 'You have pushed the button this many times:', 46 | ), 47 | new Text( 48 | '$_counter', 49 | style: Theme.of(context).textTheme.button, 50 | ), 51 | ], 52 | ), 53 | ), 54 | floatingActionButton: new FloatingActionButton( 55 | onPressed: _incrementCounter, 56 | tooltip: 'Increment', 57 | child: Icon(Icons.add), 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/page/animation_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/27. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/widget/transform_animation_widget.dart'; 9 | 10 | class AnimationPage extends StatefulWidget { 11 | @override 12 | State createState() => AnimationState(); 13 | } 14 | 15 | class AnimationState extends State 16 | with SingleTickerProviderStateMixin { 17 | AnimationController imageAnimationController; 18 | Animation animation; 19 | 20 | IconData _icon = Icons.done; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | 26 | imageAnimationController = AnimationController( 27 | vsync: this, 28 | duration: Duration(seconds: 2), 29 | ); 30 | 31 | animation = Tween(begin: 0.0, end: 200.0).animate(imageAnimationController) 32 | ..addStatusListener(_imageAnimationStatusListener); 33 | /*animation = 34 | CurvedAnimation(parent: imageAnimationController, curve: Curves.easeIn) 35 | ..addStatusListener(_imageAnimationStatusListener);*/ 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text('动画'), 43 | actions: [ 44 | AnimatedSwitcher( 45 | transitionBuilder: (Widget child, Animation animation) { 46 | return ScaleTransition(scale: animation, child: child); 47 | }, 48 | duration: Duration(milliseconds: 200), 49 | child: IconButton( 50 | key: ValueKey(_icon), 51 | icon: Icon(_icon), 52 | onPressed: () { 53 | setState(() { 54 | _icon = 55 | _icon == Icons.done ? Icons.delete_forever : Icons.done; 56 | }); 57 | }, 58 | ), 59 | ) 60 | ], 61 | ), 62 | floatingActionButton: FloatingActionButton( 63 | onPressed: _startAnimation, 64 | child: Icon(Icons.play_arrow), 65 | ), 66 | body: Column( 67 | mainAxisSize: MainAxisSize.max, 68 | crossAxisAlignment: CrossAxisAlignment.center, 69 | children: [ 70 | TransformAnimationWidget(animation: animation), 71 | /* GrowTransition( 72 | animation: animation, 73 | child: Image.asset( 74 | 'images/pic3.jpg', 75 | fit: BoxFit.fill, 76 | ), 77 | ),*/ 78 | SizedBox( 79 | height: 50.0, 80 | width: MediaQuery.of(context).size.width, 81 | ), 82 | AnimationImage( 83 | animation: animation, 84 | ) 85 | ], 86 | )); 87 | } 88 | 89 | @override 90 | void dispose() { 91 | imageAnimationController.dispose(); 92 | super.dispose(); 93 | } 94 | 95 | void _startAnimation() { 96 | imageAnimationController.forward(); 97 | } 98 | 99 | void _imageAnimationStatusListener(AnimationStatus status) { 100 | switch (status) { 101 | case AnimationStatus.dismissed: 102 | // 动画反向运行结束 103 | print('动画结束'); 104 | //动画恢复到初始状态后执行正向动画 105 | imageAnimationController.forward(); 106 | break; 107 | case AnimationStatus.forward: 108 | print('动画正向运行'); 109 | break; 110 | case AnimationStatus.reverse: 111 | print('动画反向运行'); 112 | break; 113 | case AnimationStatus.completed: 114 | //动画完成 115 | print('动画完成'); 116 | //动画结束之后执行反向动画 117 | imageAnimationController.reverse(); 118 | 119 | break; 120 | } 121 | } 122 | } 123 | 124 | class AnimationImage extends AnimatedWidget { 125 | /*static final _sizeAnimation = Tween(begin: 0.0, end: 200.0); 126 | static final _opacityAni = Tween(begin: 0.0, end: 1.0);*/ 127 | 128 | AnimationImage({ 129 | Key key, 130 | Animation animation, 131 | }) : super(key: key, listenable: animation); 132 | 133 | @override 134 | Widget build(BuildContext context) { 135 | final Animation animation = listenable; 136 | return Opacity( 137 | opacity: animation.value / 200, 138 | child: Image.asset( 139 | 'images/pic3.jpg', 140 | width: animation.value, 141 | height: animation.value, 142 | fit: BoxFit.fill, 143 | ), 144 | ); 145 | } 146 | } 147 | 148 | class GrowTransition extends StatelessWidget { 149 | final Widget child; 150 | final Animation animation; 151 | 152 | GrowTransition({this.child, this.animation}); 153 | 154 | @override 155 | Widget build(BuildContext context) { 156 | return Center( 157 | child: AnimatedBuilder( 158 | animation: animation, 159 | builder: _animatedBuilder, 160 | child: child, 161 | ), 162 | ); 163 | } 164 | 165 | Widget _animatedBuilder(BuildContext context, Widget child) { 166 | return Opacity( 167 | child: Container( 168 | child: child, 169 | height: animation.value, 170 | width: animation.value, 171 | ), 172 | opacity: animation.value / 200, 173 | ); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /lib/page/cupertino_action_sheet_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttertoast/fluttertoast.dart'; 4 | 5 | class CupertinoActionSheetPage extends StatefulWidget { 6 | @override 7 | _CupertinoActionSheetPAGEState createState() => 8 | _CupertinoActionSheetPAGEState(); 9 | } 10 | 11 | class _CupertinoActionSheetPAGEState extends State { 12 | ScrollController scrollController; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | scrollController = ScrollController(); 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text('CupertinoActionSheet'), 20 | ), 21 | body: Container( 22 | child: RaisedButton( 23 | onPressed: _showCupertinoActionSheet, 24 | child: Text('show'), 25 | ), 26 | ), 27 | ); 28 | } 29 | 30 | void _showCupertinoActionSheet() async { 31 | var result = await showCupertinoModalPopup( 32 | context: context, 33 | builder: (BuildContext context) { 34 | return CupertinoActionSheet( 35 | messageScrollController: scrollController, 36 | title: Text('兄弟 '), 37 | message: Text('不能删啊'), 38 | actions: [ 39 | CupertinoActionSheetAction( 40 | isDestructiveAction: true, 41 | onPressed: () { 42 | Fluttertoast.showToast(msg: '删除了'); 43 | 44 | Navigator.of(context).pop('删除'); 45 | }, 46 | child: Text('删除'), 47 | ), 48 | ], 49 | cancelButton: CupertinoActionSheetAction( 50 | onPressed: () { 51 | Navigator.of(context).pop('cancel'); 52 | }, 53 | child: Text('取消'), 54 | ), 55 | ); 56 | }); 57 | print(result.toString()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/page/custom_scrollview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomScrollViewPage extends StatefulWidget { 4 | @override 5 | _CustomScrollViewPageState createState() => _CustomScrollViewPageState(); 6 | } 7 | 8 | class _CustomScrollViewPageState extends State 9 | with SingleTickerProviderStateMixin { 10 | var tabController; 11 | 12 | @override 13 | void initState() { 14 | // TODO: implement initState 15 | super.initState(); 16 | tabController = TabController(length: 2, vsync: this); 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return SafeArea( 22 | child: Scaffold( 23 | body: CustomScrollView( 24 | slivers: [ 25 | SliverToBoxAdapter( 26 | child: Container(color: Colors.green, height: 100, child: Text('我的可滚动列表上面的一些文')), 27 | ), 28 | SliverAppBar( 29 | //标题居中 30 | centerTitle: true, 31 | //展开高度200 32 | expandedHeight: 200.0, 33 | //不随着滑动隐藏标题 34 | floating: false, 35 | //固定在顶部 36 | pinned: true, 37 | flexibleSpace: FlexibleSpaceBar( 38 | centerTitle: true, 39 | title: Container( 40 | child: Column( 41 | children: [ 42 | 43 | Text('我是一个FlexibleSpaceBar') 44 | ], 45 | ), 46 | ), 47 | background: Image.network( 48 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg", 49 | fit: BoxFit.cover, 50 | ), 51 | ), 52 | ), 53 | SliverPersistentHeader( 54 | pinned: true, 55 | delegate: StickyTabBarDelegate( 56 | child: TabBar( 57 | controller: tabController, 58 | labelColor: Colors.black, 59 | tabs: [ 60 | Tab(text: '资讯'), 61 | Tab(text: '技术'), 62 | ], 63 | ), 64 | ), 65 | ), 66 | SliverToBoxAdapter( 67 | child: Text('我的可滚动列表上面的一些文'), 68 | ), 69 | SliverList(delegate: SliverChildBuilderDelegate(itemBuilder, childCount: 10)), 70 | SliverFixedExtentList( 71 | itemExtent: 50.0, 72 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) { 73 | return Container( 74 | alignment: Alignment.center, 75 | color: Colors.lightBlue[100 * (index % 9)], 76 | child: Text('List Item $index'), 77 | ); 78 | }, childCount: 10), 79 | ), 80 | ], 81 | ), 82 | ), 83 | ); 84 | } 85 | 86 | Widget itemBuilder(BuildContext context, int index) { 87 | return Container( 88 | color: Colors.green.withOpacity(index / 10), 89 | height: 200, 90 | ); 91 | } 92 | } 93 | 94 | class StickyTabBarDelegate extends SliverPersistentHeaderDelegate { 95 | final TabBar child; 96 | 97 | StickyTabBarDelegate({@required this.child}); 98 | 99 | @override 100 | Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { 101 | return Container( 102 | color: Theme.of(context).backgroundColor, 103 | child: this.child, 104 | ); 105 | } 106 | 107 | @override 108 | double get maxExtent => this.child.preferredSize.height; 109 | 110 | @override 111 | double get minExtent => this.child.preferredSize.height; 112 | 113 | @override 114 | bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { 115 | return true; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lib/page/draggable_dragtargets.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhuoyuan93@gmail.com 3 | * @Date: 2018-11-20 10:43:49 4 | * @LastEditors: zhuoyuan93@gmail.com 5 | * @LastEditTime: 2018-11-20 12:09:21 6 | * @Description: 7 | */ 8 | 9 | import 'package:flutter/material.dart'; 10 | 11 | class DraggableDragtargets extends StatefulWidget { 12 | @override 13 | DraggableDragtargetsState createState() { 14 | return new DraggableDragtargetsState(); 15 | } 16 | } 17 | 18 | class DraggableDragtargetsState extends State 19 | with TickerProviderStateMixin { 20 | 21 | bool accept = true; 22 | bool accept2 = false; 23 | 24 | Widget _dragGableWidget() { 25 | return Draggable( 26 | child: _moveWidget('卓'), 27 | feedback: _moveWidget('卓'), 28 | childWhenDragging: _moveWidget(''), 29 | onDragStarted: () { 30 | print('drag start'); 31 | }, 32 | data: '卓', 33 | ); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | // TODO: implement build 39 | return Scaffold( 40 | appBar: AppBar( 41 | title: Text('可拖动的组件'), 42 | ), 43 | body: Column( 44 | crossAxisAlignment: CrossAxisAlignment.center, 45 | children: [ 46 | DragTarget( 47 | builder: (BuildContext context, List candidateData, 48 | List rejectedData) { 49 | return accept ? _dragGableWidget() : _moveWidget(''); 50 | }, 51 | onWillAccept: (data) { 52 | print('right will accept : $data'); 53 | if (data != '卓') return false; 54 | return true; 55 | }, 56 | onAccept: (data) { 57 | setState(() { 58 | accept = true; 59 | accept2 = false; 60 | }); 61 | print('accept : $data'); 62 | }, 63 | ), 64 | SizedBox( 65 | height: 150.0, 66 | ), 67 | Row( 68 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 69 | children: [ 70 | DragTarget( 71 | builder: (BuildContext context, List candidateData, 72 | List rejectedData) { 73 | return _moveWidget('Left Target'); 74 | }, 75 | onWillAccept: (data) { 76 | print('left will accept : $data'); 77 | if (data == '卓') return false; 78 | return true; 79 | }, 80 | onAccept: (data) { 81 | print('accept : $data'); 82 | }, 83 | ), 84 | DragTarget( 85 | builder: (BuildContext context, List candidateData, 86 | List rejectedData) { 87 | return accept2 ? _dragGableWidget() : _moveWidget(''); 88 | }, 89 | onWillAccept: (data) { 90 | print('right will accept : $data'); 91 | if (data != '卓') return false; 92 | return true; 93 | }, 94 | onAccept: (data) { 95 | setState(() { 96 | accept2 = true; 97 | accept = false; 98 | }); 99 | print('accept : $data'); 100 | }, 101 | ) 102 | ], 103 | ) 104 | ], 105 | ), 106 | ); 107 | } 108 | 109 | Widget _moveWidget(string) { 110 | return Container( 111 | height: 100.0, 112 | width: 100.0, 113 | color: Colors.blue, 114 | alignment: Alignment.center, 115 | child: Text( 116 | string, 117 | style: TextStyle(fontSize: 24.0, color: Colors.white), 118 | textAlign: TextAlign.center, 119 | ), 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/page/draggable_scrollable_sheet_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DraggableScrollableSheetPage extends StatefulWidget { 4 | @override 5 | _DraggableScrollableSheetPageState createState() => 6 | _DraggableScrollableSheetPageState(); 7 | } 8 | 9 | class _DraggableScrollableSheetPageState 10 | extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('DraggableScrollableSheet'), 16 | ), 17 | body: Stack( 18 | children: [ 19 | Align( 20 | alignment: Alignment.topCenter, 21 | child: Image.asset( 22 | 'images/beauty.jpg', 23 | width: 200, 24 | height: 100, 25 | fit: BoxFit.fill, 26 | ), 27 | ), 28 | DraggableScrollableSheet( 29 | initialChildSize: 0.5, 30 | minChildSize: 0.2, 31 | maxChildSize: 0.8, 32 | builder: (BuildContext context, ScrollController scrollController) { 33 | return Container( 34 | decoration: BoxDecoration( 35 | color: Colors.grey, 36 | borderRadius: BorderRadius.horizontal( 37 | left: Radius.circular(10), right: Radius.circular(10)), 38 | ), 39 | child: ListView( 40 | controller: scrollController, 41 | children: [ 42 | SizedBox( 43 | height: 20, 44 | ), 45 | Text('嘤嘤嘤'), 46 | Image.asset( 47 | 'images/jay.jpg', 48 | width: 200, 49 | height: 200, 50 | ), 51 | SizedBox(height: 300), 52 | Text('llll'), 53 | ], 54 | ), 55 | ); 56 | }, 57 | ), 58 | ], 59 | ), 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/page/extension_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | 6 | class ExtensionPage extends StatefulWidget { 7 | @override 8 | _ExtensionPagState createState() => _ExtensionPagState(); 9 | } 10 | 11 | class _ExtensionPagState extends State { 12 | bool isShowBlur = true; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar( 18 | title: Text('扩展函数'), 19 | actions: [ 20 | Padding( 21 | padding: EdgeInsets.only(right: 20), 22 | child: InkWell( 23 | onTap: () => setState(() { 24 | isShowBlur = !isShowBlur; 25 | }), 26 | child: Container( 27 | alignment: Alignment.center, 28 | child: Text( 29 | '模糊', 30 | style: TextStyle( 31 | color: Colors.white, 32 | fontSize: 20, 33 | ), 34 | )), 35 | ), 36 | ) 37 | ], 38 | ), 39 | body: Stack( 40 | children: [ 41 | Image.asset( 42 | 'images/pavlova.png', 43 | width: ScreenUtil().screenWidth, 44 | height: ScreenUtil().screenHeight, 45 | ), 46 | if (isShowBlur) 47 | BackdropFilter( 48 | filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), 49 | child: Center( 50 | child: InkWell( 51 | onTap: _onTap, 52 | child: Container( 53 | color: Colors.blue, 54 | child: Text( 55 | '显示', 56 | style: TextStyle( 57 | color: Colors.white, 58 | fontSize: 20, 59 | ), 60 | ), 61 | ), 62 | ).click(() { 63 | print('extension'); 64 | setState(() { 65 | isShowBlur = !isShowBlur; 66 | }); 67 | }), 68 | ), 69 | ), 70 | ], 71 | )); 72 | } 73 | 74 | void _onTap() { 75 | print('on tap'); 76 | } 77 | } 78 | 79 | extension Ink on InkWell { 80 | InkWell click(Function f) { 81 | return InkWell( 82 | child: child, 83 | onTap: () { 84 | f(); 85 | }, 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/page/flutter_native_web.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/3/6. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'dart:async'; 8 | 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 11 | import 'package:webview_flutter/webview_flutter.dart'; 12 | 13 | class FlutterNativeWebPage extends StatefulWidget { 14 | @override 15 | _FlutterNativeWebPageState createState() => _FlutterNativeWebPageState(); 16 | } 17 | 18 | class _FlutterNativeWebPageState extends State { 19 | final Completer _controller = 20 | Completer(); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | appBar: AppBar( 26 | title: Text('flutterwebview'), 27 | ), 28 | body: Container( 29 | height:300, 30 | width: ScreenUtil().screenWidth, 31 | child: WebView( 32 | initialUrl: 'https://www.youtube.com/watch?v=GWqwOOg6IUE', 33 | javascriptMode: JavascriptMode.unrestricted, 34 | onWebViewCreated: (WebViewController webViewController) { 35 | _controller.complete(webViewController); 36 | }, 37 | // Remove this when collection literals makes it to stable. 38 | // ignore: prefer_collection_literals 39 | javascriptChannels: [ 40 | _toasterJavascriptChannel(context), 41 | ].toSet(), 42 | )), 43 | ); 44 | } 45 | 46 | JavascriptChannel _toasterJavascriptChannel(BuildContext context) { 47 | return JavascriptChannel( 48 | name: 'Toaster', 49 | onMessageReceived: (JavascriptMessage message) { 50 | Scaffold.of(context).showSnackBar( 51 | SnackBar(content: Text(message.message)), 52 | ); 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/page/flutter_picker_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_app/bean/picker_data.dart'; 5 | import 'package:flutter_picker/flutter_picker.dart'; 6 | 7 | class PickerPage extends StatefulWidget { 8 | @override 9 | _PickerPageState createState() => _PickerPageState(); 10 | } 11 | 12 | class _PickerPageState extends State { 13 | final double listSpec = 4.0; 14 | final GlobalKey _scaffoldKey = GlobalKey(); 15 | String stateText; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | key: _scaffoldKey, 21 | appBar: AppBar( 22 | title: Text('Picker'), 23 | ), 24 | body: Container( 25 | padding: EdgeInsets.all(10.0), 26 | alignment: Alignment.topCenter, 27 | child: ListView( 28 | children: [ 29 | (stateText != null) ? Text(stateText) : Container(), 30 | SizedBox(height: listSpec), 31 | RaisedButton( 32 | child: Text('Picker Show Modal'), 33 | onPressed: showPickerModal, 34 | ), 35 | SizedBox(height: listSpec), 36 | RaisedButton( 37 | child: Text('Picker Show Datetime (Round background)'), 38 | onPressed: showPickerDateTimeRoundBg, 39 | ), 40 | SizedBox(height: listSpec), 41 | ], 42 | ), 43 | ), 44 | ); 45 | } 46 | 47 | showPickerModal() { 48 | Picker( 49 | adapter: PickerDataAdapter(pickerdata: JsonDecoder().convert(PickerData)), 50 | changeToFirst: true, 51 | hideHeader: false, 52 | selectedTextStyle: TextStyle(color: Colors.blue), 53 | onConfirm: (Picker picker, List value) { 54 | print(value.toString()); 55 | print(picker.adapter.text); 56 | }).showModal(context); //_scaffoldKey.currentState); 57 | } 58 | 59 | Widget timePicker({ThemeData themeData, bool isModal = false}) { 60 | return Picker( 61 | height: 300, 62 | backgroundColor: Colors.transparent, 63 | headerDecoration: 64 | BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black12, width: 0.5))), 65 | adapter: DateTimePickerAdapter( 66 | type: PickerDateTimeType.kYMDHM, 67 | isNumberMonth: false, 68 | ), 69 | title: Text("选择时间"), 70 | onConfirm: (Picker picker, List value) { 71 | print('confirm:${picker.adapter.text}'); 72 | this.setState(() { 73 | stateText = picker.adapter.toString(); 74 | }); 75 | }, 76 | onSelect: (Picker picker, int index, List selecteds) { 77 | print('onSelect:${picker.adapter.text}'); 78 | }).makePicker(themeData, isModal); 79 | } 80 | 81 | /// 圆角背景 82 | showPickerDateTimeRoundBg() { 83 | showModalBottomSheet( 84 | context: context, 85 | backgroundColor: Colors.transparent, 86 | builder: (context) { 87 | return Material( 88 | color: Colors.white, 89 | borderRadius: BorderRadius.vertical(top: Radius.circular(10)), 90 | child: timePicker(isModal: true), 91 | ); 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/page/fractionally_sized_box_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FractionallySizedBoxPage extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | appBar: AppBar( 8 | title: Text('FractionallySizedBox:按比例设置widget尺寸'), 9 | ), 10 | body: Column( 11 | children: [ 12 | Container( 13 | width: 300, 14 | height: 300, 15 | color: Colors.grey, 16 | child: FractionallySizedBox( 17 | alignment: Alignment.bottomRight, 18 | heightFactor: 0.5, 19 | widthFactor: 0.5, 20 | child: RaisedButton( 21 | onPressed: () { 22 | print('hhh'); 23 | }, 24 | child: Text('button'), 25 | )), 26 | ), 27 | Flexible( 28 | child: FractionallySizedBox( 29 | heightFactor: 0.1, 30 | ), 31 | ), 32 | Container( 33 | color: Colors.blue, 34 | child: Row( 35 | children: [ 36 | Flexible( 37 | child: FractionallySizedBox( 38 | widthFactor: 0.5, 39 | ), 40 | ), 41 | Image.asset( 42 | 'images/jay.jpg', 43 | width: 50, 44 | ), 45 | SizedBox(width: 10), 46 | Text('文字'), 47 | ], 48 | ), 49 | ) 50 | ], 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/page/map_search_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app/common/constant.dart'; 4 | import 'package:flutter_app/utils/HttpUtil.dart'; 5 | import 'package:mapbox_search/mapbox_search.dart'; 6 | 7 | class MapSearchPage extends StatefulWidget { 8 | @override 9 | _MapSearchPageState createState() => _MapSearchPageState(); 10 | } 11 | 12 | class _MapSearchPageState extends State { 13 | static const String key = 14 | 'pk.eyJ1Ijoiemh1b3l1YW45OSIsImEiOiJja2VwcXducjUya291MnFucDNlMmZmeDAzIn0.JoxtgAjdqfpZZz-dUJLykQ'; 15 | 16 | TextEditingController controller = TextEditingController(); 17 | 18 | List addressList = []; 19 | 20 | var placesSearch = PlacesSearch( 21 | apiKey: key, 22 | limit: 8, 23 | ); 24 | 25 | var selectAddress; 26 | var loadingText = ''; 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | floatingActionButton: FloatingActionButton( 32 | onPressed: baiduSearch, 33 | ), 34 | appBar: AppBar( 35 | title: Text(loadingText), 36 | ), 37 | body: GestureDetector( 38 | onTap: () { 39 | FocusScope.of(context).requestFocus(FocusNode()); 40 | }, 41 | child: ListView( 42 | children: [ 43 | Text('选择的地址:$selectAddress'), 44 | TextField( 45 | onChanged: (text) async { 46 | setState(() { 47 | loadingText = '正在搜寻位置'; 48 | }); 49 | getGooglePlaces(text); 50 | var places = await getPlaces(text); 51 | 52 | setState(() { 53 | loadingText = '搜索完成'; 54 | addressList = places; 55 | }); 56 | }, 57 | decoration: InputDecoration( 58 | hintText: '输入地址', 59 | ), 60 | ), 61 | ListView.builder( 62 | shrinkWrap: true, 63 | itemBuilder: _itemBuilder, 64 | itemCount: addressList.length, 65 | ) 66 | ], 67 | ), 68 | ), 69 | ); 70 | } 71 | 72 | Future> getPlaces(String place) => 73 | placesSearch.getPlaces(place); 74 | 75 | Future getGooglePlaces(String place) async { 76 | String googleBaseUrl = 77 | 'https://maps.googleapis.com/maps/api/place/autocomplete/json'; 78 | 79 | Response response = await HttpUtil().get(googleBaseUrl, 80 | data: {'key': PLACES_API_KEY, 'input': place, 'type': 'regions'}); 81 | print(response); 82 | } 83 | 84 | Future baiduSearch() async { 85 | String baiduBaseUrl = 'http://api.map.baidu.com/place_abroad/v1/search'; 86 | 87 | var response = await HttpUtil().get(baiduBaseUrl, data: { 88 | 'ak': 'o7BxXRdG5GEZ8qbA03GGvA1Xix7UcG0P', 89 | 'output': 'json', 90 | 'region': '全国', 91 | 'query': 'newyor', 92 | }); 93 | } 94 | 95 | Widget _itemBuilder(BuildContext context, int index) { 96 | return ListTile( 97 | onTap: () { 98 | _onTap(addressList[index]); 99 | }, 100 | leading: Icon(Icons.location_city), 101 | title: Text('${addressList[index].text}'), 102 | ); 103 | } 104 | 105 | void _onTap(address) { 106 | print('click $address'); 107 | setState(() { 108 | selectAddress = address; 109 | addressList?.clear(); 110 | }); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/page/modal_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ModalPage extends StatefulWidget { 4 | @override 5 | _ModalPageState createState() => _ModalPageState(); 6 | } 7 | 8 | class _ModalPageState extends State { 9 | String fileContent; 10 | 11 | String timeZone; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text('弹窗'), 18 | ), 19 | body: Column( 20 | children: [ 21 | RaisedButton( 22 | child: Text('show bottom sheet'), 23 | onPressed: _showBottom, 24 | ) 25 | ], 26 | ), 27 | ); 28 | } 29 | 30 | Future _showBottom() async { 31 | var res = await showModalBottomSheet( 32 | context: context, 33 | isScrollControlled: true, 34 | shape: RoundedRectangleBorder( 35 | borderRadius: BorderRadius.circular(15), 36 | side: BorderSide( 37 | color: Colors.blue, 38 | width: 5 39 | ), 40 | ), 41 | builder: (context) => Container( 42 | height: 400, 43 | child: Column( 44 | children: [ 45 | Text('top'), 46 | RaisedButton( 47 | child: Text('pop pop'), 48 | onPressed: () { 49 | Navigator.of(context).pop('pop'); 50 | }, 51 | ), 52 | SizedBox( 53 | height: 300, 54 | ), 55 | Text('bottom') 56 | ], 57 | ), 58 | ), 59 | ); 60 | tt(res, (result, index) => {print(result)}); 61 | } 62 | 63 | void tt(String s, MyFun f) { 64 | f(s, 1); 65 | } 66 | } 67 | 68 | typedef MyFun = Function(String result, int index); 69 | -------------------------------------------------------------------------------- /lib/page/repaint_boundary_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:typed_data'; 3 | import 'dart:ui' as ui; 4 | import 'dart:ui'; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter/rendering.dart'; 8 | import 'package:flutter_share_me/flutter_share_me.dart'; 9 | import 'package:fluttertoast/fluttertoast.dart'; 10 | import 'package:path_provider/path_provider.dart'; 11 | 12 | class RepaintBoundaryPage extends StatefulWidget { 13 | @override 14 | _RepaintBoundaryPageState createState() => _RepaintBoundaryPageState(); 15 | } 16 | 17 | class _RepaintBoundaryPageState extends State { 18 | GlobalKey _globalKey = GlobalKey(); 19 | Uint8List uint8list; 20 | File file; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | //getFile(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | floatingActionButton: FloatingActionButton( 32 | child: Icon(Icons.delete_forever), 33 | onPressed: deleteFile, 34 | ), 35 | appBar: AppBar( 36 | title: Text('屏幕/组件截图'), 37 | actions: [ 38 | IconButton( 39 | icon: Icon(Icons.share), 40 | onPressed: share, 41 | ) 42 | ], 43 | ), 44 | body: Container( 45 | color: Colors.grey, 46 | alignment: Alignment.center, 47 | child: Column( 48 | crossAxisAlignment: CrossAxisAlignment.center, 49 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 50 | children: [ 51 | ElevatedButton( 52 | child: Text('以下的东西会截图'), 53 | onPressed: _screenShot, 54 | ), 55 | RepaintBoundary( 56 | key: _globalKey, 57 | child: Row( 58 | mainAxisAlignment: MainAxisAlignment.center, 59 | children: [ 60 | Text( 61 | '图里的文字', 62 | style: TextStyle(color: Colors.blue, fontSize: 20), 63 | ), 64 | Icon( 65 | Icons.accessibility, 66 | color: Colors.red, 67 | ), 68 | ], 69 | ), 70 | ), 71 | Text('↓以下为截图的内容↓'), 72 | if (uint8list != null) Image.memory(uint8list), 73 | Text('↓下面的图片为本地保存的图片文件↓'), 74 | if (file?.existsSync() == true) Image.file(file), 75 | ], 76 | ), 77 | )); 78 | } 79 | 80 | Future deleteFile() async { 81 | bool fileIsExist = await file.exists(); 82 | if (fileIsExist) { 83 | file.deleteSync(); 84 | setState(() {}); 85 | print('删除图片成功:${file.existsSync()}'); 86 | } 87 | } 88 | 89 | Future _screenShot() async { 90 | RenderRepaintBoundary boundary = _globalKey.currentContext.findRenderObject(); 91 | ui.Image image = await boundary.toImage(); 92 | ByteData byteData = await image.toByteData(format: ImageByteFormat.png); 93 | Uint8List pngBytes = byteData.buffer.asUint8List(); 94 | 95 | setState(() { 96 | uint8list = pngBytes; 97 | }); 98 | 99 | byte2File(pngBytes); 100 | } 101 | 102 | /// 把图片ByteData写入File 103 | Future byte2File(Uint8List pngBytes) async { 104 | await getFile(); 105 | if (!file.existsSync()) { 106 | file.createSync(); 107 | print('生成图片文件:$file'); 108 | } 109 | file.writeAsBytesSync(pngBytes); 110 | if (file.existsSync()) { 111 | print('图片保存成功'); 112 | Fluttertoast.showToast(msg: '图片保存成功'); 113 | } 114 | } 115 | 116 | Future getFile() async { 117 | Directory tempDir = await getTemporaryDirectory(); 118 | file = File('${tempDir.path}/img${DateTime.now()}.png'); 119 | 120 | setState(() {}); 121 | } 122 | 123 | void share() { 124 | FlutterShareMe().shareToWhatsApp(imagePath: file.path, msg: 'ssss'); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /lib/page/route_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | class RoutePage extends StatelessWidget { 5 | final List listData = []; 6 | 7 | void initData(BuildContext context) { 8 | listData.clear(); 9 | 10 | listData.add(ListItem("Home Page", "Home", Icons.home)); 11 | listData.add(ListItem("Pavlova示例", "Pavlova", Icons.panorama_vertical)); 12 | listData.add(ListItem("randomWords示例", "randomWords", Icons.book)); 13 | listData.add(ListItem("图片", "Image", Icons.image)); 14 | listData.add(ListItem("GridView", "GridView", Icons.grid_on)); 15 | listData.add(ListItem("StateWidget", "StateWidget", Icons.widgets)); 16 | listData.add(ListItem("TextField", "TextField", Icons.text_fields)); 17 | listData.add(ListItem("KeepAlive", "KeepAlive", Icons.live_tv)); 18 | listData.add(ListItem("Swiper", "Swiper", Icons.landscape)); 19 | listData.add(ListItem("流式布局", "Wrap", Icons.landscape)); 20 | listData.add(ListItem("动画", "Animation", Icons.landscape)); 21 | listData.add(ListItem('动画2', 'AnimationTwo', Icons.android)); 22 | listData.add(ListItem("屏幕适配示例", "ScreenUtilPage", Icons.landscape)); 23 | listData.add(ListItem("futureBuilder", "FutureBuilderPage", Icons.hourglass_full)); 24 | listData.add(ListItem("主题", "ThemePage", Icons.landscape)); 25 | listData.add(ListItem("Chip", "ChipPage", Icons.landscape)); 26 | listData.add(ListItem("ExpansionTile", "ExpansionTilePage", Icons.landscape)); 27 | listData.add(ListItem("Transform 3D效果", "TransformPage", Icons.landscape)); 28 | listData.add(ListItem("登录页", "LoginPage", Icons.landscape)); 29 | listData.add(ListItem("WebView", "WebViewPage", Icons.web)); 30 | listData.add(ListItem("自定义View", "CustomViewPage", Icons.view_quilt)); 31 | listData.add(ListItem("Tab的使用", "TabPae", Icons.view_quilt)); 32 | listData.add(ListItem("backdropPage", "backdropPage", Icons.view_quilt)); 33 | listData.add(ListItem('可拖动组件', 'Draggable', Icons.drag_handle)); 34 | listData.add(ListItem('分享', 'SharePage', Icons.share)); 35 | listData.add(ListItem('搜索', 'SearchPage', Icons.search)); 36 | listData.add(ListItem('mp4视频播放', 'VideoPlayerPage', Icons.video_library)); 37 | listData.add(ListItem('Youtube视频播放', 'FlutterYoutubePage', Icons.video_library)); 38 | listData.add(ListItem('FlutterNativeWeb插件的使用', 'FlutterNativeWeb', Icons.web)); 39 | listData.add(ListItem('sqflite的使用', 'SqfLitePage', Icons.crop_square)); 40 | listData.add(ListItem('步骤条Stepper ', 'StepperPage', Icons.short_text)); 41 | listData.add(ListItem('类似于qq列表的组件树', 'TreePage', Icons.people)); 42 | listData.add(ListItem('Sliver', 'Sliver', Icons.list)); 43 | listData 44 | .add(ListItem('CupertinoActionSheet', 'CupertinoActionSheetPage', Icons.call_to_action)); 45 | listData.add(ListItem('按比例设置尺寸', 'FractionallySizedBoxPage', Icons.crop_din)); 46 | listData.add(ListItem('屏幕/组件截图', 'RepaintBoundaryPage', Icons.screen_lock_landscape)); 47 | listData.add(ListItem('高斯模糊&扩展函数', 'ExtensionPage', Icons.extension)); 48 | listData.add(ListItem('搜索地理位置', 'MapSearchPage', Icons.location_city)); 49 | listData.add( 50 | ListItem('DraggableScrollableSheetPage', 'DraggableScrollableSheet', Icons.location_city)); 51 | listData.add(ListItem('弹窗', 'ModalPage', Icons.airplanemode_active)); 52 | listData.add(ListItem('日期选择器,多级联动', 'PickerPage', Icons.airplanemode_active)); 53 | 54 | listData.add(ListItem('复杂的CustomScrollView', 'CustomScrollViewPage', Icons.crop_rotate)); 55 | } 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | initData(context); 60 | 61 | //设置适配尺寸 (填入设计稿中设备的屏幕尺寸) 假如设计稿是按iPhone6的尺寸设计的(iPhone6 750*1334) 62 | return Scaffold( 63 | appBar: AppBar( 64 | title: Text('列表'), 65 | centerTitle: true, 66 | ), 67 | body: ListView.builder( 68 | itemBuilder: (BuildContext context, int index) { 69 | return ListItemWidget(listData[index]); 70 | }, 71 | itemCount: listData.length, 72 | ), 73 | ); 74 | } 75 | } 76 | 77 | class ListItem { 78 | final String title; 79 | final String routeName; 80 | final IconData iconData; 81 | 82 | ListItem(this.title, this.routeName, this.iconData); 83 | } 84 | 85 | class ListItemWidget extends StatelessWidget { 86 | final ListItem listItem; 87 | 88 | ListItemWidget(this.listItem); 89 | 90 | @override 91 | Widget build(BuildContext context) { 92 | return ListTile( 93 | title: Text(listItem.title), 94 | leading: Icon(listItem.iconData), 95 | trailing: Icon(Icons.arrow_forward), 96 | onTap: () { 97 | Navigator.pushNamed(context, listItem.routeName, arguments: listItem.title); 98 | }); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/page/search_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/2/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/widget/searchbar_delegate.dart'; 9 | 10 | class SearchPage extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('搜索'), 16 | ), 17 | body: Container( 18 | child: RaisedButton( 19 | onPressed: () { 20 | showSearch(context: context, delegate: SearchBarDelegate()); 21 | }, 22 | child: Text('去搜索')), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/page/sliver_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2020/7/5 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | import 'package:flutter/material.dart'; 7 | 8 | class SliverPage extends StatefulWidget { 9 | @override 10 | _SliverPageState createState() => _SliverPageState(); 11 | } 12 | 13 | class _SliverPageState extends State { 14 | List list = [1, 2, 3, 4, 5]; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | body: CustomScrollView( 20 | slivers: [ 21 | SliverAppBar( 22 | automaticallyImplyLeading: false, 23 | elevation: 5, 24 | forceElevated: true, 25 | expandedHeight: 200, 26 | floating: true, 27 | snap: false, 28 | pinned: true, 29 | stretch: true, 30 | flexibleSpace: FlexibleSpaceBar( 31 | title: Text('SliverAppBar'), 32 | background: Image.asset( 33 | 'images/pic1.jpg', 34 | fit: BoxFit.fill, 35 | ), 36 | //标题是否居中 37 | centerTitle: false, 38 | //标题间距 39 | //titlePadding: EdgeInsetsDirectional.only(start: 0, bottom: 16), 40 | collapseMode: CollapseMode.parallax, 41 | )), 42 | SliverList( 43 | delegate: SliverChildBuilderDelegate( 44 | _reportBuilder, 45 | childCount: list.length + 1, 46 | ), 47 | ), 48 | SliverToBoxAdapter( 49 | child: Text('Title'), 50 | ), 51 | SliverGrid( 52 | gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( 53 | maxCrossAxisExtent: 400), 54 | delegate: SliverChildBuilderDelegate( 55 | _reportBuilder, 56 | childCount: list.length + 1, 57 | ), 58 | ) 59 | ], 60 | ), 61 | ); 62 | } 63 | 64 | Widget _reportBuilder(BuildContext context, int index) { 65 | const header = Text('I am title'); 66 | 67 | if (index <= 0) { 68 | return header; 69 | } else { 70 | int listIndex = index - 1; 71 | print(listIndex); 72 | return Container( 73 | color: Colors.blue, 74 | height: 200, 75 | child: Text('${list[listIndex]}'), 76 | ); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/page/sqflite_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/3/12. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/model/note.dart'; 9 | import 'package:flutter_app/utils/dbHelper.dart'; 10 | 11 | class SqfLite extends StatefulWidget { 12 | @override 13 | _SqfLiteState createState() => _SqfLiteState(); 14 | } 15 | 16 | class _SqfLiteState extends State { 17 | List notes = []; 18 | int i = 0; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: Text('Sqflite的使用'), 25 | centerTitle: true, 26 | ), 27 | body: Container( 28 | child: Column( 29 | children: [ 30 | ButtonBar( 31 | children: [ 32 | RaisedButton( 33 | onPressed: _insertData, 34 | child: Text('存储数据'), 35 | ), 36 | RaisedButton( 37 | onPressed: getNotes, 38 | child: Text('点一次取2条数据'), 39 | ), 40 | ], 41 | ), 42 | Expanded( 43 | child: ListView.builder( 44 | itemBuilder: _itemBuilder, 45 | shrinkWrap: true, 46 | itemCount: notes.length, 47 | ), 48 | ) 49 | ], 50 | ), 51 | ), 52 | ); 53 | } 54 | 55 | void _insertData() async { 56 | var db = DatabaseHelper(); 57 | Note todo = new Note(DateTime.now().millisecondsSinceEpoch, 'imarge', i, i, 58 | 0.1 * i, 0.1 * i); 59 | i++; 60 | await db.saveNote(todo); 61 | 62 | getNotes(); 63 | } 64 | 65 | void getNotes() async { 66 | var db = DatabaseHelper(); 67 | var res = await db.getAllNotes(limit: 2, offset: notes.length); 68 | setState(() { 69 | notes.addAll(res); 70 | }); 71 | } 72 | 73 | Widget _itemBuilder(BuildContext context, int index) { 74 | return Text('${notes[index]}'); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/page/stepper_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/8/5. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | 9 | class StepperPage extends StatefulWidget { 10 | @override 11 | _StepperPageState createState() => _StepperPageState(); 12 | } 13 | 14 | class _StepperPageState extends State { 15 | int _currentStep; 16 | List _list; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _currentStep = 0; 22 | _list = []; 23 | for (int i = 0; i < 5; i++) { 24 | _list.add('title:$i'); 25 | } 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text('Stepper(步骤条)'), 33 | ), 34 | body: Container( 35 | child: Stepper( 36 | steps: _list 37 | .map((item) => Step( 38 | title: Text(item), 39 | content: SizedBox(), 40 | isActive: _currentStep == _list.indexOf(item))) 41 | .toList(), 42 | type: StepperType.vertical, 43 | currentStep: _currentStep, 44 | onStepCancel: stepCancel, 45 | onStepContinue: stepContinue, 46 | onStepTapped: stepTapped, 47 | controlsBuilder: (BuildContext context, 48 | {VoidCallback onStepContinue, VoidCallback onStepCancel}) { 49 | return Container( 50 | /*width: double.infinity, 51 | color: Colors.blue, 52 | child: RaisedButton( 53 | child: Text('next'), 54 | onPressed: onStepContinue, 55 | ),*/ 56 | ); 57 | }, 58 | )), 59 | ); 60 | } 61 | 62 | void stepCancel() { 63 | setState(() { 64 | _currentStep = 0; 65 | }); 66 | } 67 | 68 | void stepContinue() { 69 | if (_currentStep < _list.length - 1) 70 | setState(() { 71 | _currentStep++; 72 | }); 73 | } 74 | 75 | void stepTapped(int i) { 76 | setState(() { 77 | _currentStep = i; 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/page/tab_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/10/18. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 8 | 9 | class TabPage extends StatefulWidget { 10 | @override 11 | _TabPageState createState() => _TabPageState(); 12 | } 13 | 14 | class _TabPageState extends State with SingleTickerProviderStateMixin { 15 | TabController _mysTabController; 16 | Color _color; 17 | final List _colors = [ 18 | Colors.blue, 19 | Colors.green, 20 | Colors.pink, 21 | Colors.yellow, 22 | Colors.red, 23 | Colors.purple, 24 | Colors.grey, 25 | ]; 26 | final List myTabs = [ 27 | Tab(text: '明教'), 28 | Tab(text: '霸刀'), 29 | Tab(text: '天策'), 30 | Tab(text: '纯阳'), 31 | Tab(text: '少林'), 32 | Tab(text: '藏剑'), 33 | Tab(text: '五毒'), 34 | ]; 35 | 36 | final List myTabBarViews = [ 37 | Tab(text: '喵喵喵喵喵喵喵喵喵喵'), 38 | Tab(text: '叨叨叨叨叨叨叨叨叨叨'), 39 | Tab(text: '汪汪汪汪汪汪汪汪汪汪'), 40 | Tab(text: '咩咩咩咩咩咩咩咩咩咩'), 41 | Tab(text: '观自在菩萨,行深般若波罗蜜多时'), 42 | Tab(text: '君子如风,藏剑西湖'), 43 | Tab(text: '情之所依,心之所系。代君受命,保君平安。'), 44 | ]; 45 | 46 | @override 47 | void initState() { 48 | _color ??= _colors[0]; //设置一个颜色的初始值 49 | _mysTabController = TabController(vsync: this, length: myTabs.length); 50 | super.initState(); 51 | _mysTabController.animation.addListener(() { 52 | setState(() { 53 | _color = _colors[_mysTabController.index]; 54 | 55 | //当Tab向右滑动时 56 | if (_mysTabController.offset > 0) { 57 | final ColorTween myscolor = ColorTween( 58 | begin: _colors[_mysTabController.index], 59 | end: _colors[_mysTabController.index + 1], 60 | ); 61 | _color = myscolor.lerp(_mysTabController.offset); 62 | } else if (_mysTabController.offset < 0) { 63 | //当Tab向左滑动时 64 | final ColorTween myscolor = ColorTween( 65 | begin: _colors[_mysTabController.index], 66 | end: _colors[_mysTabController.index - 1], 67 | ); 68 | _color = myscolor.lerp(-_mysTabController.offset); 69 | } 70 | print(_mysTabController.offset); 71 | }); 72 | }); 73 | } 74 | 75 | @override 76 | void dispose() { 77 | _mysTabController.dispose(); 78 | super.dispose(); 79 | } 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | return Scaffold( 84 | backgroundColor: _color, 85 | body: Column( 86 | children: [ 87 | Container( 88 | color: _color, 89 | height: ScreenUtil().statusBarHeight, 90 | ), 91 | CustomScrollView( 92 | shrinkWrap: true, 93 | slivers: [ 94 | SliverToBoxAdapter( 95 | child: Text('asda'), 96 | ), 97 | SliverToBoxAdapter( 98 | child: Container( 99 | child: TabBar( 100 | controller: _mysTabController, 101 | labelColor: Colors.black, 102 | tabs: [...myTabs], 103 | isScrollable: true, 104 | ), 105 | ), 106 | ), 107 | SliverToBoxAdapter( 108 | child: SizedBox( 109 | height: 500, 110 | child: TabBarView( 111 | controller: _mysTabController, 112 | children: myTabBarViews 113 | .map((Tab tab) => Container( 114 | alignment: Alignment.center, 115 | // color: _color, 116 | child: Text( 117 | tab.text, 118 | style: TextStyle(color: Colors.white), 119 | ), 120 | )) 121 | .toList()), 122 | ), 123 | ), 124 | SliverToBoxAdapter( 125 | child: Container( 126 | height: 20, 127 | color: Colors.blue, 128 | ), 129 | ) 130 | ], 131 | ), 132 | ], 133 | ), 134 | ); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /lib/page/theme_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/10/8. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/model/AppModel.dart'; 9 | import 'package:flutter_app/rxdart/bloc_provider.dart'; 10 | import 'package:flutter_app/rxdart/theme_select.dart'; 11 | 12 | import 'package:scoped_model/scoped_model.dart'; 13 | 14 | class ThemePage extends StatefulWidget { 15 | @override 16 | State createState() => ThemeState(); 17 | } 18 | 19 | class ThemeState extends State { 20 | ThemeSelect themeSelect; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | themeSelect = BlocProvider.of(context); 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text('夜间模式'), 28 | ), 29 | body: StreamBuilder( 30 | builder: _builder, 31 | stream: themeSelect.value, 32 | initialData: false, 33 | ), 34 | ); 35 | } 36 | 37 | Widget _builder(BuildContext context, AsyncSnapshot snapshot) { 38 | return Row( 39 | children: [ 40 | Text('夜间模式'), 41 | Switch( 42 | value: snapshot.data, 43 | onChanged: (bool value) { 44 | print('value:$value'); 45 | themeSelect.changeTheme(value); 46 | }) 47 | ], 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/page/tree_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app/widget/node.dart'; 3 | 4 | ///类似于qq列表的组件树 5 | class TreePage extends StatefulWidget { 6 | @override 7 | _TreePageState createState() => _TreePageState(); 8 | } 9 | 10 | class _TreePageState extends State { 11 | List goodFriends2 = ['刘亦菲', '李一桐', '信']; 12 | List goodFriends = ['陈浩', '胡歌', '周杰伦', '田馥甄']; 13 | List sb = ['罗永浩', '陈年', '特朗普', '安倍晋三']; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | print(goodFriends.length); 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("类似于qq列表的组件树"), 21 | ), 22 | body: NodeWidget( 23 | node: Node(me: Text('我的好友'), children: [ 24 | Node( 25 | me: NodeWidget( 26 | node: Node( 27 | me: Text('好友1'), 28 | children: 29 | goodFriends.map((f) => Node(me: Text(f))).toList()))), 30 | Node( 31 | me: NodeWidget( 32 | node: Node(me: Text('家人'), children: [ 33 | ...goodFriends2.map((item) => Node(me: Text(item))) 34 | ]), 35 | )), 36 | Node( 37 | me: NodeWidget( 38 | node: Node( 39 | children: [...sb.map((item) => Node(me: Text(item)))], 40 | me: Text('MDZZ')), 41 | ), 42 | ) 43 | ]), 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/page/video_player.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/2/22. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | 9 | class VideoPlayerPage extends StatefulWidget { 10 | @override 11 | _VideoPlayerPageState createState() => _VideoPlayerPageState(); 12 | } 13 | 14 | class _VideoPlayerPageState extends State { 15 | // VideoPlayerController _videoPlayerController; 16 | String videoUrl = 17 | 'https:\/\/r2---sn-t0a7ln7d.googlevideo.com\/videoplayback?pcm2=no&id=o-AGhjJTNX-_rpxrF-lQPBebK-cqFnodGNEMsSZ1RlZPHM&key=yt6&mn=sn-t0a7ln7d%2Csn-vgqsknlz&mm=31%2C26&expire=1551100886&ms=au%2Conr&requiressl=yes&ei=dZdzXI2sOeHP8gTiuahA&fvip=2&pl=24&mv=u&ipbits=0&ip=54.80.95.108&ratebypass=yes&txp=5531432&sparams=dur%2Cei%2Cid%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpcm2%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cexpire&signature=246C48A87B1DE26DACF4558F02F14836F986F125.2058F1D1395A987D10183B01486A5BE7384FB482&lmt=1542774011565518&dur=552.588&itag=22&mime=video%2Fmp4&source=youtube&mt=1551078639'; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text('播放视频'), 30 | ), 31 | 32 | ); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | super.dispose(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/page/wrap_page.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/27. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | 9 | import 'package:fluttertoast/fluttertoast.dart'; 10 | 11 | class WrapPage extends StatelessWidget { 12 | final List list = [ 13 | '斗破苍穹', 14 | '遮天', 15 | '斗罗大陆', 16 | '大主宰', 17 | '凡人修仙传', 18 | '盗墓笔记', 19 | '校花的贴身高手', 20 | '诛仙' 21 | ]; 22 | 23 | List _childList(BuildContext context) { 24 | List childs = []; 25 | /*for (int i = 0; i < list.length; i++) { 26 | childs.add(Text(list[i])); 27 | }*/ 28 | childs.addAll( 29 | list.map((item) => Container( 30 | child: Row( 31 | mainAxisSize: MainAxisSize.min, 32 | children: [ 33 | Container( 34 | color: Colors.red, 35 | child: Text( 36 | '#', 37 | style: TextStyle(color: Colors.white), 38 | ), 39 | ), 40 | Text(item), 41 | ], 42 | ), 43 | padding: EdgeInsets.all(8), 44 | color: Colors.blue)), 45 | ); 46 | // list.forEach((item) => childs.add(Text(item))); 47 | return childs; 48 | } 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return Scaffold( 53 | appBar: AppBar( 54 | title: Text('流式布局'), 55 | ), 56 | body: Container( 57 | padding: EdgeInsets.all(10.0), 58 | child: Wrap( 59 | alignment: WrapAlignment.start, 60 | children: _childList(context), 61 | spacing: 10.0, 62 | runSpacing: 10.0, 63 | direction: Axis.horizontal, 64 | //children: list.map((item) => (Text(item))).toList(), 65 | ), 66 | ), 67 | ); 68 | } 69 | } 70 | 71 | class Textbook extends StatelessWidget { 72 | final item; 73 | 74 | Textbook(this.item); 75 | 76 | @override 77 | Widget build(BuildContext context) { 78 | return GestureDetector( 79 | onTap: () { 80 | Fluttertoast.showToast(msg: item); 81 | /* Scaffold.of(context).showSnackBar(SnackBar( 82 | content: Text(item), 83 | action: new SnackBarAction( 84 | label: "撤回", 85 | onPressed: () {}, 86 | ), 87 | ));*/ 88 | }, 89 | child: Container( 90 | padding: EdgeInsets.all(5.0), 91 | decoration: BoxDecoration( 92 | border: Border.all( 93 | color: Colors.blue, width: 2.0, style: BorderStyle.solid), 94 | borderRadius: new BorderRadius.all(new Radius.circular(2.0)), 95 | ), 96 | child: Text( 97 | item, 98 | style: TextStyle(fontSize: 18.0), 99 | ), 100 | )); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app/page/ChipPage.dart'; 3 | import 'package:flutter_app/page/ExpansionTilePage.dart'; 4 | import 'package:flutter_app/page/FutureBuilderPage.dart'; 5 | import 'package:flutter_app/page/GridViewPage.dart'; 6 | import 'package:flutter_app/page/ImagePage.dart'; 7 | import 'package:flutter_app/page/KeepAlivePage.dart'; 8 | import 'package:flutter_app/page/MyHomePage.dart'; 9 | import 'package:flutter_app/page/PavlovaPage.dart'; 10 | import 'package:flutter_app/page/RandomWords.dart'; 11 | import 'package:flutter_app/page/cupertino_action_sheet_page.dart'; 12 | import 'package:flutter_app/page/custom_scrollview_page.dart'; 13 | import 'package:flutter_app/page/draggable_scrollable_sheet_page.dart'; 14 | import 'package:flutter_app/page/flutter_picker_page.dart'; 15 | import 'package:flutter_app/page/fractionally_sized_box_page.dart'; 16 | import 'package:flutter_app/page/map_search_page.dart'; 17 | import 'package:flutter_app/page/modal_page.dart'; 18 | import 'package:flutter_app/page/repaint_boundary_page.dart'; 19 | import 'package:flutter_app/page/extension_page.dart'; 20 | import 'package:flutter_app/page/route_page.dart'; 21 | import 'package:flutter_app/page/ScreenUtilTest.dart'; 22 | import 'package:flutter_app/page/StateWidgetPage.dart'; 23 | import 'package:flutter_app/page/SwiperPage.dart'; 24 | import 'package:flutter_app/page/theme_page.dart'; 25 | import 'package:flutter_app/page/Transform3D.dart'; 26 | import 'package:flutter_app/page/wrap_page.dart'; 27 | import 'package:flutter_app/page/animation_page.dart'; 28 | import 'package:flutter_app/page/animation_two.dart'; 29 | import 'package:flutter_app/page/backdrop_page.dart'; 30 | import 'package:flutter_app/page/custom_animation_page.dart'; 31 | import 'package:flutter_app/page/draggable_dragtargets.dart'; 32 | import 'package:flutter_app/page/flutter_native_web.dart'; 33 | import 'package:flutter_app/page/login_page.dart'; 34 | import 'package:flutter_app/page/search_page.dart'; 35 | import 'package:flutter_app/page/share_page.dart'; 36 | import 'package:flutter_app/page/sliver_page.dart'; 37 | import 'package:flutter_app/page/sqflite_page.dart'; 38 | import 'package:flutter_app/page/tab_page.dart'; 39 | import 'package:flutter_app/page/textField.dart'; 40 | import 'package:flutter_app/page/tree_page.dart'; 41 | import 'package:flutter_app/page/video_player.dart'; 42 | 43 | import 'page/stepper_page.dart'; 44 | 45 | final routes = { 46 | //静态路由,无法传参 47 | '/': (_) => RoutePage(), 48 | 'randomWords': (_) => RandomWords(), 49 | 'Home': (context) => MyHomePage(tag: ModalRoute.of(context).settings.arguments), 50 | 'Pavlova': (_) => PavlovaPage(), 51 | 'Image': (_) => ImagePage(), 52 | 'GridView': (_) => GridViewPage(), 53 | 'StateWidget': (_) => StateWidgetPage(), 54 | 'TextField': (_) => TextFieldAndCheckPage(), 55 | 'KeepAlive': (_) => KeepAliveDemo(), 56 | 'Swiper': (_) => SwiperPage(), 57 | 'Wrap': (_) => WrapPage(), 58 | 'Animation': (_) => AnimationPage(), 59 | 'ScreenUtilPage': (_) => ScreenUtilTest(title: 'ScreenUtil测试'), 60 | 'FutureBuilderPage': (_) => FutureBuilderPage(), 61 | 'ThemePage': (_) => ThemePage(), 62 | 'ChipPage': (_) => ChipPage(), 63 | 'ExpansionTilePage': (_) => ExpansionTilePage(), 64 | 'TransformPage': (_) => Transform3D(), 65 | 'LoginPage': (_) => LoginPage(), 66 | 'CustomViewPage': (_) => CustomAnimationPage(), 67 | 'TabPae': (_) => TabPage(), 68 | 'backdropPage': (_) => BackdropPage(), 69 | 'Draggable': (_) => DraggableDragtargets(), 70 | 'SharePage': (_) => SharePage(), 71 | 'AnimationTwo': (_) => AnimationTwo(), 72 | 'SearchPage': (_) => SearchPage(), 73 | 'VideoPlayerPage': (_) => VideoPlayerPage(), 74 | 'Sliver': (_) => SliverPage(), 75 | 'FlutterNativeWeb': (_) => FlutterNativeWebPage(), 76 | 'SqfLitePage': (_) => SqfLite(), 77 | 'StepperPage': (_) => StepperPage(), 78 | 'TreePage': (_) => TreePage(), 79 | 'CupertinoActionSheetPage': (_) => CupertinoActionSheetPage(), 80 | 'FractionallySizedBoxPage': (_) => FractionallySizedBoxPage(), 81 | 'RepaintBoundaryPage': (_) => RepaintBoundaryPage(), 82 | 'ExtensionPage': (_) => ExtensionPage(), 83 | 'MapSearchPage': (_) => MapSearchPage(), 84 | 'DraggableScrollableSheet': (_) => DraggableScrollableSheetPage(), 85 | 'ModalPage': (_) => ModalPage(), 86 | 'PickerPage': (_) => PickerPage(), 87 | 'CustomScrollViewPage': (_) => CustomScrollViewPage(), 88 | }; 89 | 90 | ///当通过Navigation.of(context).pushNamed跳转路由时,在routes查找不到时,会调用该方法 91 | Route onGenerateRoute(RouteSettings settings) { 92 | return MaterialPageRoute(builder: (BuildContext context) { 93 | String routeName = settings.name; 94 | print('----route name : $routeName'); 95 | 96 | return Scaffold( 97 | appBar: AppBar( 98 | title: Text('$routeName'), 99 | ), 100 | body: Text('找不到$routeName'), 101 | ); 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /lib/rxdart/bloc_provider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/10/30. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/rxdart/theme_select.dart'; 9 | 10 | class BlocProvider extends InheritedWidget { 11 | final ThemeSelect themeSelect = ThemeSelect(); 12 | 13 | BlocProvider({Key key, Widget child}) : super(key: key, child: child); 14 | 15 | @override 16 | bool updateShouldNotify(_) => true; 17 | 18 | static ThemeSelect of(BuildContext context) => 19 | (context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider) 20 | .themeSelect; 21 | } 22 | -------------------------------------------------------------------------------- /lib/rxdart/theme_select.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/10/30. 3 | * email: zhuoyuan93@gmail.com 4 | * rxdart 实现 主题切换 5 | */ 6 | import 'dart:async'; 7 | 8 | import 'package:rxdart/rxdart.dart'; 9 | import 'package:shared_preferences/shared_preferences.dart'; 10 | 11 | class ThemeSelect { 12 | ThemeSelect() { 13 | print("theme select cons"); 14 | 15 | initTheme(); 16 | } 17 | 18 | var _subject = BehaviorSubject(); 19 | 20 | Stream get value => _subject.stream; 21 | 22 | void changeTheme(bool value) async { 23 | SharedPreferences preferences = await SharedPreferences.getInstance(); 24 | preferences.setBool("isNight", value); 25 | _subject.add(value); 26 | } 27 | 28 | void dispose() { 29 | _subject.close(); 30 | } 31 | 32 | void initTheme() async { 33 | SharedPreferences preferences = await SharedPreferences.getInstance(); 34 | bool isNight = preferences.getBool("isNight") ?? false; 35 | preferences.setBool("isNight", isNight); 36 | _subject.add(isNight); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/theme/app_theme.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/10/30. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | import 'package:flutter/material.dart'; 7 | 8 | class AppTheme { 9 | final darkTheme = ThemeData( 10 | backgroundColor: Colors.black, 11 | primaryColor: Colors.black, 12 | brightness: Brightness.dark); 13 | 14 | final lightTheme = ThemeData( 15 | backgroundColor: Colors.white, 16 | primaryColor: Colors.green, 17 | primarySwatch: Colors.blue, 18 | brightness: Brightness.light); 19 | } 20 | -------------------------------------------------------------------------------- /lib/utils/HttpUtil.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/15. 3 | * email: zhuoyuan93@gmail.com 4 | * 网络请求封装 5 | */ 6 | 7 | import 'package:dio/dio.dart'; 8 | 9 | class HttpUtil { 10 | static HttpUtil instance; 11 | Dio dio; 12 | Options options; 13 | 14 | static HttpUtil getInstance() { 15 | print('getInstance'); 16 | if (instance == null) { 17 | instance = new HttpUtil(); 18 | } 19 | return instance; 20 | } 21 | 22 | HttpUtil() { 23 | print('dio赋值'); 24 | // 或者通过传递一个 `options`来创建dio实例 25 | options = Options( 26 | // 请求基地址,可以包含子路径,如: "https://www.google.com/api/". 27 | baseUrl: "https://www.xx.com/api", 28 | //连接服务器超时时间,单位是毫秒. 29 | connectTimeout: 10000, 30 | 31 | /// 响应流上前后两次接受到数据的间隔,单位为毫秒。如果两次间隔超过[receiveTimeout], 32 | /// [Dio] 将会抛出一个[DioErrorType.RECEIVE_TIMEOUT]的异常. 33 | /// 注意: 这并不是接收数据的总时限. 34 | receiveTimeout: 3000, 35 | headers: {}, 36 | ); 37 | dio = new Dio(options); 38 | } 39 | 40 | get(url, {data, options, cancelToken}) async { 41 | print('get请求启动! url:$url ,body: $data'); 42 | Response response; 43 | try { 44 | response = await dio.get( 45 | url, 46 | data: data, 47 | cancelToken: cancelToken, 48 | ); 49 | print('get请求成功!response.data:${response.data}'); 50 | } on DioError catch (e) { 51 | if (CancelToken.isCancel(e)) { 52 | print('get请求取消! ' + e.message); 53 | } 54 | print('get请求发生错误:$e'); 55 | } 56 | return response.data; 57 | } 58 | 59 | post(url, {data, options, cancelToken}) async { 60 | print('post请求启动! url:$url ,body: $data'); 61 | Response response; 62 | try { 63 | response = await dio.post( 64 | url, 65 | data: data, 66 | cancelToken: cancelToken, 67 | ); 68 | print('post请求成功!response.data:${response.data}'); 69 | } on DioError catch (e) { 70 | if (CancelToken.isCancel(e)) { 71 | print('post请求取消! ' + e.message); 72 | } 73 | print('post请求发生错误:$e'); 74 | } 75 | return response.data; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/utils/dbHelper.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/3/12. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'dart:async'; 8 | 9 | import 'package:flutter_app/model/note.dart'; 10 | import 'package:path/path.dart'; 11 | import 'package:sqflite/sqflite.dart'; 12 | 13 | class DatabaseHelper { 14 | static final DatabaseHelper _instance = new DatabaseHelper.internal(); 15 | 16 | factory DatabaseHelper() => _instance; 17 | 18 | final String tableNote = 'note11Table'; 19 | final String pointID = 'pointid'; 20 | final String image = 'image'; 21 | final String contractId = 'contractId'; 22 | final String publicationId = 'publicationId'; 23 | final String pointLat = 'pointLat'; 24 | final String pointLng = 'pointLng'; 25 | 26 | static Database _db; 27 | 28 | DatabaseHelper.internal(); 29 | 30 | Future get db async { 31 | if (_db != null) { 32 | return _db; 33 | } 34 | _db = await initDb(); 35 | 36 | return _db; 37 | } 38 | 39 | initDb() async { 40 | String databasesPath = await getDatabasesPath(); 41 | String path = join(databasesPath, 'notes11.db'); 42 | 43 | var db = await openDatabase(path, version: 1, onCreate: _onCreate); 44 | return db; 45 | } 46 | 47 | void _onCreate(Database db, int newVersion) async { 48 | await db.execute( 49 | 'CREATE TABLE $tableNote($pointID TEXT PRIMARY KEY, $image TEXT, $contractId TEXT, $publicationId TEXT, $pointLng TEXT, $pointLat TEXT)'); 50 | } 51 | 52 | Future saveNote(Note note) async { 53 | var dbClient = await db; 54 | var result = await dbClient.insert(tableNote, note.toMap()); 55 | 56 | return result; 57 | } 58 | 59 | Future getAllNotes({int limit, int offset}) async { 60 | var dbClient = await db; 61 | var result = await dbClient.query( 62 | tableNote, 63 | columns: [pointID, image, contractId, publicationId, pointLng, pointLat], 64 | limit: limit, 65 | offset: offset, 66 | ); 67 | 68 | return result.toList(); 69 | } 70 | 71 | Future getCount() async { 72 | var dbClient = await db; 73 | return Sqflite.firstIntValue( 74 | await dbClient.rawQuery('SELECT COUNT(*) FROM $tableNote')); 75 | } 76 | 77 | Future getNote(int id) async { 78 | var dbClient = await db; 79 | List result = await dbClient.query(tableNote, 80 | columns: [ 81 | pointID, 82 | image, 83 | contractId, 84 | publicationId, 85 | pointLng, 86 | pointLat 87 | ], 88 | where: '$pointID = ?', 89 | whereArgs: [id]); 90 | 91 | if (result.length > 0) { 92 | return new Note.fromMap(result.first); 93 | } 94 | 95 | return null; 96 | } 97 | 98 | Future deleteNote(String images) async { 99 | var dbClient = await db; 100 | return await dbClient 101 | .delete(tableNote, where: '$image = ?', whereArgs: [images]); 102 | } 103 | 104 | Future updateNote(Note note) async { 105 | var dbClient = await db; 106 | return await dbClient.update(tableNote, note.toMap(), 107 | where: "$pointID = ?", whereArgs: [note.pointID]); 108 | } 109 | 110 | Future close() async { 111 | var dbClient = await db; 112 | return dbClient.close(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /lib/utils/image_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | import 'dart:ui' as ui; 5 | 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter/services.dart'; 8 | 9 | class ImageUtil { 10 | ///通过 文件读取 Image 11 | static Future loadImageByFile(String path) async { 12 | var list = await File(path).readAsBytes(); 13 | return loadImageByUint8List(list); 14 | } 15 | 16 | ///通过ImageProvider读取Image 17 | static Future loadImageByProvider( 18 | ImageProvider provider, { 19 | ImageConfiguration config = ImageConfiguration.empty, 20 | }) async { 21 | Completer completer = Completer(); //完成的回调 22 | ImageStreamListener listener; 23 | ImageStream stream = provider.resolve(config); //获取图片流 24 | listener = ImageStreamListener((ImageInfo frame, bool sync) { 25 | //监听 26 | final ui.Image image = frame.image; 27 | completer.complete(image); //完成 28 | stream.removeListener(listener); //移除监听 29 | }); 30 | stream.addListener(listener); //添加监听 31 | return completer.future; //返回 32 | } 33 | 34 | /// 通过assets路径,获取资源图片 35 | static Future load( 36 | String asset, { 37 | int width, 38 | int height, 39 | }) async { 40 | ByteData data = await rootBundle.load(asset); 41 | return loadImageByUint8List( 42 | data.buffer.asUint8List(), 43 | width: width, 44 | height: height, 45 | ); 46 | } 47 | 48 | ///通过[Uint8List]获取图片 49 | static Future loadImageByUint8List( 50 | Uint8List list, { 51 | int width, 52 | int height, 53 | }) async { 54 | ui.Codec codec = await ui.instantiateImageCodec( 55 | list, 56 | targetWidth: width, 57 | targetHeight: height, 58 | ); 59 | ui.FrameInfo frame = await codec.getNextFrame(); 60 | return frame.image; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/utils/share_util.dart: -------------------------------------------------------------------------------- 1 | import 'package:social_share_plugin/social_share_plugin.dart'; 2 | 3 | class ShareUtil { 4 | static const String img = 5 | '/data/user/0/com.example.flutterapp/cache/img2020-09-23 19:30:51.836764.png'; 6 | 7 | static void shareIns() async { 8 | // InstagramShare.share(img, "image"); 9 | await SocialSharePlugin.shareToFeedInstagram(path: img); 10 | 11 | } 12 | 13 | static void shareFacebook() async { 14 | // await SocialSharePlugin.shareToFeedFacebook(path: img); 15 | 16 | await SocialSharePlugin.shareToFeedFacebookLink(quote: 'quote', url: 'https://flutter.dev'); 17 | } 18 | 19 | static void shareTwitter() async { 20 | var data = await SocialSharePlugin.shareToTwitterLink(text: 'text', url: 'https://flutter.dev'); 21 | 22 | print(data); 23 | } 24 | 25 | // static void shareWhatsApp() async { 26 | // var data = await SocialShare.shareWhatsapp("Hello World \n https://google.com"); 27 | // print(data); 28 | // } 29 | } 30 | -------------------------------------------------------------------------------- /lib/widget/node.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Node { 4 | Widget me; 5 | List children; 6 | 7 | Node({this.me, this.children}); 8 | } 9 | 10 | class NodeWidget extends StatefulWidget { 11 | final Node node; 12 | 13 | NodeWidget({Key key, this.node}) : super(key: key); 14 | 15 | @override 16 | _NodeWidgetState createState() => _NodeWidgetState(); 17 | } 18 | 19 | class _NodeWidgetState extends State { 20 | bool showList = false; 21 | Node node; 22 | @override 23 | Widget build(BuildContext context) { 24 | var me = InkWell( 25 | child: Row( 26 | children: [ 27 | Icon( 28 | showList ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, 29 | size: 20, 30 | ), 31 | widget.node.me 32 | ], 33 | ), 34 | onTap: () { 35 | setState(() { 36 | showList = !showList; 37 | }); 38 | }, 39 | ); 40 | return Column( 41 | crossAxisAlignment: CrossAxisAlignment.start, 42 | children: [ 43 | me, 44 | if (showList) 45 | Padding( 46 | padding: EdgeInsets.only(left: 20), 47 | child: Column( 48 | crossAxisAlignment: CrossAxisAlignment.start, 49 | children: widget.node.children.map((node) => node.me).toList(), 50 | ), 51 | ) 52 | ], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/widget/searchbar_delegate.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/2/19. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | 9 | class SearchBarDelegate extends SearchDelegate { 10 | ///显示搜索框右边的图标按钮 11 | @override 12 | List buildActions(BuildContext context) { 13 | return [ 14 | IconButton( 15 | icon: Icon(Icons.clear), 16 | onPressed: () { 17 | // 清除搜索内容 18 | query = ''; 19 | showSuggestions(context); 20 | }) 21 | ]; 22 | } 23 | 24 | ///显示为搜索框左侧的按钮 25 | @override 26 | Widget buildLeading(BuildContext context) { 27 | return IconButton( 28 | icon: Icon(Icons.arrow_back), 29 | onPressed: () { 30 | //关闭搜索页面 31 | close(context, null); 32 | }, 33 | ); 34 | } 35 | 36 | @override 37 | Widget buildResults(BuildContext context) { 38 | return Center( 39 | child: query.length == 0 40 | ? Text('搜索内容不能为空,当然也可以展示推荐的东西') 41 | : _searchResult()); 42 | } 43 | 44 | ///显示建议的搜索内容(搜索热词,搜索历史) , 点击直接展示相关搜索结果 45 | @override 46 | Widget buildSuggestions(BuildContext context) { 47 | return Padding( 48 | padding: const EdgeInsets.all(11.0), 49 | child: Wrap( 50 | runSpacing: 10, 51 | spacing: 20, 52 | children: searchRecommendationWidget(context), 53 | ), 54 | ); 55 | } 56 | 57 | ///搜索热词 58 | List searchRecommendationWidget(BuildContext context) { 59 | List list = ['斗破苍穹', '遮天', '斗罗大陆', '大主宰', '凡人修仙传', '盗墓笔记', '校花的贴身高手', '诛仙']; 60 | List searchRecommendation = []; 61 | list.forEach((item) => searchRecommendation.add(InkWell( 62 | onTap: () { 63 | query = item; 64 | showResults(context); 65 | }, 66 | child: Container( 67 | padding: EdgeInsets.all(5), 68 | color: Colors.green, 69 | child: Text( 70 | item, 71 | style: TextStyle(color: Colors.white), 72 | )), 73 | ))); 74 | return searchRecommendation; 75 | } 76 | 77 | ///搜索结果 78 | Widget _searchResult() { 79 | return ListView.builder( 80 | itemBuilder: (BuildContext context, int index) { 81 | return Text('你好,我是$query的搜索结果$index'); 82 | }, 83 | itemCount: 5, 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/widget/transform_animation_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TransformAnimationWidget extends AnimatedWidget { 4 | TransformAnimationWidget({Key key, Animation animation}) 5 | : super(key: key, listenable: animation); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | final Animation animation = listenable; 10 | return Transform.rotate( 11 | angle: animation.value / 10, 12 | child: Container( 13 | height: animation.value, 14 | width: animation.value, 15 | color: Colors.amber, 16 | child: Text('方块 '), 17 | ), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/widget/verification_code.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2019/2/1. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'dart:ui' as ui; 9 | import 'package:path_drawing/path_drawing.dart'; 10 | 11 | class DottedLineUnderlineInputBorder extends UnderlineInputBorder { 12 | final double textSize; //字体大小 13 | final spaceWidth; //虚线间隔 14 | final int textLength; //数字个数 15 | final borderSide; 16 | final letterSpacing; //字体间隔 17 | 18 | DottedLineUnderlineInputBorder( 19 | {this.textSize, 20 | this.borderSide, 21 | this.spaceWidth, 22 | this.textLength, 23 | this.letterSpacing}); 24 | 25 | @override 26 | void paint( 27 | Canvas canvas, 28 | Rect rect, { 29 | double gapStart, 30 | double gapExtent = 0.0, 31 | double gapPercentage = 0.0, 32 | TextDirection textDirection, 33 | }) { 34 | Path path = Path(); 35 | var textWidth = calcTrueTextSize(textSize); 36 | var startOffset = letterSpacing / 2; 37 | path.moveTo(rect.bottomLeft.dx + startOffset, rect.bottomLeft.dy); 38 | path.lineTo(rect.bottomLeft.dx + (textWidth + spaceWidth) * textLength, 39 | rect.bottomRight.dy); 40 | path = dashPath(path, 41 | dashArray: CircularIntervalList([ 42 | textWidth, 43 | spaceWidth, 44 | ])); 45 | canvas.drawPath(path, borderSide.toPaint()); 46 | } 47 | 48 | ///测量单个数字宽度 49 | double calcTrueTextSize(double textSize) { 50 | var paragraph = ui.ParagraphBuilder(ui.ParagraphStyle(fontSize: textSize)) 51 | ..addText("0"); 52 | var p = paragraph.build() 53 | ..layout(ui.ParagraphConstraints(width: double.infinity)); 54 | 55 | return p.minIntrinsicWidth; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_app 2 | description: A new Flutter application. 3 | 4 | environment: 5 | sdk: '>=2.10.0 <3.0.0' 6 | 7 | dependencies: 8 | flutter: 9 | sdk: flutter 10 | flutter_localizations: 11 | sdk: flutter 12 | english_words: ^3.1.0 13 | # The following adds the Cupertino Icons font to your application. 14 | # Use with the CupertinoIcons class for iOS style icons. 15 | dio: ^1.0.3 16 | flutter_swiper: ^1.1.6 17 | url_launcher: ^5.5.2 18 | flutter_screenutil: ^4.0.2+2 19 | scoped_model: ^0.3.0 20 | groovin_material_icons: ^1.1.5 21 | fluttertoast: ^3.0.3 22 | rxdart: ^0.19.0 23 | http: ^0.12.0 24 | nima: ^1.0.0 25 | path_drawing: ^0.4.0 26 | video_player: ^1.0.1 27 | chewie: ^0.12.0 28 | webview_flutter: ^0.3.3+1 29 | sqflite: ^1.1.3 30 | shared_preferences: ^0.5.3+4 31 | path_provider: ^2.0.2 32 | mapbox_search: ^2.0.1 33 | flutter_picker: ^1.1.5 34 | share: '>=0.6.5+1 <2.0.0' 35 | social_share_plugin: ^0.3.1 36 | flutter_appavailability: ^0.0.21 37 | address_picker: ^0.0.1 38 | image_gallery_saver: ^1.6.7 39 | permission_handler: ^5.0.1+1 40 | flutter_share_me: 41 | git: https://github.com/OpenFlutter/flutter_share_me 42 | 43 | 44 | dev_dependencies: 45 | flutter_test: 46 | sdk: flutter 47 | 48 | 49 | # For information on the generic Dart part of this file, see the 50 | # following page: https://www.dartlang.org/tools/pub/pubspec 51 | 52 | # The following section is specific to Flutter. 53 | flutter: 54 | # The following line ensures that the Material Icons font is 55 | # included with your application, so that you can use the icons in 56 | # the material Icons class. 57 | uses-material-design: true 58 | 59 | 60 | # To add assets to your application, add an assets section, like this: 61 | # assets: 62 | # - images/a_dot_burr.jpeg 63 | # - images/a_dot_ham.jpeg 64 | assets: 65 | - images/ 66 | 67 | - lib/locale/i18n_en.json 68 | - lib/locale/i18n_zh.json 69 | # An image asset can refer to one or more resolution-specific "variants", see 70 | # https://flutter.io/assets-and-images/#resolution-aware. 71 | 72 | # For details regarding adding assets from package dependencies, see 73 | # https://flutter.io/assets-and-images/#from-packages 74 | 75 | # To add custom fonts to your application, add a fonts section here, 76 | # in this "flutter" section. Each entry in this list should have a 77 | # "family" key with the font family name, and a "fonts" key with a 78 | # list giving the asset and other descriptors for the font. For 79 | # example: 80 | # fonts: 81 | # - family: Schyler 82 | # fonts: 83 | # - asset: fonts/Schyler-Regular.ttf 84 | # - asset: fonts/Schyler-Italic.ttf 85 | # style: italic 86 | # - family: Trajan Pro 87 | # fonts: 88 | # - asset: fonts/TrajanPro.ttf 89 | # - asset: fonts/TrajanPro_Bold.ttf 90 | # weight: 700 91 | # 92 | # For details regarding fonts from package dependencies, 93 | # see https://flutter.io/custom-fonts/#from-packages 94 | -------------------------------------------------------------------------------- /test/study.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Created by 李卓原 on 2018/11/1. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | */ 6 | 7 | void main() { 8 | String a = 'asdad'; 9 | String s = a.substring(a.length - 3); 10 | print(s); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter 3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to 4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties 5 | // are correct. 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_app/main.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(new MyApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | --------------------------------------------------------------------------------