├── .DS_Store ├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md └── flutter_learn ├── .gitignore ├── .metadata ├── .vscode └── settings.json ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── xuexiang │ │ │ │ └── flutterLearn │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── ic_splash_app_logo.png │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_splash_app_logo.png │ │ │ └── ic_splash_company_logo_xuexiang.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── repos.gradle └── settings.gradle ├── apk └── app-release.apk ├── art ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png ├── alipay.jpeg ├── demo.gif ├── download_github.png ├── download_pugongying.png └── wxpay.jpeg ├── assets ├── app.db ├── fonts │ └── iconfont.ttf ├── images │ ├── bg_update_top.png │ ├── flutter.png │ ├── food01.jpeg │ ├── food02.jpeg │ ├── food03.jpeg │ ├── food04.jpeg │ ├── food05.jpeg │ ├── food06.jpeg │ ├── normal_user_icon.png │ ├── scenery.jpg │ ├── timg.jpeg │ ├── xupdate_bg_app_top.png │ └── xupdate_ic_close.png └── json │ ├── app_version.json │ ├── picker1.json │ └── picker2.json ├── i10n-arb ├── intl_messages.arb └── intl_zh_CN.arb ├── intl.sh ├── ios ├── Flutter │ ├── .last_build_id │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter.podspec │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── 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 │ ├── Runner-Bridging-Header.h │ └── Runner.entitlements ├── jsonapi └── update_api.json ├── lib ├── home.dart ├── i10n │ ├── localization_intl.dart │ ├── messages_all.dart │ ├── messages_messages.dart │ └── messages_zh_CN.dart ├── init │ ├── app_init.dart │ ├── normal_app.dart │ └── splash.dart ├── main.dart ├── model │ └── sql │ │ ├── app_info.dart │ │ └── user_info.dart ├── page │ ├── expand │ │ ├── badge.dart │ │ ├── city_picker.dart │ │ ├── date_picker.dart │ │ ├── download.dart │ │ ├── iconfont.dart │ │ ├── image_picker.dart │ │ ├── multi_image_picker.dart │ │ ├── picker.dart │ │ ├── qrcode.dart │ │ ├── refresh │ │ │ ├── ballpulse_refresh.dart │ │ │ ├── basic_refresh.dart │ │ │ ├── material_refresh.dart │ │ │ └── user_profile.dart │ │ ├── spinkit.dart │ │ ├── swiper.dart │ │ └── web.dart │ ├── utils │ │ ├── app_badge.dart │ │ ├── battery.dart │ │ ├── bugly.dart │ │ ├── camera_complex.dart │ │ ├── camera_simple.dart │ │ ├── device_info.dart │ │ ├── event_bus.dart │ │ ├── jpush.dart │ │ ├── json_serialize.dart │ │ ├── local_notification.dart │ │ ├── navigator.dart │ │ ├── net.dart │ │ ├── package_info.dart │ │ ├── path.dart │ │ ├── permission_apply.dart │ │ ├── provider.dart │ │ ├── provider_next.dart │ │ ├── share.dart │ │ ├── shared_preferences.dart │ │ ├── sqlite.dart │ │ ├── toast.dart │ │ ├── url.dart │ │ └── video.dart │ └── widget │ │ ├── anim │ │ ├── basic_animation.dart │ │ ├── stagger_animation.dart │ │ └── transition_animations.dart │ │ ├── appbar.dart │ │ ├── bottom_navigation_bar.dart │ │ ├── button.dart │ │ ├── cardview.dart │ │ ├── contain │ │ ├── clip.dart │ │ ├── constrained_box.dart │ │ ├── container.dart │ │ ├── decorated_box.dart │ │ └── transform.dart │ │ ├── control.dart │ │ ├── custom │ │ ├── combination_widget.dart │ │ └── drawing_widget.dart │ │ ├── dialog.dart │ │ ├── drag.dart │ │ ├── drawer.dart │ │ ├── empty.dart │ │ ├── form.dart │ │ ├── future_builder.dart │ │ ├── gesture.dart │ │ ├── image │ │ ├── cached_network_image.dart │ │ ├── image.dart │ │ └── image_zoom.dart │ │ ├── input.dart │ │ ├── layout │ │ ├── layout_align.dart │ │ ├── layout_flex.dart │ │ ├── layout_linear.dart │ │ ├── layout_stack.dart │ │ └── layout_wrap.dart │ │ ├── notification.dart │ │ ├── progress.dart │ │ ├── scrollview │ │ ├── custom_scrollview.dart │ │ ├── nested_scrollview.dart │ │ └── scroll_controller.dart │ │ ├── tab.dart │ │ └── text.dart ├── router │ ├── route.dart │ ├── router.dart │ └── switch_animation.dart ├── utils │ ├── bugly.dart │ ├── camera.dart │ ├── click.dart │ ├── device.dart │ ├── dialog.dart │ ├── download.dart │ ├── event.dart │ ├── http.dart │ ├── notification.dart │ ├── oktoast.dart │ ├── path.dart │ ├── provider.dart │ ├── push.dart │ ├── random.dart │ ├── shared_preferences.dart │ ├── sql.dart │ ├── sql_helper.dart │ ├── toast.dart │ ├── umeng.dart │ ├── utils.dart │ ├── xuifont.dart │ └── xupdate.dart └── view │ ├── button.dart │ ├── gridview_page.dart │ ├── home │ ├── about.dart │ ├── home_drawer.dart │ ├── language.dart │ ├── login.dart │ ├── register.dart │ ├── sponsor.dart │ └── theme_color.dart │ ├── list │ ├── list_item.dart │ └── sample_list_item.dart │ ├── listview_page.dart │ ├── loading_dialog.dart │ ├── number_progress.dart │ ├── simple_list_page.dart │ ├── swiper_control.dart │ ├── titlebar.dart │ ├── update_dialog.dart │ └── web_view_page.dart ├── pubspec.yaml └── test └── widget_test.dart /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Dart", 9 | "program": "flutter_learn/lib/main.dart", 10 | "request": "launch", 11 | "type": "dart" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /flutter_learn/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | pubspec.lock 32 | .flutter-plugins-dependencies 33 | 34 | # Android related 35 | **/android/**/gradle-wrapper.jar 36 | **/android/.gradle 37 | **/android/captures/ 38 | **/android/gradlew 39 | **/android/gradlew.bat 40 | **/android/local.properties 41 | **/android/**/GeneratedPluginRegistrant.java 42 | **/android/keystores/ 43 | 44 | # iOS/XCode related 45 | **/ios/**/*.mode1v3 46 | **/ios/**/*.mode2v3 47 | **/ios/**/*.moved-aside 48 | **/ios/**/*.pbxuser 49 | **/ios/**/*.perspectivev3 50 | **/ios/**/*sync/ 51 | **/ios/**/.sconsign.dblite 52 | **/ios/**/.tags* 53 | **/ios/**/.vagrant/ 54 | **/ios/**/DerivedData/ 55 | **/ios/**/Icon? 56 | **/ios/**/Pods/ 57 | **/ios/**/.symlinks/ 58 | **/ios/**/profile 59 | **/ios/**/xcuserdata 60 | **/ios/.generated/ 61 | **/ios/Flutter/App.framework 62 | **/ios/Flutter/Flutter.framework 63 | **/ios/Flutter/Generated.xcconfig 64 | **/ios/Flutter/app.flx 65 | **/ios/Flutter/app.zip 66 | **/ios/Flutter/flutter_assets/ 67 | **/ios/Flutter/flutter_export_environment.sh 68 | **/ios/ServiceDefinitions.json 69 | **/ios/Runner/GeneratedPluginRegistrant.* 70 | 71 | # Exceptions to above rules. 72 | !**/ios/**/default.mode1v3 73 | !**/ios/**/default.mode2v3 74 | !**/ios/**/default.pbxuser 75 | !**/ios/**/default.perspectivev3 76 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 77 | -------------------------------------------------------------------------------- /flutter_learn/.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: 68587a0916366e9512a78df22c44163d041dd5f3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /flutter_learn/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic" 3 | } -------------------------------------------------------------------------------- /flutter_learn/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /flutter_learn/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.xuexiang.flutterLearn" 42 | minSdkVersion 21 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | 48 | manifestPlaceholders = [ 49 | JPUSH_PKGNAME : "com.xuexiang.flutterLearn", 50 | JPUSH_APPKEY : "0a6e78d9e1f9fe225cedf1e8", // NOTE: JPush 上注册的包名对应的 Appkey. 51 | JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可. 52 | ] 53 | } 54 | 55 | signingConfigs { 56 | release { 57 | storeFile file("../keystores/android.keystore") 58 | storePassword "xuexiang" 59 | keyAlias "android.keystore" 60 | keyPassword "xuexiang" 61 | } 62 | } 63 | 64 | buildTypes { 65 | release { 66 | // TODO: Add your own signing config for the release build. 67 | // Signing with the debug keys for now, so `flutter run --release` works. 68 | signingConfig signingConfigs.release 69 | } 70 | } 71 | 72 | lintOptions { 73 | checkReleaseBuilds false 74 | abortOnError false 75 | } 76 | } 77 | 78 | flutter { 79 | source '../..' 80 | } 81 | 82 | dependencies { 83 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 84 | testImplementation 'junit:junit:4.12' 85 | androidTestImplementation 'androidx.test:runner:1.1.1' 86 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 87 | } 88 | -------------------------------------------------------------------------------- /flutter_learn/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/kotlin/com/xuexiang/flutterLearn/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.xuexiang.flutterLearn 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/drawable/ic_splash_app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/drawable/ic_splash_app_logo.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_splash_app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_splash_app_logo.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_splash_company_logo_xuexiang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-hdpi/ic_splash_company_logo_xuexiang.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_learn/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /flutter_learn/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_learn/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | apply from: './repos.gradle' 3 | ext.kotlin_version = '1.3.72' 4 | addRepos(repositories) 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:3.5.0' 7 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 8 | } 9 | } 10 | 11 | allprojects { 12 | addRepos(repositories) 13 | } 14 | 15 | rootProject.buildDir = '../build' 16 | subprojects { 17 | project.buildDir = "${rootProject.buildDir}/${project.name}" 18 | } 19 | subprojects { 20 | project.evaluationDependsOn(':app') 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /flutter_learn/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true -------------------------------------------------------------------------------- /flutter_learn/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /flutter_learn/android/repos.gradle: -------------------------------------------------------------------------------- 1 | //默认添加代码仓库路径 2 | static def addRepos(RepositoryHandler handler) { 3 | handler.mavenLocal() 4 | handler.google { url 'https://maven.aliyun.com/repository/google' } 5 | handler.jcenter { url 'https://maven.aliyun.com/repository/jcenter' } 6 | handler.mavenCentral { url 'https://maven.aliyun.com/repository/central' } 7 | handler.maven { url "https://jitpack.io" } 8 | handler.maven { url 'https://maven.aliyun.com/repository/public' } 9 | handler.maven { url 'https://oss.sonatype.org/content/repositories/public' } 10 | } 11 | 12 | ext.addRepos = this.&addRepos 13 | 14 | 15 | -------------------------------------------------------------------------------- /flutter_learn/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_learn/apk/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/apk/app-release.apk -------------------------------------------------------------------------------- /flutter_learn/art/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/1.png -------------------------------------------------------------------------------- /flutter_learn/art/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/2.png -------------------------------------------------------------------------------- /flutter_learn/art/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/3.png -------------------------------------------------------------------------------- /flutter_learn/art/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/4.png -------------------------------------------------------------------------------- /flutter_learn/art/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/5.png -------------------------------------------------------------------------------- /flutter_learn/art/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/6.png -------------------------------------------------------------------------------- /flutter_learn/art/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/7.png -------------------------------------------------------------------------------- /flutter_learn/art/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/8.png -------------------------------------------------------------------------------- /flutter_learn/art/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/9.png -------------------------------------------------------------------------------- /flutter_learn/art/alipay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/alipay.jpeg -------------------------------------------------------------------------------- /flutter_learn/art/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/demo.gif -------------------------------------------------------------------------------- /flutter_learn/art/download_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/download_github.png -------------------------------------------------------------------------------- /flutter_learn/art/download_pugongying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/download_pugongying.png -------------------------------------------------------------------------------- /flutter_learn/art/wxpay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/art/wxpay.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/app.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/app.db -------------------------------------------------------------------------------- /flutter_learn/assets/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/fonts/iconfont.ttf -------------------------------------------------------------------------------- /flutter_learn/assets/images/bg_update_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/bg_update_top.png -------------------------------------------------------------------------------- /flutter_learn/assets/images/flutter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/flutter.png -------------------------------------------------------------------------------- /flutter_learn/assets/images/food01.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food01.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/food02.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food02.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/food03.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food03.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/food04.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food04.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/food05.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food05.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/food06.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/food06.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/normal_user_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/normal_user_icon.png -------------------------------------------------------------------------------- /flutter_learn/assets/images/scenery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/scenery.jpg -------------------------------------------------------------------------------- /flutter_learn/assets/images/timg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/timg.jpeg -------------------------------------------------------------------------------- /flutter_learn/assets/images/xupdate_bg_app_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/xupdate_bg_app_top.png -------------------------------------------------------------------------------- /flutter_learn/assets/images/xupdate_ic_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/assets/images/xupdate_ic_close.png -------------------------------------------------------------------------------- /flutter_learn/assets/json/app_version.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "msg": "", 4 | "updateStatus": 1, 5 | "versionCode": 3, 6 | "versionName": "1.0.2", 7 | "uploadTime": "2018-07-10 17:28:41", 8 | "modifyContent": "\r\n1、优化api接口。\r\n2、添加使用demo演示。\r\n3、新增自定义更新服务api接口。\r\n4、优化更新提示界面。", 9 | "downloadUrl": "https://raw.githubusercontent.com/xuexiangjys/xupdate/master/apk/xupdate_demo_1.0.2.apk", 10 | "apkSize": 2048, 11 | "apkMd5": "e4b79a36efb9f17df7e3bb161f9bcfd8" 12 | } -------------------------------------------------------------------------------- /flutter_learn/assets/json/picker2.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "一年级", 4 | "二年级", 5 | "三年级", 6 | "四年级", 7 | "五年级", 8 | "六年级", 9 | "初一", 10 | "初二", 11 | "初三", 12 | "高一", 13 | "高二", 14 | "高三" 15 | ], 16 | [ 17 | "1班", 18 | "2班", 19 | "3班", 20 | "4班", 21 | "5班", 22 | "6班", 23 | "7班", 24 | "8班", 25 | "9班", 26 | "10班", 27 | "11班", 28 | "12班", 29 | "13班", 30 | "14班", 31 | "15班", 32 | "16班", 33 | "17班", 34 | "18班", 35 | "19班", 36 | "20班" 37 | ] 38 | ] -------------------------------------------------------------------------------- /flutter_learn/intl.sh: -------------------------------------------------------------------------------- 1 | flutter pub pub run intl_translation:extract_to_arb --output-dir=i10n-arb lib/i10n/localization_intl.dart 2 | flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i10n --no-use-deferred-loading lib/i10n/localization_intl.dart i10n-arb/intl_*.arb -------------------------------------------------------------------------------- /flutter_learn/ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | c9b26dc9f2cebfc4bd8303cc71bdc6c9 -------------------------------------------------------------------------------- /flutter_learn/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_learn/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_learn/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 | -------------------------------------------------------------------------------- /flutter_learn/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_learn/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import flutter_downloader 4 | 5 | @UIApplicationMain 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | GeneratedPluginRegistrant.register(with: self) 12 | FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins) 13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 14 | } 15 | } 16 | 17 | private func registerPlugins(registry: FlutterPluginRegistry) { 18 | if (!registry.hasPlugin("FlutterDownloaderPlugin")) { 19 | FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flutter_learn/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 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /flutter_learn/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 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/FlutterSample/92b375f49437b4428e9fe145616b945bc7e8abd0/flutter_learn/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /flutter_learn/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. -------------------------------------------------------------------------------- /flutter_learn/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 | -------------------------------------------------------------------------------- /flutter_learn/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 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | flutter学习 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | UIBackgroundModes 47 | 48 | fetch 49 | remote-notification 50 | 51 | NSPhotoLibraryUsageDescription 52 | 应用需要访问您的照片 53 | NSCameraUsageDescription 54 | 应用需要访问您的相机 55 | NSMicrophoneUsageDescription 56 | 应用需要访问您的麦克风 57 | NSAppTransportSecurity 58 | 59 | NSAllowsArbitraryLoads 60 | 61 | 62 | FDMaximumConcurrentTasks 63 | 5 64 | FDAllFilesDownloadedMessage 65 | All files have been downloaded 66 | 67 | 68 | -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /flutter_learn/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_learn/jsonapi/update_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "Code": 0, 3 | "Msg": "", 4 | "UpdateStatus": 1, 5 | "VersionCode": 3, 6 | "VersionName": "1.0.2", 7 | "UploadTime": "2020-02-20 08:00:00", 8 | "ModifyContent": "\r\n1、增加了账号系统。\r\n2、增加了语言和皮肤主题的切换功能。\r\n3、还有更多新增的案例待你去发现。", 9 | "DownloadUrl": "https://raw.githubusercontent.com/xuexiangjys/FlutterSample/master/flutter_learn/apk/app-release.apk", 10 | "ApkSize": 23338, 11 | "ApkMd5": "29385F984CC427632514ADA4435928EC" 12 | } -------------------------------------------------------------------------------- /flutter_learn/lib/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/i10n/localization_intl.dart'; 3 | import 'package:flutter_learn/router/route.dart'; 4 | import 'package:flutter_learn/utils/click.dart'; 5 | import 'package:flutter_learn/utils/xupdate.dart'; 6 | import 'package:flutter_learn/view/gridview_page.dart'; 7 | import 'package:flutter_learn/view/home/home_drawer.dart'; 8 | 9 | class MainHomePage extends StatefulWidget { 10 | MainHomePage({Key key}) : super(key: key); 11 | @override 12 | _MainHomePageState createState() => _MainHomePageState(); 13 | } 14 | 15 | class _MainHomePageState extends State 16 | with SingleTickerProviderStateMixin { 17 | List getTabs(BuildContext context) => [ 18 | Tab(text: Languages.of(context).widget), 19 | Tab(text: Languages.of(context).utils), 20 | Tab(text: Languages.of(context).expand) 21 | ]; 22 | 23 | List getTabViews(BuildContext context) => [ 24 | GridViewPage(items: RouteMap.getWidgetItems(context)), 25 | GridViewPage(items: RouteMap.getUtilsItems(context)), 26 | GridViewPage(items: RouteMap.getExpandItems(context)), 27 | ]; 28 | 29 | TabController _tabController; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | _tabController = TabController(vsync: this, length: 3); 35 | 36 | XUpdate.initAndCheck(); 37 | } 38 | 39 | @override 40 | void dispose() { 41 | _tabController.dispose(); 42 | super.dispose(); 43 | } 44 | 45 | final GlobalKey _scaffoldKey = GlobalKey(); 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return WillPopScope( 50 | child: Scaffold( 51 | key: _scaffoldKey, 52 | appBar: AppBar( 53 | title: Text(Languages.of(context).title), 54 | bottom: TabBar( 55 | controller: _tabController, 56 | tabs: getTabs(context), 57 | ), 58 | ), 59 | drawer: HomeDrawer(), 60 | body: TabBarView( 61 | controller: _tabController, 62 | children: getTabViews(context).map((Widget widget) { 63 | return widget; 64 | }).toList(), 65 | ), 66 | ), 67 | //监听导航栏返回,类似onKeyEvent 68 | onWillPop: () => 69 | ClickUtils.exitBy2Click(status: _scaffoldKey.currentState)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /flutter_learn/lib/i10n/messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | // Ignore issues from commonly used lints in this file. 6 | // ignore_for_file:implementation_imports, file_names, unnecessary_new 7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering 8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment 9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases 10 | // ignore_for_file:comment_references 11 | 12 | import 'dart:async'; 13 | 14 | import 'package:intl/intl.dart'; 15 | import 'package:intl/message_lookup_by_library.dart'; 16 | import 'package:intl/src/intl_helpers.dart'; 17 | 18 | import 'messages_messages.dart' as messages_messages; 19 | import 'messages_zh_CN.dart' as messages_zh_cn; 20 | 21 | typedef Future LibraryLoader(); 22 | Map _deferredLibraries = { 23 | 'messages': () => new Future.value(null), 24 | 'zh_CN': () => new Future.value(null), 25 | }; 26 | 27 | MessageLookupByLibrary _findExact(String localeName) { 28 | switch (localeName) { 29 | case 'messages': 30 | return messages_messages.messages; 31 | case 'zh_CN': 32 | return messages_zh_cn.messages; 33 | default: 34 | return null; 35 | } 36 | } 37 | 38 | /// User programs should call this before using [localeName] for messages. 39 | Future initializeMessages(String localeName) async { 40 | var availableLocale = Intl.verifiedLocale( 41 | localeName, 42 | (locale) => _deferredLibraries[locale] != null, 43 | onFailure: (_) => null); 44 | if (availableLocale == null) { 45 | return new Future.value(false); 46 | } 47 | var lib = _deferredLibraries[availableLocale]; 48 | await (lib == null ? new Future.value(false) : lib()); 49 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 50 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 51 | return new Future.value(true); 52 | } 53 | 54 | bool _messagesExistFor(String locale) { 55 | try { 56 | return _findExact(locale) != null; 57 | } catch (e) { 58 | return false; 59 | } 60 | } 61 | 62 | MessageLookupByLibrary _findGeneratedMessagesFor(String locale) { 63 | var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, 64 | onFailure: (_) => null); 65 | if (actualLocale == null) return null; 66 | return _findExact(actualLocale); 67 | } 68 | -------------------------------------------------------------------------------- /flutter_learn/lib/init/app_init.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_learn/init/normal_app.dart'; 5 | 6 | //应用初始化 7 | class AppInit { 8 | 9 | static void run() { 10 | catchException(() => NormalApp.run()); 11 | // //Bugly的异常捕获上传 12 | // Bugly.postCatchedException(() => NormalApp.run()); 13 | } 14 | 15 | ///异常捕获处理 16 | static void catchException(T callback()) { 17 | //捕获异常的回调 18 | FlutterError.onError = (FlutterErrorDetails details) { 19 | reportErrorAndLog(details); 20 | }; 21 | runZoned>( 22 | () async { 23 | callback(); 24 | }, 25 | zoneSpecification: ZoneSpecification( 26 | print: (Zone self, ZoneDelegate parent, Zone zone, String line) { 27 | collectLog(parent, zone, line); // 收集日志 28 | }, 29 | ), 30 | //未捕获的异常的回调 31 | onError: (Object obj, StackTrace stack) { 32 | var details = makeDetails(obj, stack); 33 | reportErrorAndLog(details); 34 | }, 35 | ); 36 | } 37 | 38 | //日志拦截, 收集日志 39 | static void collectLog(ZoneDelegate parent, Zone zone, String line) { 40 | parent.print(zone, "日志拦截: $line"); 41 | } 42 | 43 | //上报错误和日志逻辑 44 | static void reportErrorAndLog(FlutterErrorDetails details) { 45 | print(details); 46 | } 47 | 48 | // 构建错误信息 49 | static FlutterErrorDetails makeDetails(Object obj, StackTrace stack) { 50 | return FlutterErrorDetails(stack: stack); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flutter_learn/lib/init/splash.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/shared_preferences.dart'; 3 | 4 | //类似广告启动页 5 | class SplashPage extends StatefulWidget { 6 | @override 7 | _SplashPageState createState() => _SplashPageState(); 8 | } 9 | 10 | class _SplashPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | countDown(); 15 | } 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Container( 20 | decoration: BoxDecoration( 21 | color: Colors.white, 22 | ), 23 | child: Center( 24 | child: Image( 25 | image: AssetImage('assets/images/flutter.png'), 26 | height: 96, 27 | width: 96, 28 | ))); 29 | } 30 | 31 | //倒计时 32 | void countDown() { 33 | var _duration = Duration(seconds: 2); 34 | new Future.delayed(_duration, goHomePage); 35 | } 36 | 37 | //页面跳转 38 | void goHomePage() { 39 | String nickName = SPUtils.getNickName(); 40 | if (nickName != null && nickName.isNotEmpty) { 41 | Navigator.of(context).pushReplacementNamed('/home'); 42 | } else { 43 | Navigator.of(context).pushReplacementNamed('/login'); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /flutter_learn/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_learn/init/app_init.dart'; 2 | 3 | //程序的主入口 4 | void main() => AppInit.run(); 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /flutter_learn/lib/model/sql/app_info.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | //使用Dart Data Class Generator插件进行创建 4 | //使用命令: Generate from JSON 5 | class AppInfo { 6 | final int code; 7 | final String msg; 8 | final int updateStatus; 9 | final int versionCode; 10 | final String versionName; 11 | final String uploadTime; 12 | final String modifyContent; 13 | final String downloadUrl; 14 | final int apkSize; 15 | final String apkMd5; 16 | AppInfo({ 17 | this.code, 18 | this.msg, 19 | this.updateStatus, 20 | this.versionCode, 21 | this.versionName, 22 | this.uploadTime, 23 | this.modifyContent, 24 | this.downloadUrl, 25 | this.apkSize, 26 | this.apkMd5, 27 | }); 28 | 29 | Map toMap() { 30 | return { 31 | 'code': code, 32 | 'msg': msg, 33 | 'updateStatus': updateStatus, 34 | 'versionCode': versionCode, 35 | 'versionName': versionName, 36 | 'uploadTime': uploadTime, 37 | 'modifyContent': modifyContent, 38 | 'downloadUrl': downloadUrl, 39 | 'apkSize': apkSize, 40 | 'apkMd5': apkMd5, 41 | }; 42 | } 43 | 44 | static AppInfo fromMap(Map map) { 45 | if (map == null) return null; 46 | 47 | return AppInfo( 48 | code: map['code']?.toInt(), 49 | msg: map['msg'], 50 | updateStatus: map['updateStatus']?.toInt(), 51 | versionCode: map['versionCode']?.toInt(), 52 | versionName: map['versionName'], 53 | uploadTime: map['uploadTime'], 54 | modifyContent: map['modifyContent'], 55 | downloadUrl: map['downloadUrl'], 56 | apkSize: map['apkSize']?.toInt(), 57 | apkMd5: map['apkMd5'], 58 | ); 59 | } 60 | 61 | String toJson() => json.encode(toMap()); 62 | 63 | static AppInfo fromJson(String source) => fromMap(json.decode(source)); 64 | 65 | @override 66 | String toString() { 67 | return 'AppInfo code: $code, msg: $msg, updateStatus: $updateStatus, versionCode: $versionCode, versionName: $versionName, uploadTime: $uploadTime, modifyContent: $modifyContent, downloadUrl: $downloadUrl, apkSize: $apkSize, apkMd5: $apkMd5'; 68 | } 69 | } -------------------------------------------------------------------------------- /flutter_learn/lib/model/sql/user_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_learn/utils/sql.dart'; 2 | 3 | abstract class UserInfoInterface { 4 | int get id; 5 | String get userName; 6 | String get password; 7 | String get nickName; 8 | int get age; 9 | int get sex; 10 | } 11 | 12 | class UserInfo implements UserInfoInterface { 13 | int id; 14 | String userName; 15 | String password; 16 | String nickName; 17 | int age; 18 | int sex; 19 | 20 | UserInfo( 21 | {this.id, 22 | this.userName, 23 | this.password, 24 | this.nickName, 25 | this.age, 26 | this.sex}); 27 | 28 | factory UserInfo.fromJSON(Map json) { 29 | return UserInfo( 30 | id: json['id'], 31 | userName: json['userName'], 32 | password: json['password'], 33 | nickName: json['nickName'], 34 | age: json['age'], 35 | sex: json['sex']); 36 | } 37 | 38 | Map toJSON() { 39 | return { 40 | 'id': id, 41 | 'userName': userName, 42 | 'password': password, 43 | 'nickName': nickName, 44 | 'age': age, 45 | 'sex': sex 46 | }; 47 | } 48 | } 49 | 50 | class UserInfoModel { 51 | final String table = 'userInfo'; 52 | Sql sql; 53 | 54 | UserInfoModel() { 55 | sql = Sql.setTable(table); 56 | } 57 | 58 | // 插入 59 | Future> insert(UserInfo userInfo) { 60 | return sql.insert(userInfo.toJSON()); 61 | } 62 | 63 | // 查询 64 | Future> getAllInfo() async { 65 | List list = await sql.getByCondition(); 66 | List resultList = []; 67 | list.forEach((item) { 68 | print(item); 69 | resultList.add(UserInfo.fromJSON(item)); 70 | }); 71 | return resultList; 72 | } 73 | 74 | // 修改 75 | Future update(UserInfo userInfo) { 76 | return sql.updateById(userInfo.toJSON(), userInfo.id); 77 | } 78 | 79 | // 删除所有 80 | Future deleteAll() async { 81 | return await sql.deleteAll(); 82 | } 83 | 84 | // 删除所有 85 | Future deleteById(int id) async { 86 | return await sql.deleteById(id); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/city_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:city_pickers/city_pickers.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CityPickerPage extends StatefulWidget { 5 | final String title; 6 | CityPickerPage(this.title, {Key key}) : super(key: key); 7 | @override 8 | _CityPickerPageState createState() => _CityPickerPageState(); 9 | } 10 | 11 | class _CityPickerPageState extends State { 12 | String _data1 = "省市区三级选择"; 13 | String _data2 = "省市区三级选择(全屏)"; 14 | String _data3 = "城市选择"; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar(title: Text(widget.title)), 20 | body: SingleChildScrollView( 21 | padding: const EdgeInsets.all(10), 22 | child: Column(children: [ 23 | ButtonBar( 24 | alignment: 25 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 26 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 27 | children: [ 28 | RaisedButton( 29 | child: Text(_data1), 30 | onPressed: () => showPicker1(context), 31 | ), 32 | RaisedButton( 33 | child: Text(_data2), 34 | onPressed: () => showPicker2(context), 35 | ), 36 | RaisedButton( 37 | child: Text(_data3), 38 | onPressed: () => showPicker3(context), 39 | ), 40 | ], 41 | ), 42 | ]))); 43 | } 44 | 45 | void showPicker1(BuildContext context) { 46 | ///设置默认: 江苏-南京市-江宁区 47 | CityPickers.showCityPicker( 48 | context: context, height: 220, locationCode: '320115') 49 | .then((value) => setState(() { 50 | _data1 = 51 | "${value.provinceName}-${value.cityName}-${value.areaName}"; 52 | })); 53 | } 54 | 55 | void showPicker2(BuildContext context) { 56 | ///设置默认: 江苏-南京市-江宁区 57 | CityPickers.showFullPageCityPicker(context: context, locationCode: '320115') 58 | .then((value) => setState(() { 59 | _data2 = 60 | "${value.provinceName}-${value.cityName}-${value.areaName}"; 61 | })); 62 | } 63 | 64 | void showPicker3(BuildContext context) { 65 | CityPickers.showCitiesSelector( 66 | context: context, 67 | hotCities: [ 68 | HotCity(id: 0, name: '北京'), 69 | HotCity(id: 1, name: '上海'), 70 | HotCity(id: 2, name: '广州'), 71 | HotCity(id: 3, name: '南京'), 72 | HotCity(id: 4, name: '杭州'), 73 | ], 74 | cityItemStyle: BaseStyle(fontSize: 15), 75 | sideBarStyle: BaseStyle(backgroundActiveColor: Colors.transparent)) 76 | .then((value) => setState(() { 77 | _data3 = "${value.cityName}"; 78 | })); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/iconfont.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/xuifont.dart'; 3 | 4 | class IconFontPage extends StatefulWidget { 5 | IconFontPage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _IconFontPageState createState() => _IconFontPageState(); 9 | } 10 | 11 | class _IconFontPageState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar( 16 | title: Text(widget.title), 17 | ), 18 | body: Container( 19 | padding: const EdgeInsets.all(10), 20 | child: GridView.builder( 21 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 22 | crossAxisCount: 3, 23 | crossAxisSpacing: 5, 24 | mainAxisSpacing: 5, 25 | childAspectRatio: 1), 26 | itemCount: XUIIcons.icons.length, 27 | itemBuilder: (BuildContext context, int index) { 28 | return Icon(XUIIcons.icons[index], color: Theme.of(context).primaryColor); 29 | }, 30 | ))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/image_picker.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:image_picker/image_picker.dart'; 5 | 6 | class ImagePickerPage extends StatefulWidget { 7 | ImagePickerPage(this.title, {Key key}) : super(key: key); 8 | final String title; 9 | @override 10 | _ImagePickerPageState createState() => _ImagePickerPageState(); 11 | } 12 | 13 | class _ImagePickerPageState extends State { 14 | File _image; 15 | 16 | //选择照片 17 | Future getImage() async { 18 | var image = await ImagePicker.pickImage(source: ImageSource.gallery); 19 | 20 | setState(() { 21 | _image = image; 22 | }); 23 | } 24 | 25 | //拍照片 26 | Future takeImage() async { 27 | var image = await ImagePicker.pickImage(source: ImageSource.camera); 28 | 29 | setState(() { 30 | _image = image; 31 | }); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Scaffold( 37 | appBar: AppBar( 38 | title: Text(widget.title), 39 | ), 40 | body: Container( 41 | padding: const EdgeInsets.all(10), 42 | child: ListView( 43 | scrollDirection: Axis.vertical, // 水平listView 44 | children: [ 45 | ButtonBar( 46 | alignment: MainAxisAlignment.start, 47 | mainAxisSize: MainAxisSize.min, 48 | children: [ 49 | RaisedButton( 50 | child: Text('选择图片'), 51 | onPressed: getImage, 52 | ), 53 | RaisedButton( 54 | child: Text('拍照片'), 55 | onPressed: takeImage, 56 | ), 57 | ], 58 | ), 59 | _image == null 60 | ? Text('您还未选择任何图片.') 61 | : Image.file( 62 | _image, 63 | scale: 0.5, 64 | fit: BoxFit.cover, 65 | ) 66 | ], 67 | ))); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/multi_image_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:multi_image_picker/multi_image_picker.dart'; 3 | 4 | class MultiImagePickerPage extends StatefulWidget { 5 | MultiImagePickerPage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _MultiImagePickerPageState createState() => _MultiImagePickerPageState(); 9 | } 10 | 11 | class _MultiImagePickerPageState extends State { 12 | List images = List(); 13 | String _error = ''; 14 | 15 | Future loadAssets(BuildContext context) async { 16 | List resultList = List(); 17 | String error = ''; 18 | 19 | try { 20 | resultList = await MultiImagePicker.pickImages( 21 | maxImages: 9, 22 | enableCamera: true, 23 | selectedAssets: images, 24 | cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"), 25 | materialOptions: MaterialOptions( 26 | actionBarColor: "#2196F3", 27 | statusBarColor: "#2196F3", 28 | actionBarTitle: "图片选择", 29 | allViewTitle: "所有图片", 30 | useDetailsView: false, 31 | autoCloseOnSelectionLimit: false, 32 | selectCircleStrokeColor: "#000000", 33 | ), 34 | ); 35 | } on Exception catch (e) { 36 | error = e.toString(); 37 | } 38 | if (!mounted) return; 39 | 40 | setState(() { 41 | images = resultList; 42 | _error = error; 43 | }); 44 | } 45 | 46 | Widget buildGridView() { 47 | return GridView.count( 48 | crossAxisCount: 3, 49 | crossAxisSpacing: 10, 50 | mainAxisSpacing: 10, 51 | children: List.generate(images.length, (index) { 52 | Asset asset = images[index]; 53 | return AssetThumb( 54 | asset: asset, 55 | width: 300, 56 | height: 300, 57 | ); 58 | }), 59 | ); 60 | } 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Scaffold( 65 | appBar: AppBar( 66 | title: Text(widget.title), 67 | ), 68 | body: Container( 69 | padding: EdgeInsets.all(10), 70 | child: Column( 71 | children: [ 72 | RaisedButton( 73 | child: Text("选择图片"), 74 | textColor: Colors.white, 75 | onPressed: () { 76 | loadAssets(context); 77 | }), 78 | Center(child: Text('错误: $_error')), 79 | Expanded( 80 | child: buildGridView(), 81 | ) 82 | ], 83 | ))); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/refresh/ballpulse_refresh.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_easyrefresh/ball_pulse_footer.dart'; 5 | import 'package:flutter_easyrefresh/ball_pulse_header.dart'; 6 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 7 | import 'package:flutter_learn/view/list/sample_list_item.dart'; 8 | 9 | /// 球脉冲样式 10 | class BallPulseRefreshPage extends StatefulWidget { 11 | /// 标题 12 | final String title; 13 | const BallPulseRefreshPage(this.title, {Key key}) : super(key: key); 14 | 15 | @override 16 | _BallPulseRefreshPageState createState() { 17 | return _BallPulseRefreshPageState(); 18 | } 19 | } 20 | 21 | class _BallPulseRefreshPageState extends State { 22 | // 总数 23 | int _count = 10; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text(widget.title), 30 | ), 31 | body: EasyRefresh.custom( 32 | header: BallPulseHeader(), 33 | footer: BallPulseFooter(), 34 | onRefresh: () async { 35 | await Future.delayed(Duration(seconds: 1), () { 36 | setState(() { 37 | _count = 10; 38 | }); 39 | }); 40 | }, 41 | onLoad: () async { 42 | await Future.delayed(Duration(seconds: 1), () { 43 | setState(() { 44 | _count += 10; 45 | }); 46 | }); 47 | }, 48 | slivers: [ 49 | SliverList( 50 | delegate: SliverChildBuilderDelegate( 51 | (context, index) { 52 | return SampleListItem(); 53 | }, 54 | childCount: _count, 55 | ), 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/refresh/material_refresh.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 5 | import 'package:flutter_easyrefresh/material_header.dart'; 6 | import 'package:flutter_easyrefresh/material_footer.dart'; 7 | import 'package:flutter_learn/view/list/sample_list_item.dart'; 8 | 9 | /// Material Design样式 10 | class MaterialRefreshPage extends StatefulWidget { 11 | /// 标题 12 | final String title; 13 | const MaterialRefreshPage(this.title, {Key key}) : super(key: key); 14 | 15 | @override 16 | _MaterialPageState createState() { 17 | return _MaterialPageState(); 18 | } 19 | } 20 | 21 | class _MaterialPageState extends State { 22 | // 总数 23 | int _count = 10; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text(widget.title), 30 | ), 31 | body: EasyRefresh.custom( 32 | header: MaterialHeader(), 33 | footer: MaterialFooter(), 34 | onRefresh: () async { 35 | await Future.delayed(Duration(seconds: 1), () { 36 | setState(() { 37 | _count = 10; 38 | }); 39 | }); 40 | }, 41 | onLoad: () async { 42 | await Future.delayed(Duration(seconds: 1), () { 43 | setState(() { 44 | _count += 10; 45 | }); 46 | }); 47 | }, 48 | slivers: [ 49 | SliverList( 50 | delegate: SliverChildBuilderDelegate( 51 | (context, index) { 52 | return SampleListItem(); 53 | }, 54 | childCount: _count, 55 | ), 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/expand/web.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/view/web_view_page.dart'; 3 | 4 | class WebPage extends StatefulWidget { 5 | WebPage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _WebPageState createState() => _WebPageState(); 9 | } 10 | 11 | class _WebPageState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar( 16 | title: Text(widget.title), 17 | ), 18 | body: Container( 19 | padding: const EdgeInsets.all(10), 20 | child: ListView( 21 | scrollDirection: Axis.vertical, // 水平listView 22 | children: [ 23 | ButtonBar( 24 | alignment: 25 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 26 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 27 | children: [ 28 | RaisedButton( 29 | child: Text('访问百度'), 30 | onPressed: () => {gotoBaidu(context)}, 31 | ), 32 | RaisedButton( 33 | child: Text('访问我的Github'), 34 | onPressed: () => {gotoGithub(context)}, 35 | ), 36 | RaisedButton( 37 | child: Text('访问我的博客'), 38 | onPressed: () => {gotoBlog(context)}, 39 | ), 40 | ], 41 | ), 42 | ], 43 | ))); 44 | } 45 | 46 | void gotoBaidu(BuildContext context) { 47 | Navigator.push(context, MaterialPageRoute(builder: (context) { 48 | return WebViewPage("https://www.baidu.com/", "百度"); 49 | })); 50 | } 51 | 52 | void gotoGithub(BuildContext context) { 53 | Navigator.push(context, MaterialPageRoute(builder: (context) { 54 | return WebViewPage("https://github.com/xuexiangjys", "Github"); 55 | })); 56 | } 57 | 58 | void gotoBlog(BuildContext context) { 59 | Navigator.push(context, MaterialPageRoute(builder: (context) { 60 | return WebViewPage("https://juejin.im/user/598feef55188257d592e56ed", "博客"); 61 | })); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/app_badge.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_badger/flutter_app_badger.dart'; 3 | import 'package:flutter_learn/utils/shared_preferences.dart'; 4 | 5 | class AppBadgePage extends StatefulWidget { 6 | final String title; 7 | AppBadgePage(this.title, {Key key}) : super(key: key); 8 | @override 9 | _AppBadgePageState createState() => _AppBadgePageState(); 10 | } 11 | 12 | class _AppBadgePageState extends State { 13 | int _count = 0; 14 | bool _isSupport = false; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | _count = SPUtils.getAppBadgeNumber(); 20 | FlutterAppBadger.isAppBadgeSupported().then((value) => { 21 | setState(() { 22 | _isSupport = value; 23 | }) 24 | }); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Scaffold( 30 | appBar: AppBar(title: Text(widget.title)), 31 | body: SingleChildScrollView( 32 | padding: const EdgeInsets.all(10), 33 | child: Column(children: [ 34 | Text('当前应用消息徽章数量: $_count, 是否支持: $_isSupport'), 35 | Padding( 36 | padding: const EdgeInsets.only(top: 15), 37 | child: Row( 38 | children: [ 39 | FlatButton.icon( 40 | icon: Icon(Icons.add), 41 | label: Text('增加'), 42 | onPressed: _isSupport 43 | ? () { 44 | setState(() { 45 | _count += 1; 46 | }); 47 | FlutterAppBadger.updateBadgeCount(_count); 48 | SPUtils.saveAppBadgeNumber(_count); 49 | } 50 | : null, 51 | ), 52 | FlatButton.icon( 53 | icon: Icon(Icons.remove), 54 | label: Text('减少'), 55 | onPressed: _isSupport 56 | ? () { 57 | if (_count > 0) { 58 | setState(() { 59 | _count -= 1; 60 | }); 61 | FlutterAppBadger.updateBadgeCount(_count); 62 | SPUtils.saveAppBadgeNumber(_count); 63 | } 64 | } 65 | : null, 66 | ), 67 | FlatButton.icon( 68 | icon: Icon(Icons.clear), 69 | label: Text('清除'), 70 | onPressed: _isSupport 71 | ? () { 72 | setState(() { 73 | _count = 0; 74 | }); 75 | FlutterAppBadger.removeBadge(); 76 | SPUtils.saveAppBadgeNumber(0); 77 | } 78 | : null, 79 | ) 80 | ], 81 | )) 82 | ]))); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/battery.dart: -------------------------------------------------------------------------------- 1 | import 'package:battery/battery.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_learn/utils/utils.dart'; 4 | 5 | class BatteryPage extends StatefulWidget { 6 | final String title; 7 | BatteryPage(this.title, {Key key}) : super(key: key); 8 | @override 9 | _BatteryPageState createState() => _BatteryPageState(); 10 | } 11 | 12 | class _BatteryPageState extends State { 13 | int _battery = 0; 14 | String _batteryStatus; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | Utils.getBattery().then((value) { 20 | setState(() { 21 | _battery = value; 22 | }); 23 | }); 24 | Utils.registerBatteryChanged((status) { 25 | switch (status) { 26 | case BatteryState.full: 27 | _batteryStatus = "充满"; 28 | break; 29 | case BatteryState.charging: 30 | _batteryStatus = "充电中..."; 31 | break; 32 | case BatteryState.discharging: 33 | _batteryStatus = "充电断开"; 34 | break; 35 | default: 36 | } 37 | setState(() {}); 38 | }); 39 | } 40 | 41 | @override 42 | void dispose() { 43 | Utils.unregisterBatteryChanged(); 44 | super.dispose(); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Scaffold( 50 | appBar: AppBar(title: Text(widget.title)), 51 | body: SingleChildScrollView( 52 | padding: const EdgeInsets.all(30), 53 | child: Column( 54 | crossAxisAlignment: CrossAxisAlignment.start, 55 | children: [ 56 | Text('电量: $_battery%'), 57 | SizedBox(height: 10), 58 | Text('电池状态: $_batteryStatus') 59 | ]))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/bugly.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/bugly.dart'; 3 | import 'package:flutter_learn/utils/toast.dart'; 4 | 5 | class BuglyPage extends StatefulWidget { 6 | BuglyPage(this.title, {Key key}) : super(key: key); 7 | final String title; 8 | @override 9 | _BuglyPageState createState() => _BuglyPageState(); 10 | } 11 | 12 | class _BuglyPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | ), 19 | body: Container( 20 | padding: const EdgeInsets.all(10), 21 | child: ListView( 22 | scrollDirection: Axis.vertical, // 水平listView 23 | children: [ 24 | ButtonBar( 25 | alignment: 26 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 27 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 28 | children: [ 29 | RaisedButton( 30 | child: Text('版本更新检查'), 31 | onPressed: _checkUpdate, 32 | ), 33 | RaisedButton( 34 | child: Text('自定义异常信息上传'), 35 | onPressed: _uploadException, 36 | ), 37 | ], 38 | ), 39 | ], 40 | ))); 41 | } 42 | 43 | void _checkUpdate() { 44 | print("版本更新检查..."); 45 | Bugly.checkUpgrade().then((upgradeInfo) { 46 | print("版本更新检查结果: $upgradeInfo"); 47 | }); 48 | } 49 | 50 | void _uploadException() { 51 | //这里的异常可能是业务逻辑上的异常,不一定是程序的异常 52 | Bugly.uploadException("这是异常的标题", "这是异常的详细内容", 53 | data: {"key1": "value1", "key2": "value2"}).then((value) { 54 | XToast.success("上传成功"); 55 | }).catchError((error) { 56 | XToast.error("上传失败$error"); 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/camera_simple.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:camera/camera.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_learn/i10n/localization_intl.dart'; 6 | import 'package:flutter_learn/page/utils/camera_complex.dart'; 7 | import 'package:flutter_learn/router/router.dart'; 8 | import 'package:flutter_learn/utils/camera.dart'; 9 | import 'package:flutter_learn/utils/path.dart'; 10 | import 'package:flutter_learn/utils/toast.dart'; 11 | import 'package:flutter_learn/utils/utils.dart'; 12 | 13 | class CameraPage extends StatefulWidget { 14 | final String title; 15 | CameraPage(this.title, {Key key}) : super(key: key); 16 | @override 17 | _CameraPageState createState() => _CameraPageState(); 18 | } 19 | 20 | class _CameraPageState extends State { 21 | CameraController _controller; 22 | String _imageFilePath = ''; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | CameraUtils.init().then((cameras) { 28 | _controller = CameraController(cameras[0], ResolutionPreset.medium); 29 | _controller.initialize().then((_) { 30 | if (!mounted) { 31 | return; 32 | } 33 | setState(() {}); 34 | }); 35 | }); 36 | } 37 | 38 | @override 39 | void dispose() { 40 | _controller?.dispose(); 41 | super.dispose(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | appBar: AppBar( 48 | title: Text(widget.title), 49 | actions: [ 50 | IconButton( 51 | icon: Icon(Icons.view_compact), 52 | onPressed: () { 53 | XRouter.gotoWidget(context, 54 | ComplexCameraPage(Languages.of(context).complexCamera)); 55 | }), 56 | ], 57 | ), 58 | body: Center(child: buildWidget()), 59 | floatingActionButton: FloatingActionButton( 60 | onPressed: takePhoto, 61 | child: Icon( 62 | _imageFilePath.isEmpty ? Icons.photo_camera : Icons.switch_camera, 63 | ), 64 | )); 65 | } 66 | 67 | Widget buildWidget() { 68 | if (_controller != null && _controller.value.isInitialized) { 69 | if (_imageFilePath.isEmpty) { 70 | return AspectRatio( 71 | aspectRatio: _controller.value.aspectRatio, 72 | child: CameraPreview(_controller)); 73 | } else { 74 | return Image.file(File(_imageFilePath)); 75 | } 76 | } else { 77 | return CircularProgressIndicator(); 78 | } 79 | } 80 | 81 | ///拍照片 82 | void takePhoto() { 83 | if (_imageFilePath.isNotEmpty) { 84 | setState(() { 85 | _imageFilePath = ''; 86 | }); 87 | return; 88 | } 89 | 90 | PathUtils.getCacheDirPath().then((value) { 91 | String path = '$value/${Utils.timestamp()}.jpg'; 92 | print('文件路径:$path'); 93 | _controller.takePicture(path).then((value) { 94 | XToast.success('拍摄成功'); 95 | setState(() { 96 | _imageFilePath = path; 97 | }); 98 | }); 99 | }).catchError((error) => {XToast.error(error)}); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/device_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/device.dart'; 3 | 4 | class DeviceInfoPage extends StatefulWidget { 5 | final String title; 6 | DeviceInfoPage(this.title, {Key key}) : super(key: key); 7 | @override 8 | _DeviceInfoPageState createState() => _DeviceInfoPageState(); 9 | } 10 | 11 | class _DeviceInfoPageState extends State { 12 | Map _deviceData = {}; 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | initDeviceInfo(); 18 | } 19 | 20 | void initDeviceInfo() { 21 | if (!mounted) return; 22 | 23 | DeviceUtils.getDeviceInfo().then((map) { 24 | setState(() { 25 | _deviceData = map; 26 | }); 27 | }); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return Scaffold( 33 | appBar: AppBar( 34 | title: Text(widget.title), 35 | ), 36 | body: ListView( 37 | shrinkWrap: true, 38 | children: _deviceData.keys.map((String property) { 39 | return Row( 40 | children: [ 41 | Container( 42 | padding: const EdgeInsets.all(10.0), 43 | child: Text( 44 | property, 45 | style: const TextStyle( 46 | fontWeight: FontWeight.bold, 47 | ), 48 | ), 49 | ), 50 | Expanded( 51 | child: Container( 52 | padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), 53 | child: Text( 54 | '${_deviceData[property]}', 55 | overflow: TextOverflow.ellipsis, 56 | ), 57 | )), 58 | ], 59 | ); 60 | }).toList(), 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/event_bus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/event.dart'; 3 | import 'package:flutter_learn/utils/random.dart'; 4 | 5 | class EventBusPage extends StatefulWidget { 6 | EventBusPage(this.title, {Key key}) : super(key: key); 7 | final String title; 8 | @override 9 | _EventBusPageState createState() => _EventBusPageState(); 10 | } 11 | 12 | const String EVENT_CHANGE_COLOR = "event_change_color"; 13 | 14 | class _EventBusPageState extends State { 15 | Color _primaryColor = Colors.blue; 16 | bool _isSubscription = false; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | initEvent(); 22 | } 23 | 24 | void initEvent() { 25 | if (!_isSubscription) { 26 | XEvent.on(EVENT_CHANGE_COLOR, (color) { 27 | setState(() { 28 | _primaryColor = color; 29 | }); 30 | }); 31 | setState(() { 32 | _isSubscription = true; 33 | }); 34 | } 35 | } 36 | 37 | void switchEvent() { 38 | if (_isSubscription) { 39 | XEvent.cancelAll(EVENT_CHANGE_COLOR); 40 | setState(() { 41 | _isSubscription = false; 42 | }); 43 | } else { 44 | initEvent(); 45 | } 46 | } 47 | 48 | @override 49 | void dispose() { 50 | super.dispose(); 51 | //取消订阅 52 | XEvent.cancelAll(EVENT_CHANGE_COLOR); 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return Scaffold( 58 | appBar: AppBar( 59 | title: Text(widget.title), 60 | backgroundColor: _primaryColor, 61 | ), 62 | body: Container( 63 | padding: const EdgeInsets.all(10), 64 | child: ListView( 65 | scrollDirection: Axis.vertical, // 水平listView 66 | children: [ 67 | ButtonBar( 68 | alignment: 69 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 70 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 71 | children: [ 72 | RaisedButton( 73 | child: Text('改变标题栏的背景颜色'), 74 | onPressed: () => { 75 | XEvent.post( 76 | EVENT_CHANGE_COLOR, RandomUtils.getRandomColor()) 77 | }, 78 | ), 79 | RaisedButton( 80 | child: Text(_isSubscription ? '取消订阅' : "订阅"), 81 | onPressed: switchEvent, 82 | ), 83 | ], 84 | ), 85 | ], 86 | ))); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/json_serialize.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_learn/model/sql/app_info.dart'; 4 | 5 | /* 6 | * 1.可使用Dart Data Class Generator插件 根据json创建dart类,类似Android的GsonFormat 7 | * 使用命令: Generate from JSON 8 | * 2.使用在线生成工具: https://javiercbk.github.io/json_to_dart/ 9 | */ 10 | class JsonSerializePage extends StatefulWidget { 11 | JsonSerializePage(this.title, {Key key}) : super(key: key); 12 | final String title; 13 | @override 14 | _JsonSerializePageState createState() => _JsonSerializePageState(); 15 | } 16 | 17 | class _JsonSerializePageState extends State { 18 | String jsonString = ""; 19 | String message = ""; 20 | 21 | Future loadJsonFromAsset() async { 22 | jsonString = await rootBundle.loadString('assets/json/app_version.json'); 23 | updateResult("从assets加载的json:\n" + jsonString); 24 | } 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | loadJsonFromAsset(); 30 | } 31 | 32 | void updateResult(String result) { 33 | setState(() { 34 | message = result; 35 | }); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text(widget.title), 43 | ), 44 | body: Container( 45 | padding: const EdgeInsets.all(10), 46 | child: ListView( 47 | scrollDirection: Axis.vertical, // 水平listView 48 | children: [ 49 | ButtonBar( 50 | alignment: 51 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 52 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 53 | children: [ 54 | RaisedButton( 55 | child: Text('反序列化'), 56 | onPressed: deSerialize, 57 | ), 58 | RaisedButton( 59 | child: Text('序列化'), 60 | onPressed: serialize, 61 | ), 62 | ], 63 | ), 64 | Text("结果:"), 65 | SizedBox(height: 10), 66 | Text(message) 67 | ], 68 | ))); 69 | } 70 | 71 | //反序列化 72 | void deSerialize() { 73 | AppInfo appInfo = AppInfo.fromJson(jsonString); 74 | updateResult("反序列化获取更新的内容:" + appInfo.modifyContent); 75 | } 76 | 77 | //序列化 78 | void serialize() { 79 | AppInfo appInfo = AppInfo.fromJson(jsonString); 80 | updateResult("序列化结果:" + appInfo.toJson()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/navigator.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_learn/page/widget/empty.dart'; 4 | import 'package:flutter_learn/router/router.dart'; 5 | import 'package:flutter_learn/router/switch_animation.dart'; 6 | import 'package:flutter_learn/utils/toast.dart'; 7 | 8 | class NavigatorPage extends StatefulWidget { 9 | NavigatorPage(this.title, {Key key}) : super(key: key); 10 | final String title; 11 | @override 12 | _NavigatorPageState createState() => _NavigatorPageState(); 13 | } 14 | 15 | class _NavigatorPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text(widget.title), 21 | ), 22 | body: SingleChildScrollView( 23 | padding: const EdgeInsets.all(10), 24 | child: Column( 25 | children: [ 26 | ButtonBar( 27 | alignment: MainAxisAlignment.start, 28 | mainAxisSize: MainAxisSize.min, 29 | children: [ 30 | RaisedButton( 31 | child: Text('命名路由'), 32 | onPressed: () => { 33 | //不可以传参数 34 | Navigator.pushNamed(context, "/empty") 35 | }, 36 | ), 37 | RaisedButton( 38 | child: Text('构建路由'), 39 | onPressed: () => { 40 | Navigator.push(context, new MaterialPageRoute( 41 | builder: (BuildContext context) { 42 | return new EmptyPage(title: "这是我传的参数"); 43 | })).then((result) => { 44 | if (result != null) {XToast.toast(result)} 45 | }) 46 | }, 47 | ), 48 | ], 49 | ), 50 | ButtonBar( 51 | alignment: MainAxisAlignment.start, 52 | mainAxisSize: MainAxisSize.min, 53 | children: [ 54 | RaisedButton( 55 | child: Text('路由动画'), 56 | onPressed: () => 57 | {Navigator.push(context, SlidePageRoute(routeName: "/empty"))}, 58 | ), 59 | RaisedButton( 60 | child: Text('fluro跳转'), 61 | onPressed: () => { 62 | XRouter.router.navigateTo(context, 63 | "/web?url=${Uri.encodeComponent("https://www.baidu.com/")}&title=${Uri.encodeComponent("百度")}", 64 | transition: TransitionType.fadeIn) 65 | }, 66 | ), 67 | ], 68 | ), 69 | ], 70 | ))); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/net.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/http.dart'; 3 | 4 | class NetRequestPage extends StatefulWidget { 5 | NetRequestPage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _NetRequestPageState createState() => _NetRequestPageState(); 9 | } 10 | 11 | class _NetRequestPageState extends State { 12 | String json = ""; 13 | 14 | void doGet() { 15 | XHttp.get("/banner/json").then((response) => { 16 | setState(() { 17 | json = response.toString(); 18 | }) 19 | }); 20 | } 21 | 22 | void doParam() { 23 | XHttp.get("/article/list/0/json", {"author": "xuexiangjys"}) 24 | .then((response) => { 25 | setState(() { 26 | json = response.toString(); 27 | }) 28 | }); 29 | } 30 | 31 | void doPost() { 32 | XHttp.post("/user/login", {"username": "xuexiang", "password" : "123456"}) 33 | .then((response) => { 34 | setState(() { 35 | json = response.toString(); 36 | }) 37 | }); 38 | } 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return Scaffold( 43 | appBar: AppBar( 44 | title: Text(widget.title), 45 | ), 46 | body: Container( 47 | padding: const EdgeInsets.all(20), 48 | child: ListView( 49 | scrollDirection: Axis.vertical, // 水平listView 50 | children: [ 51 | ButtonBar( 52 | alignment: MainAxisAlignment.start, 53 | mainAxisSize: MainAxisSize.min, 54 | children: [ 55 | // Button集合 56 | RaisedButton( 57 | child: Text('Get请求'), 58 | onPressed: doGet, 59 | ), 60 | RaisedButton( 61 | child: Text('参数请求'), 62 | onPressed: doParam, 63 | ), 64 | RaisedButton( 65 | child: Text('post请求'), 66 | onPressed: doPost, 67 | ), 68 | ], 69 | ), 70 | Text('网络请求结果:\n$json', 71 | style: TextStyle(fontSize: 14), textAlign: TextAlign.left), 72 | ], 73 | ))); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/package_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/utils.dart'; 3 | 4 | class PackageInfoPage extends StatefulWidget { 5 | final String title; 6 | PackageInfoPage(this.title, {Key key}) : super(key: key); 7 | @override 8 | _PackageInfoPageState createState() => _PackageInfoPageState(); 9 | } 10 | 11 | class _PackageInfoPageState extends State { 12 | Map _packageInfo = {}; 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | if (!mounted) return; 18 | 19 | Utils.getPackageInfoMap().then((map) { 20 | setState(() { 21 | _packageInfo = map; 22 | }); 23 | }); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar(title: Text(widget.title)), 30 | body: ListView( 31 | shrinkWrap: true, 32 | children: _packageInfo.keys.map((String property) { 33 | return buildItem(property, '${_packageInfo[property]}'); 34 | }).toList(), 35 | )); 36 | } 37 | 38 | Widget buildItem(String title, String content) { 39 | return Row( 40 | children: [ 41 | Container( 42 | padding: const EdgeInsets.all(10.0), 43 | child: Text( 44 | title, 45 | style: const TextStyle( 46 | fontWeight: FontWeight.bold, 47 | ), 48 | ), 49 | ), 50 | Expanded( 51 | child: Container( 52 | padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), 53 | child: Text( 54 | content, 55 | overflow: TextOverflow.ellipsis, 56 | ), 57 | )), 58 | ], 59 | ); 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/path.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/path.dart'; 3 | 4 | class FilePathPage extends StatefulWidget { 5 | final String title; 6 | FilePathPage(this.title, {Key key}) : super(key: key); 7 | @override 8 | _FilePathPageState createState() => _FilePathPageState(); 9 | } 10 | 11 | class _FilePathPageState extends State { 12 | String cachePath = ''; 13 | String filesPath = ''; 14 | String documentsPath = ''; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | PathUtils.getCacheDirPath().then((value) { 20 | setState(() { 21 | cachePath = value; 22 | }); 23 | }); 24 | PathUtils.getFilesDirPath().then((value) { 25 | setState(() { 26 | filesPath = value; 27 | }); 28 | }); 29 | PathUtils.getDocumentsDirPath().then((value) { 30 | setState(() { 31 | documentsPath = value; 32 | }); 33 | }); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | appBar: AppBar(title: Text(widget.title)), 40 | body: Container( 41 | padding: const EdgeInsets.all(10), 42 | child: ListView(children: [ 43 | buildItem('缓存路径', cachePath), 44 | buildItem('文件路径', filesPath), 45 | buildItem('文档路径', documentsPath), 46 | ]))); 47 | } 48 | 49 | Widget buildItem(String title, String content) { 50 | return Row( 51 | children: [ 52 | Container( 53 | padding: const EdgeInsets.all(10.0), 54 | child: Text( 55 | title, 56 | style: const TextStyle( 57 | fontWeight: FontWeight.bold, 58 | ), 59 | ), 60 | ), 61 | Expanded( 62 | child: Container( 63 | padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), 64 | child: Text( 65 | content, 66 | maxLines: 3, 67 | overflow: TextOverflow.ellipsis, 68 | ), 69 | )), 70 | ], 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/permission_apply.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/toast.dart'; 3 | import 'package:permission_handler/permission_handler.dart'; 4 | 5 | class PermissionApplyPage extends StatefulWidget { 6 | final String title; 7 | PermissionApplyPage(this.title, {Key key}) : super(key: key); 8 | @override 9 | _PermissionApplyPageState createState() => _PermissionApplyPageState(); 10 | } 11 | 12 | class _PermissionApplyPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar(title: Text(widget.title), actions: [ 17 | IconButton( 18 | icon: const Icon(Icons.settings), 19 | onPressed: () { 20 | openAppSettings().then((bool hasOpened) => 21 | debugPrint('App Settings opened: ' + hasOpened.toString())); 22 | }, 23 | ) 24 | ]), 25 | body: SingleChildScrollView( 26 | padding: const EdgeInsets.all(10), 27 | child: Column(children: [ 28 | ButtonBar( 29 | alignment: MainAxisAlignment.start, 30 | mainAxisSize: MainAxisSize.min, 31 | children: [ 32 | RaisedButton( 33 | child: Text('相机权限申请'), 34 | onPressed: () { 35 | Permission.camera 36 | .request() 37 | .then((value) => {XToast.toast("申请结果:$value")}); 38 | }, 39 | ), 40 | RaisedButton( 41 | child: Text('相机权限检查'), 42 | onPressed: () { 43 | Permission.camera.status 44 | .then((value) => {XToast.toast("检查结果:$value")}); 45 | }, 46 | ), 47 | ], 48 | ) 49 | ]))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/router/router.dart'; 3 | import 'package:flutter_learn/utils/provider.dart'; 4 | import 'package:flutter_learn/utils/random.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class ProviderPage extends StatefulWidget { 8 | ProviderPage(this.title, {Key key}) : super(key: key); 9 | 10 | final String title; 11 | 12 | @override 13 | _ProviderPageState createState() => _ProviderPageState(); 14 | } 15 | 16 | class _ProviderPageState extends State { 17 | final Color _color = RandomUtils.getRandomColor(); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | appBar: AppBar( 23 | title: Text(widget.title), 24 | ), 25 | body: Center( 26 | child: Container( 27 | alignment: Alignment.center, 28 | height: 100, 29 | child: Column(children: [ 30 | Text("counter:${Provider.of(context).count}"), 31 | SizedBox(height: 20), 32 | RaisedButton( 33 | child: Text("下一页"), 34 | color: _color, 35 | textColor: Colors.white, 36 | onPressed: () { 37 | XRouter.goto(context, '/utils/provider_next'); 38 | }, 39 | ), 40 | ]))), 41 | floatingActionButton: FloatingActionButton( 42 | onPressed: () { 43 | Provider.of(context, listen: false).add(); 44 | }, 45 | tooltip: '增加', 46 | child: Icon(Icons.add), 47 | )); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/provider_next.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/router/router.dart'; 3 | import 'package:flutter_learn/utils/provider.dart'; 4 | import 'package:flutter_learn/utils/random.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class ProviderNextPage extends StatefulWidget { 8 | ProviderNextPage(this.title, {Key key}) : super(key: key); 9 | final String title; 10 | 11 | @override 12 | _ProviderNextPageState createState() => _ProviderNextPageState(); 13 | } 14 | 15 | class _ProviderNextPageState extends State { 16 | final Color _color = RandomUtils.getRandomColor(); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | appBar: AppBar( 22 | title: Text(widget.title), 23 | ), 24 | body: Padding( 25 | padding: const EdgeInsets.all(60), 26 | child: Center( 27 | child: Column(children: [ 28 | //可以使用Consumer 29 | Consumer(builder: (cotext, value, child) { 30 | return Text("counter:${value.count}"); 31 | }), 32 | SizedBox(height: 20), 33 | RaisedButton( 34 | child: Text("下一页"), 35 | color: _color, 36 | textColor: Colors.white, 37 | onPressed: () { 38 | XRouter.goto(context, '/utils/provider_next'); 39 | }, 40 | ), 41 | ]))), 42 | floatingActionButton: FloatingActionButton( 43 | onPressed: () { 44 | Store.value(context).add(); 45 | }, 46 | tooltip: '增加', 47 | child: Icon(Icons.add), 48 | )); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/share.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:share/share.dart'; 3 | 4 | class SharePage extends StatefulWidget { 5 | final String title; 6 | SharePage(this.title, {Key key}) : super(key: key); 7 | @override 8 | _SharePageState createState() => _SharePageState(); 9 | } 10 | 11 | class _SharePageState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(title: Text(widget.title)), 16 | body: SingleChildScrollView( 17 | padding: const EdgeInsets.all(10), 18 | child: Column(children: [ 19 | ButtonBar( 20 | alignment: MainAxisAlignment 21 | .start, 22 | mainAxisSize: MainAxisSize.min, 23 | children: [ 24 | // Button集合 25 | RaisedButton( 26 | child: Text('文本分享1'), 27 | onPressed: share1, 28 | ), 29 | RaisedButton( 30 | child: Text('文本分享2'), 31 | onPressed: share2, 32 | ), 33 | ], 34 | ), 35 | ]))); 36 | } 37 | 38 | void share1() { 39 | Share.share('这是我分享的内容: https://baidu.com'); 40 | } 41 | 42 | void share2() { 43 | Share.share('这是我分享的内容: https://baidu.com', subject: "这是副标题"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/shared_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_learn/utils/shared_preferences.dart'; 5 | 6 | class SharedPreferencesPage extends StatefulWidget { 7 | SharedPreferencesPage(this.title, {Key key}) : super(key: key); 8 | final String title; 9 | @override 10 | _SharedPreferencesPageState createState() => _SharedPreferencesPageState(); 11 | } 12 | 13 | class _SharedPreferencesPageState extends State { 14 | String result = ""; 15 | 16 | int random; 17 | 18 | void updateResult(String value) { 19 | setState(() { 20 | result = value; 21 | }); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | appBar: AppBar( 28 | title: Text(widget.title), 29 | ), 30 | body: Container( 31 | padding: const EdgeInsets.all(20), 32 | child: ListView( 33 | scrollDirection: Axis.vertical, // 水平listView 34 | children: [ 35 | ButtonBar( 36 | alignment: 37 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 38 | mainAxisSize: MainAxisSize.max, //主轴大小,默认MainAxisSize.max 39 | children: [ 40 | // Button集合 41 | RaisedButton( 42 | child: Text('设置String'), 43 | onPressed: () => { 44 | SPUtils.putString("username", "xuexiang123").then( 45 | (result) => 46 | {updateResult(result ? '设置成功' : '设置失败')}) 47 | }, 48 | ), 49 | RaisedButton( 50 | child: Text('获取String'), 51 | onPressed: () => 52 | {updateResult(SPUtils.getString("username"))}, 53 | ), 54 | ], 55 | ), 56 | ButtonBar( 57 | alignment: 58 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 59 | mainAxisSize: MainAxisSize.max, //主轴大小,默认MainAxisSize.max 60 | children: [ 61 | // Button集合 62 | RaisedButton( 63 | child: Text('设置Int随机数'), 64 | onPressed: () => { 65 | random = Random().nextInt(100), 66 | SPUtils.putInt("int_key", random).then((result) => 67 | {updateResult('保存的数字:' + random.toString())}) 68 | }, 69 | ), 70 | RaisedButton( 71 | child: Text('获取Int'), 72 | onPressed: () => { 73 | updateResult( 74 | '获得的数字:' + SPUtils.getInt("int_key").toString()) 75 | }, 76 | ), 77 | ], 78 | ), 79 | Text('结果:\n$result', 80 | style: TextStyle(fontSize: 14), textAlign: TextAlign.left), 81 | ], 82 | ))); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/url.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/utils.dart'; 3 | 4 | class UrlPage extends StatefulWidget { 5 | final String title; 6 | UrlPage(this.title, {Key key}) : super(key: key); 7 | 8 | @override 9 | _UrlPageState createState() => _UrlPageState(); 10 | } 11 | 12 | class _UrlPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar(title: Text(widget.title)), 17 | body: SingleChildScrollView( 18 | padding: const EdgeInsets.all(10), 19 | child: Column(children: [ 20 | ButtonBar( 21 | alignment: MainAxisAlignment.start, 22 | mainAxisSize: MainAxisSize.min, 23 | children: [ 24 | // Button集合 25 | RaisedButton( 26 | child: Text("网页"), 27 | onPressed: web, 28 | ), 29 | RaisedButton( 30 | child: Text('邮件'), 31 | onPressed: email, 32 | ), 33 | RaisedButton( 34 | child: Text('电话'), 35 | onPressed: phone, 36 | ), 37 | RaisedButton( 38 | child: Text('短信'), 39 | onPressed: message, 40 | ), 41 | ], 42 | ) 43 | ]))); 44 | } 45 | 46 | void web() { 47 | Utils.launchURL("https://github.com/xuexiangjys"); 48 | } 49 | 50 | void email() { 51 | Utils.launchURL("mailto:xuexiangandroid@163.com?subject=这是邮件的标题&body=这是邮件的内容"); 52 | } 53 | 54 | void phone() { 55 | //打电话骚扰中国移动,嘿嘿~~ 56 | Utils.launchURL("tel:10086"); 57 | } 58 | 59 | void message() { 60 | Utils.launchURL("sms:10086"); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/utils/video.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:video_player/video_player.dart'; 3 | 4 | class VideoPlayerPage extends StatefulWidget { 5 | final String title; 6 | VideoPlayerPage(this.title, {Key key}) : super(key: key); 7 | 8 | @override 9 | _VideoPlayerPageState createState() => _VideoPlayerPageState(); 10 | } 11 | 12 | class _VideoPlayerPageState extends State { 13 | VideoPlayerController _controller; 14 | 15 | static const String VIDEO_URL = 16 | 'http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4'; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = VideoPlayerController.network(VIDEO_URL) 22 | ..initialize().then((_) { 23 | switchControl(); 24 | }); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | void switchControl() { 34 | setState(() { 35 | _controller.value.isPlaying ? _controller.pause() : _controller.play(); 36 | }); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return Scaffold( 42 | appBar: AppBar(title: Text(widget.title)), 43 | body: Center( 44 | child: _controller.value.initialized 45 | ? AspectRatio( 46 | aspectRatio: _controller.value.aspectRatio, 47 | child: VideoPlayer(_controller), 48 | ) 49 | : CircularProgressIndicator(), 50 | ), 51 | floatingActionButton: FloatingActionButton( 52 | onPressed: switchControl, 53 | child: Icon( 54 | _controller.value.isPlaying ? Icons.pause : Icons.play_arrow, 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/anim/basic_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BasicAnimationPage extends StatefulWidget { 4 | BasicAnimationPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _AnimationPageState createState() => _AnimationPageState(); 8 | } 9 | 10 | class _AnimationPageState extends State 11 | with SingleTickerProviderStateMixin { 12 | Animation animation; 13 | AnimationController _controller; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _controller = 19 | AnimationController(duration: const Duration(seconds: 1), vsync: this); 20 | //图片宽高从0变到300 21 | animation = Tween(begin: 0.0, end: 300.0).animate(_controller); 22 | animation.addStatusListener((status) { 23 | ///dismissed 动画在起始点停止 24 | ///forward 动画正在正向执行 25 | ///reverse 动画正在反向执行 26 | ///completed 动画在终点停止 27 | if (status == AnimationStatus.completed) { 28 | //动画执行结束时反向执行动画 29 | _controller.reverse(); 30 | } else if (status == AnimationStatus.dismissed) { 31 | //动画恢复到初始状态时执行动画(正向) 32 | _controller.forward(); 33 | } 34 | }); 35 | 36 | //启动动画(正向) 37 | _controller.forward(); 38 | } 39 | 40 | @override 41 | void dispose() { 42 | _controller.dispose(); 43 | super.dispose(); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return Scaffold( 49 | appBar: AppBar( 50 | title: Text(widget.title), 51 | ), 52 | body: GrowTransition( 53 | child: Image.asset("assets/images/food01.jpeg"), 54 | animation: animation, 55 | )); 56 | } 57 | } 58 | 59 | ///自动变大的动画 60 | ///Flutter中正是通过这种方式封装了很多动画,如:FadeTransition、ScaleTransition、SizeTransition等,很多时候都可以复用这些预置的过渡类。 61 | class GrowTransition extends StatelessWidget { 62 | GrowTransition({this.child, this.animation}); 63 | 64 | final Widget child; 65 | final Animation animation; 66 | 67 | Widget build(BuildContext context) { 68 | return new Center( 69 | child: new AnimatedBuilder( 70 | animation: animation, 71 | builder: (BuildContext context, Widget child) { 72 | return new Container( 73 | height: animation.value, width: animation.value, child: child); 74 | }, 75 | child: child), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/appbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/toast.dart'; 3 | import 'package:flutter_learn/view/titlebar.dart'; 4 | 5 | class AppBarPage extends StatefulWidget { 6 | final String title; 7 | AppBarPage(this.title, {key}) : super(key: key); 8 | @override 9 | _AppBarPageState createState() => _AppBarPageState(); 10 | } 11 | 12 | class _AppBarPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | actions: [ 19 | IconButton( 20 | icon: Icon(Icons.add_a_photo), 21 | tooltip: '拍照', 22 | onPressed: () { 23 | // do nothing 24 | }), 25 | PopupMenuButton( 26 | itemBuilder: (BuildContext context) => >[ 27 | PopupMenuItem(value: "about", child: Text('关于')), 28 | PopupMenuItem(value: "setting", child: Text('设置')), 29 | ], 30 | onSelected: (String action) { 31 | switch (action) { 32 | case "about": 33 | XToast.toast("点击了关于"); 34 | break; 35 | case "setting": 36 | XToast.toast("点击了设置"); 37 | break; 38 | } 39 | }) 40 | ], 41 | ), 42 | body: Container( 43 | padding: const EdgeInsets.only(top: 10), 44 | child: ListView( 45 | scrollDirection: Axis.vertical, // 水平listView 46 | children: [TitleBar.backAppbar(context, '个人资料')], 47 | )), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/bottom_navigation_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavigationBarPage extends StatefulWidget { 4 | BottomNavigationBarPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _BottomNavigationBarPageState createState() => 8 | _BottomNavigationBarPageState(); 9 | } 10 | 11 | class _BottomNavigationBarPageState extends State { 12 | List _myTabs = [ 13 | BottomNavigationBarItem(label: "主页", icon: Icon(Icons.home)), 14 | BottomNavigationBarItem(label: "列表", icon: Icon(Icons.list)), 15 | BottomNavigationBarItem(label: "新建", icon: Icon(Icons.add)), 16 | BottomNavigationBarItem(label: "消息", icon: Icon(Icons.message)), 17 | BottomNavigationBarItem(label: "菜单", icon: Icon(Icons.menu)), 18 | BottomNavigationBarItem(label: "其他", icon: Icon(Icons.devices_other)), 19 | ]; 20 | 21 | int _currentIndex = 0; 22 | 23 | void _onItemTapped(int index) { 24 | if (mounted) { 25 | setState(() { 26 | _currentIndex = index; 27 | }); 28 | } 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return Scaffold( 34 | appBar: AppBar( 35 | title: Text(widget.title), 36 | ), 37 | body: IndexedStack( 38 | index: _currentIndex, 39 | children: _myTabs.map((BottomNavigationBarItem tab) { 40 | return Center(child: Text(tab.label)); 41 | }).toList(), 42 | ), 43 | bottomNavigationBar: BottomNavigationBar( 44 | items: _myTabs, 45 | //高亮 被点击高亮 46 | currentIndex: _currentIndex, 47 | //修改 页面 48 | onTap: _onItemTapped, 49 | //shifting :按钮点击移动效果 50 | //fixed:固定 51 | type: BottomNavigationBarType.fixed, 52 | fixedColor: Theme.of(context).primaryColor, 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/contain/clip.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ClipPage extends StatefulWidget { 4 | ClipPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _ClipPageState createState() => _ClipPageState(); 8 | } 9 | 10 | class _ClipPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | Widget image = Image.asset('assets/images/food01.jpeg', width: 80.0); 14 | return Scaffold( 15 | appBar: AppBar( 16 | title: Text(widget.title), 17 | ), 18 | body: SingleChildScrollView( 19 | padding: const EdgeInsets.all(10), 20 | child: Column( 21 | children: [ 22 | image, //不剪裁 23 | 24 | //子组件为正方形时剪裁为内贴圆形,为矩形时,剪裁为内贴椭圆 25 | ClipOval(child: image), 26 | 27 | //将子组件剪裁为圆角矩形 28 | ClipRRect( 29 | //剪裁为圆角矩形 30 | borderRadius: BorderRadius.circular(5.0), 31 | child: image, 32 | ), 33 | Row( 34 | mainAxisAlignment: MainAxisAlignment.center, 35 | children: [ 36 | Align( 37 | alignment: Alignment.topLeft, 38 | widthFactor: .5, //宽度设为原来宽度一半,另一半会溢出 39 | child: image, 40 | ), 41 | Text( 42 | "你好世界", 43 | style: TextStyle(color: Colors.green), 44 | ) 45 | ], 46 | ), 47 | Row( 48 | mainAxisAlignment: MainAxisAlignment.center, 49 | children: [ 50 | ClipRect( 51 | //将溢出部分剪裁 52 | child: Align( 53 | alignment: Alignment.topLeft, 54 | widthFactor: .5, //宽度设为原来宽度一半 55 | child: image, 56 | ), 57 | ), 58 | Text("你好世界", style: TextStyle(color: Colors.green)) 59 | ], 60 | ), 61 | 62 | SizedBox(height: 20), 63 | 64 | DecoratedBox( 65 | decoration: BoxDecoration(color: Colors.red), 66 | child: ClipRect( 67 | clipper: MyClipper(), //使用自定义的clipper 68 | child: image), 69 | ) 70 | 71 | ], 72 | ))); 73 | } 74 | } 75 | 76 | //自定义裁剪 77 | class MyClipper extends CustomClipper { 78 | ///用于获取剪裁区域的接口 79 | @override 80 | Rect getClip(Size size) => Rect.fromLTWH(10.0, 10.0, 40.0, 30.0); //以(10, 10)为左顶角起,宽为40, 高为30的矩形区域. 81 | 82 | /// 接口决定是否重新剪裁。如果在应用中,剪裁区域始终不会发生变化时应该返回false,这样就不会触发重新剪裁,避免不必要的性能开销。如果剪裁区域会发生变化(比如在对剪裁区域执行一个动画),那么变化后应该返回true来重新执行剪裁。 83 | @override 84 | bool shouldReclip(CustomClipper oldClipper) => false; 85 | } 86 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/contain/container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ContainerPage extends StatefulWidget { 4 | ContainerPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _ContainerPageState createState() => _ContainerPageState(); 8 | } 9 | 10 | class _ContainerPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: Container( 18 | margin: EdgeInsets.only(top: 50.0, left: 120.0), //容器外填充 19 | //1.尺寸约束,相当于ConstrainedBox 20 | constraints: 21 | BoxConstraints.tightFor(width: 200.0, height: 150.0), //卡片大小 22 | //2.装饰,相当于DecoratedBox 23 | decoration: BoxDecoration( 24 | //背景装饰 25 | gradient: RadialGradient( 26 | //背景径向渐变 27 | colors: [Colors.red, Colors.orange], 28 | center: Alignment.topLeft, 29 | radius: .98), 30 | boxShadow: [ 31 | //卡片阴影 32 | BoxShadow( 33 | color: Colors.black54, 34 | offset: Offset(2.0, 2.0), 35 | blurRadius: 4.0) 36 | ]), 37 | //3.变换, 相当于Transform 38 | transform: Matrix4.rotationZ(.2), //卡片倾斜变换 39 | //4.对齐, 相当于Align 40 | alignment: Alignment.center, //卡片内文字居中 41 | child: Text( 42 | //卡片文字 43 | "5.20", style: TextStyle(color: Colors.white, fontSize: 40.0), 44 | ), 45 | )); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/contain/decorated_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DecoratedBoxPage extends StatefulWidget { 4 | DecoratedBoxPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _DecoratedBoxPageState createState() => _DecoratedBoxPageState(); 8 | } 9 | 10 | class _DecoratedBoxPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: SingleChildScrollView( 18 | padding: const EdgeInsets.all(10), 19 | child: Column( 20 | children: [ 21 | DecoratedBox( 22 | decoration: BoxDecoration( 23 | //线性渐变 24 | gradient: LinearGradient( 25 | colors: [Colors.red, Colors.orange[700]]), //背景渐变 26 | //圆角 27 | borderRadius: BorderRadius.circular(3.0), //3像素圆角 28 | //阴影 29 | boxShadow: [ 30 | BoxShadow( 31 | color: Colors.black54, 32 | offset: Offset(2.0, 2.0), 33 | blurRadius: 4.0) 34 | ]), 35 | child: Padding( 36 | padding: EdgeInsets.symmetric( 37 | horizontal: 60.0, vertical: 18.0), 38 | child: Text( 39 | "Login", 40 | style: TextStyle(color: Colors.white), 41 | ), 42 | )), 43 | 44 | SizedBox(height: 20), 45 | 46 | DecoratedBox( 47 | decoration: BoxDecoration( 48 | //放射渐变 49 | gradient: RadialGradient( 50 | colors: [Colors.red, Colors.orange, Colors.blue, Colors.pink]), //背景渐变 51 | //圆角 52 | borderRadius: BorderRadius.circular(10), //10像素圆角 53 | //阴影 54 | boxShadow: [ 55 | BoxShadow( 56 | color: Colors.black54, 57 | offset: Offset(4.0, 4.0), 58 | blurRadius: 4.0) 59 | ]), 60 | child: Padding( 61 | padding: EdgeInsets.symmetric( 62 | horizontal: 60.0, vertical: 60.0), 63 | child: Text( 64 | "Login", 65 | style: TextStyle(color: Colors.white), 66 | ), 67 | )) 68 | ], 69 | ))); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/contain/transform.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math' as math; 3 | 4 | ///Transform的变换是应用在绘制阶段,而并不是应用在布局(layout)阶段,所以无论对子组件应用何种变化,其占用空间的大小和在屏幕上的位置都是固定不变的,因为这些是在布局阶段就确定的。 5 | class TransformPage extends StatefulWidget { 6 | TransformPage(this.title, {Key key}) : super(key: key); 7 | final String title; 8 | @override 9 | _TransformPageState createState() => _TransformPageState(); 10 | } 11 | 12 | class _TransformPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | ), 19 | body: SingleChildScrollView( 20 | padding: const EdgeInsets.all(10), 21 | child: Column( 22 | children: [ 23 | SizedBox(height: 40), 24 | Container( 25 | color: Colors.black38, 26 | child: Transform( 27 | alignment: Alignment.topRight, //相对于坐标系原点的对齐方式 28 | transform: Matrix4.skewY(0.3), //沿Y轴倾斜0.3弧度 29 | child: Container( 30 | padding: const EdgeInsets.all(8.0), 31 | color: Colors.deepOrange, 32 | child: const Text('Apartment for rent!'), 33 | ), 34 | ), 35 | ), 36 | 37 | SizedBox(height: 20), 38 | 39 | //平移: Transform.translate接收一个offset参数,可以在绘制时沿x、y轴对子组件平移指定的距离。 40 | DecoratedBox( 41 | decoration: BoxDecoration(color: Colors.red), 42 | //默认原点为左上角,左移20像素,向上平移5像素 43 | child: Transform.translate( 44 | offset: Offset(-20.0, -5.0), 45 | child: Text("Hello world"), 46 | ), 47 | ), 48 | 49 | SizedBox(height: 40), 50 | 51 | //旋转: Transform.rotate可以对子组件进行旋转变换 52 | DecoratedBox( 53 | decoration: BoxDecoration(color: Colors.red), 54 | child: Transform.rotate( 55 | //旋转90度 56 | angle: math.pi / 2, 57 | child: Text("Hello world"), 58 | ), 59 | ), 60 | 61 | SizedBox(height: 40), 62 | 63 | //缩放: Transform.scale可以对子组件进行缩小或放大 64 | DecoratedBox( 65 | decoration: BoxDecoration(color: Colors.red), 66 | child: Transform.scale( 67 | scale: 1.5, //放大到1.5倍 68 | child: Text("Hello world"))), 69 | 70 | SizedBox(height: 40), 71 | 72 | //RotatedBox和Transform.rotate功能相似,它们都可以对子组件进行旋转变换,但是有一点不同:RotatedBox的变换是在layout阶段,会影响在子组件的位置和大小。 73 | DecoratedBox( 74 | decoration: BoxDecoration(color: Colors.red), 75 | //将Transform.rotate换成RotatedBox 76 | child: RotatedBox( 77 | quarterTurns: 1, //旋转90度(1/4圈) 78 | child: Text("Hello world"), 79 | ), 80 | ), 81 | 82 | ], 83 | ))); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/drag.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DragPage extends StatefulWidget { 4 | DragPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _DragPageState createState() => _DragPageState(); 8 | } 9 | 10 | class _DragPageState extends State { 11 | double _top = 100.0; //距顶部的偏移 12 | double _left = 100.0; //距左边的偏移 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar( 18 | title: Text(widget.title), 19 | ), 20 | body: Stack( 21 | children: [ 22 | Positioned( 23 | top: _top, 24 | left: _left, 25 | child: GestureDetector( 26 | child: Container( 27 | height: 70, 28 | width: 70, 29 | child: CircleAvatar(child: Text("按住\n拖动"))), 30 | //手指按下时会触发此回调 31 | onPanDown: (DragDownDetails e) { 32 | //打印手指按下的位置(相对于屏幕) 33 | print("用户手指按下:${e.globalPosition}"); 34 | }, 35 | //手指滑动时会触发此回调 36 | onPanUpdate: (DragUpdateDetails e) { 37 | //用户手指滑动时,更新偏移,重新构建 38 | setState(() { 39 | _left += e.delta.dx; 40 | _top += e.delta.dy; 41 | }); 42 | }, 43 | onPanEnd: (DragEndDetails e) { 44 | //打印滑动结束时在x、y轴上的速度 45 | print(e.velocity); 46 | }, 47 | ), 48 | ) 49 | ], 50 | )); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/toast.dart'; 3 | 4 | class DrawerPage extends StatefulWidget { 5 | DrawerPage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _DrawerPageState createState() => _DrawerPageState(); 9 | } 10 | 11 | class _DrawerPageState extends State { 12 | int count = 0; 13 | final GlobalKey _scaffoldKey = GlobalKey(); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | key: _scaffoldKey, 19 | appBar: AppBar( 20 | title: Text(widget.title), 21 | ), 22 | body: Center( 23 | child: Column( 24 | children: [ 25 | RaisedButton( 26 | child: Text('点我试试呼出SnackBar&Drawer'), 27 | textColor: Colors.white, 28 | onPressed: () { 29 | _scaffoldKey.currentState.openDrawer(); 30 | _scaffoldKey.currentState.showSnackBar(const SnackBar( 31 | content: Text("我是通过ScaffoldState的方式呼出的SnackBar."))); 32 | }, 33 | ), 34 | RaisedButton( 35 | child: Text('返回'), 36 | textColor: Colors.white, 37 | onPressed: () { 38 | Navigator.pop(context); 39 | }, 40 | ) 41 | ], 42 | ), 43 | ), 44 | drawer: Drawer( 45 | child: Column( 46 | children: [ 47 | const UserAccountsDrawerHeader( 48 | accountName: Text('xuexiang'), 49 | accountEmail: Text('xuexiangjys@163.com'), 50 | currentAccountPicture: CircleAvatar( 51 | backgroundImage: AssetImage( 52 | 'assets/images/flutter.png', 53 | ), 54 | ), 55 | margin: EdgeInsets.zero, 56 | ), 57 | MediaQuery.removePadding( 58 | context: context, 59 | // DrawerHeader consumes top MediaQuery padding. 60 | removeTop: true, 61 | child: ListView( 62 | shrinkWrap: true, //为true可以解决子控件必须设置高度的问题 63 | physics: NeverScrollableScrollPhysics(), //禁用滑动事件 64 | scrollDirection: Axis.vertical, // 水平listView 65 | children: [ 66 | ListTile( 67 | leading: Icon(Icons.payment), 68 | title: Text('菜单1'), 69 | onTap: () => {XToast.toast("菜单1")}, 70 | ), 71 | ListTile( 72 | leading: Icon(Icons.payment), 73 | title: Text('菜单2'), 74 | onTap: () => {XToast.toast("菜单2")}, 75 | ), 76 | ListTile( 77 | leading: Icon(Icons.payment), 78 | title: Text('菜单3'), 79 | onTap: () => {XToast.toast("菜单3")}, 80 | ) 81 | ], 82 | ), 83 | ), 84 | ], 85 | ), 86 | )); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/empty.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmptyPage extends StatefulWidget { 4 | EmptyPage({this.title, Key key}) : super(key: key); 5 | 6 | final String title; 7 | 8 | @override 9 | _EmptyPageState createState() => _EmptyPageState(); 10 | } 11 | 12 | class _EmptyPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | ), 19 | body: Container( 20 | padding: const EdgeInsets.all(10), 21 | child: ListView( 22 | scrollDirection: Axis.vertical, // 水平listView 23 | children: [ 24 | ButtonBar( 25 | alignment: 26 | MainAxisAlignment.start, //布局方向,默认MainAxisAlignment.end 27 | mainAxisSize: MainAxisSize.min, //主轴大小,默认MainAxisSize.max 28 | children: [ 29 | RaisedButton( 30 | child: Text('参数回传'), 31 | color: Colors.blue, 32 | onPressed: () => {Navigator.of(context).pop("回传的参数")}, 33 | ), 34 | RaisedButton( 35 | child: Text('按钮二'), 36 | color: Colors.blue, 37 | onPressed: () => {}, 38 | ), 39 | ], 40 | ), 41 | ], 42 | ))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/future_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FutureBuilderPage extends StatefulWidget { 4 | FutureBuilderPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _FutureBuilderPageState createState() => _FutureBuilderPageState(); 8 | } 9 | 10 | class _FutureBuilderPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: Center( 18 | child: FutureBuilder( 19 | future: mockNetworkData(), 20 | builder: (BuildContext context, AsyncSnapshot snapshot) { 21 | // 请求已结束 22 | if (snapshot.connectionState == ConnectionState.done) { 23 | if (snapshot.hasError) { 24 | // 请求失败,显示错误 25 | return Text("Error: ${snapshot.error}"); 26 | } else { 27 | // 请求成功,显示数据 28 | return Text("Contents: ${snapshot.data}"); 29 | } 30 | } else { 31 | // 请求未结束,显示loading 32 | return CircularProgressIndicator(); 33 | } 34 | }, 35 | ), 36 | )); 37 | } 38 | 39 | Future mockNetworkData() async { 40 | return Future.delayed(Duration(seconds: 2), () => "我是从互联网上获取的数据"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/gesture.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | //手势动作 4 | class GesturePage extends StatefulWidget { 5 | GesturePage(this.title, {Key key}) : super(key: key); 6 | final String title; 7 | @override 8 | _GesturePageState createState() => _GesturePageState(); 9 | } 10 | 11 | class _GesturePageState extends State { 12 | String _operation = "没有手势!"; //保存事件名 13 | 14 | double _width = 200.0; //通过修改图片宽度来达到缩放效果 15 | double _height = 100.0; //通过修改图片高度来达到缩放效果 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text(widget.title), 22 | ), 23 | body: Center( 24 | child: GestureDetector( 25 | child: Container( 26 | alignment: Alignment.center, 27 | color: Theme.of(context).primaryColor, 28 | width: _width, 29 | height: _height, 30 | child: Text( 31 | _operation, 32 | style: TextStyle(color: Colors.white), 33 | ), 34 | ), 35 | onTap: () => updateText("点击"), //点击 36 | onDoubleTap: () => updateText("双击"), //双击 37 | onLongPress: () => updateText("长按"), //长按 38 | onScaleUpdate: (ScaleUpdateDetails details) { 39 | setState(() { 40 | //缩放倍数在0.8到10倍之间 41 | _operation = "缩放"; 42 | _width = 200 * details.scale.clamp(0.8, 2.0); 43 | _height = 100 * details.scale.clamp(0.8, 2.0); 44 | }); 45 | }, 46 | ), 47 | )); 48 | } 49 | 50 | void updateText(String text) { 51 | //更新显示的事件名 52 | setState(() { 53 | _operation = text; 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/image/image.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ImagePage extends StatefulWidget { 4 | ImagePage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _ImagePageState createState() => _ImagePageState(); 8 | } 9 | 10 | class _ImagePageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: Container( 18 | padding: const EdgeInsets.all(10), 19 | child: SingleChildScrollView( 20 | scrollDirection: Axis.vertical, 21 | child: Column(children: [ 22 | CircleAvatar( 23 | backgroundImage: AssetImage('assets/images/food01.jpeg'), 24 | ), 25 | Container( 26 | child: Image( 27 | image: AssetImage('assets/images/food02.jpeg'), 28 | height: 200, 29 | width: 200, 30 | ), 31 | ), 32 | ClipRRect( 33 | borderRadius: BorderRadius.circular(8), 34 | child: Image.network( 35 | 'https://pic2.zhimg.com/v2-639b49f2f6578eabddc458b84eb3c6a1.jpg', 36 | width: 120, 37 | height: 120)), 38 | Image.network( 39 | 'https://gw.alicdn.com/tfs/TB1XD.ZuYwrBKNjSZPcXXXpapXa-255-251.png'), 40 | Container( 41 | child: Text('NetworkImage的使用,带有0.5倍缩放'), 42 | margin: const EdgeInsets.symmetric(vertical: 20.0), 43 | ), 44 | Image( 45 | image: NetworkImage( 46 | 'https://gw.alicdn.com/tfs/TB1XD.ZuYwrBKNjSZPcXXXpapXa-255-251.png', 47 | scale: 0.5), 48 | ), 49 | ClipOval( 50 | child: FadeInImage.assetNetwork( 51 | placeholder: "assets/images/normal_user_icon.png", //预览图 52 | fit: BoxFit.fitWidth, 53 | image: 54 | "http://img.wxcha.com/file/201806/06/520cba4626.jpg?down", 55 | width: 80, 56 | height: 80, 57 | ), 58 | ), 59 | ]), 60 | ))); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/image/image_zoom.dart: -------------------------------------------------------------------------------- 1 | import 'package:extended_image/extended_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_learn/utils/toast.dart'; 4 | import 'package:image_picker_saver/image_picker_saver.dart'; 5 | import 'package:permission_handler/permission_handler.dart'; 6 | 7 | class ImageZoomPage extends StatefulWidget { 8 | final String title; 9 | ImageZoomPage(this.title, {Key key}) : super(key: key); 10 | @override 11 | _ImageZoomPageState createState() => _ImageZoomPageState(); 12 | } 13 | 14 | class _ImageZoomPageState extends State { 15 | static const IMAGE_URL = 16 | "https://pic4.zhimg.com/v2-1236d741cbb3aabf5a9910a5e4b73e4c_1200x500.jpg"; 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar(title: Text(widget.title), actions: [ 21 | IconButton( 22 | icon: Icon(Icons.save), onPressed: showSaveImageConfirmDialog), 23 | ]), 24 | body: Container( 25 | padding: const EdgeInsets.all(10), 26 | child: Center( 27 | child: ExtendedImage.network( 28 | IMAGE_URL, 29 | fit: BoxFit.contain, 30 | //enableLoadState: false, 31 | mode: ExtendedImageMode.gesture, 32 | initGestureConfigHandler: (state) { 33 | return GestureConfig( 34 | minScale: 0.9, 35 | animationMinScale: 0.7, 36 | maxScale: 3.0, 37 | animationMaxScale: 3.5, 38 | speed: 1.0, 39 | inertialSpeed: 100.0, 40 | initialScale: 1.0, 41 | inPageView: false, 42 | initialAlignment: InitialAlignment.center, 43 | ); 44 | }, 45 | )))); 46 | } 47 | 48 | void showSaveImageConfirmDialog() { 49 | showDialog( 50 | context: context, 51 | builder: (BuildContext context) { 52 | return AlertDialog( 53 | content: Text("是否保存当前图片?"), 54 | actions: [ 55 | FlatButton( 56 | child: const Text('取消'), 57 | onPressed: () { 58 | Navigator.of(context).pop(); 59 | }, 60 | ), 61 | FlatButton( 62 | child: const Text('确定'), 63 | onPressed: () { 64 | Navigator.of(context).pop(); 65 | }, 66 | ), 67 | ], 68 | ); 69 | }, 70 | ); 71 | } 72 | 73 | ///保存网络图片 74 | void saveImage() { 75 | Permission.storage.request().then((value) { 76 | if (PermissionStatus.granted == value) { 77 | saveNetworkImageToPhoto(IMAGE_URL).then((value) { 78 | if (value != null && value.isNotEmpty) { 79 | XToast.success("图片保存成功: $value"); 80 | } else { 81 | XToast.error("图片保存失败!"); 82 | } 83 | }).catchError((onError) => {XToast.error("图片保存失败:$onError")}); 84 | } else { 85 | XToast.error("权限申请失败!"); 86 | } 87 | }); 88 | } 89 | 90 | Future saveNetworkImageToPhoto(String url, 91 | {bool useCache: true}) async { 92 | var data = await getNetworkImageData(url, useCache: useCache); 93 | return await ImagePickerSaver.saveFile(fileData: data); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/layout/layout_linear.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LinearLayoutPage extends StatefulWidget { 4 | LinearLayoutPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _LinearLayoutPageState createState() => _LinearLayoutPageState(); 8 | } 9 | 10 | class _LinearLayoutPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: Container( 18 | padding: const EdgeInsets.all(10), 19 | child: Column( 20 | //测试Row对齐方式,排除Column默认居中对齐的干扰 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | Row( 24 | //相当于match_content, 默认值 25 | mainAxisSize: MainAxisSize.max, 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | Text(" hello world "), 29 | Text(" I am Jack "), 30 | ], 31 | ), 32 | Row( 33 | //相当于wrap_content 34 | mainAxisSize: MainAxisSize.min, 35 | mainAxisAlignment: MainAxisAlignment.center, 36 | children: [ 37 | Text(" hello world "), 38 | Text(" I am Jack "), 39 | ], 40 | ), 41 | Row( 42 | //right-to-left 布局 43 | mainAxisAlignment: MainAxisAlignment.end, 44 | textDirection: TextDirection.rtl, 45 | children: [ 46 | Text(" hello world "), 47 | Text(" I am Jack "), 48 | ], 49 | ), 50 | Row( 51 | crossAxisAlignment: CrossAxisAlignment.start, 52 | verticalDirection: VerticalDirection.up, 53 | children: [ 54 | Text( 55 | " hello world ", 56 | style: TextStyle(fontSize: 30.0), 57 | ), 58 | Text(" I am Jack "), 59 | ], 60 | ), 61 | 62 | SizedBox(height: 20), 63 | 64 | Row( 65 | ///在Column+Row的嵌套中, 因为Row默认只有一行, Text的maxLines属性会失效,需要在外面套一个Expanded 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | children: [ 68 | Expanded( 69 | child: Text( 70 | "涵盖绝大部分的UI组件:TextView、Button、EditText、ImageView、Spinner、Picker、Dialog、PopupWindow、ProgressBar、LoadingView、StateLayout、FlowLayout、Switch、Actionbar、TabBar、Banner、GuideView、BadgeView、MarqueeView、WebView、SearchView等一系列的组件和丰富多彩的样式主题。", 71 | maxLines: 4, 72 | softWrap: true, 73 | overflow: TextOverflow.ellipsis, 74 | style: 75 | TextStyle(color: Colors.grey, fontSize: 12.0))) 76 | ], 77 | ), 78 | ], 79 | ))); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/layout/layout_stack.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StackLayoutPage extends StatefulWidget { 4 | StackLayoutPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _StackLayoutPageState createState() => _StackLayoutPageState(); 8 | } 9 | 10 | class _StackLayoutPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text(widget.title), 16 | ), 17 | body: ConstrainedBox( 18 | constraints: BoxConstraints.expand(), 19 | child: Stack( 20 | alignment: Alignment.center, //指定未定位或部分定位widget的对齐方式 21 | fit: StackFit.expand, //未定位widget占满Stack整个空间 22 | children: [ 23 | //未定位,撑满 24 | Container( 25 | //这里设置容器的对齐方式 26 | alignment: Alignment.center, 27 | child: Text("未进行定位", style: TextStyle(color: Colors.white)), 28 | color: Colors.red, 29 | ), 30 | //未设置方向的默认是Stack中设置的居中对齐 31 | Positioned( 32 | left: 18.0, 33 | child: Text("左侧18dp处"), 34 | ), 35 | Positioned( 36 | top: 18.0, 37 | child: Text("顶部18dp处"), 38 | ), 39 | Positioned( 40 | bottom: 100, 41 | right: 50, 42 | child: Text("底部100dp,右侧50dp处"), 43 | ), 44 | ], 45 | ), 46 | )); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/notification.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NotificationPage extends StatefulWidget { 4 | NotificationPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _NotificationPageState createState() => _NotificationPageState(); 8 | } 9 | 10 | class _NotificationPageState extends State { 11 | String _msg = ""; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | ), 19 | body: NotificationListener( 20 | onNotification: (notification) { 21 | setState(() { 22 | _msg += notification.msg + " "; 23 | }); 24 | return true; 25 | }, 26 | child: Center( 27 | child: Column( 28 | mainAxisSize: MainAxisSize.min, 29 | children: [ 30 | // RaisedButton( 31 | // onPressed: () => TestNotification("这是通知内容~~").dispatch(context), 32 | // child: Text("发出通知"), 33 | // ), 34 | //这个context是根Context,而NotificationListener是监听的子树,所以我们通过Builder来构建RaisedButton,来获得按钮位置的context。 35 | Builder( 36 | builder: (context) { 37 | return RaisedButton( 38 | //按钮点击时分发通知 39 | onPressed: () => 40 | TestNotification("这是通知内容~~").dispatch(context), 41 | child: Text("发出通知"), 42 | textColor: Colors.white, 43 | ); 44 | }, 45 | ), 46 | Text(_msg) 47 | ], 48 | ), 49 | ), 50 | )); 51 | } 52 | } 53 | 54 | ///自定义冒泡通知 55 | class TestNotification extends Notification { 56 | TestNotification(this.msg); 57 | final String msg; 58 | } 59 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/scrollview/custom_scrollview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomScrollViewPage extends StatefulWidget { 4 | CustomScrollViewPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _CustomScrollViewPageState createState() => _CustomScrollViewPageState(); 8 | } 9 | 10 | class _CustomScrollViewPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Material( 14 | child: CustomScrollView( 15 | slivers: [ 16 | //AppBar,包含一个导航栏 17 | SliverAppBar( 18 | pinned: true, 19 | expandedHeight: 250.0, 20 | flexibleSpace: FlexibleSpaceBar( 21 | title: const Text('Demo'), 22 | background: Image.asset( 23 | "assets/images/scenery.jpg", 24 | fit: BoxFit.cover, 25 | ), 26 | ), 27 | ), 28 | 29 | //=====网格=====// 30 | SliverPadding( 31 | padding: const EdgeInsets.all(8.0), 32 | sliver: SliverGrid( 33 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 34 | crossAxisCount: 2, //Grid按两列显示 35 | mainAxisSpacing: 10.0, 36 | crossAxisSpacing: 10.0, 37 | childAspectRatio: 4.0, 38 | ), 39 | delegate: SliverChildBuilderDelegate( 40 | (BuildContext context, int index) { 41 | //创建子widget 42 | return Container( 43 | alignment: Alignment.center, 44 | color: Colors.cyan[100 * (index % 9)], 45 | child: Text('grid item $index'), 46 | ); 47 | }, 48 | childCount: 20, 49 | ), 50 | ), 51 | ), 52 | 53 | //=====列表=====// 54 | SliverFixedExtentList( 55 | itemExtent: 50.0, 56 | delegate: 57 | SliverChildBuilderDelegate((BuildContext context, int index) { 58 | //创建列表项 59 | return Container( 60 | alignment: Alignment.center, 61 | color: Colors.lightBlue[100 * (index % 9)], 62 | child: Text('list item $index'), 63 | ); 64 | }, childCount: 30 //30个列表项 65 | ), 66 | ), 67 | ], 68 | )); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/scrollview/scroll_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScrollControllerPage extends StatefulWidget { 4 | ScrollControllerPage(this.title, { Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _ScrollControllerPageState createState() => _ScrollControllerPageState(); 8 | } 9 | 10 | class _ScrollControllerPageState extends State { 11 | ScrollController _controller = ScrollController(); 12 | bool _showButton = false; //是否显示“返回到顶部”按钮 13 | String _progress = "0%"; //保存进度百分比 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | //监听滚动事件,打印滚动位置 19 | _controller.addListener(() { 20 | if (_controller.offset < 1000 && _showButton) { 21 | setState(() { 22 | _showButton = false; 23 | }); 24 | } else if (_controller.offset >= 1000 && !_showButton) { 25 | setState(() { 26 | _showButton = true; 27 | }); 28 | } 29 | }); 30 | } 31 | 32 | @override 33 | void dispose() { 34 | //为了避免内存泄露,需要调用_controller.dispose 35 | _controller.dispose(); 36 | super.dispose(); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return Scaffold( 42 | appBar: AppBar( 43 | title: Text(widget.title), 44 | ), 45 | body: Scrollbar( 46 | //进度条 47 | // 监听滚动通知 48 | child: NotificationListener( 49 | onNotification: (ScrollNotification notification) { 50 | double progress = notification.metrics.pixels / 51 | notification.metrics.maxScrollExtent; 52 | //重新构建 53 | if (progress >= 0) { 54 | setState(() { 55 | _progress = "${(progress * 100).toInt()}%"; 56 | }); 57 | } 58 | return false; 59 | //return true; //放开此行注释后,进度条将失效 60 | }, 61 | child: Stack( 62 | alignment: Alignment.center, 63 | children: [ 64 | ListView.builder( 65 | itemCount: 100, 66 | itemExtent: 50.0, 67 | controller: _controller, 68 | itemBuilder: (context, index) { 69 | return ListTile(title: Text("$index")); 70 | }), 71 | CircleAvatar( 72 | //显示进度百分比 73 | radius: 30.0, 74 | child: Text(_progress), 75 | backgroundColor: Colors.black54, 76 | ) 77 | ], 78 | ), 79 | ), 80 | ), 81 | floatingActionButton: !_showButton 82 | ? null 83 | : FloatingActionButton( 84 | child: Icon(Icons.arrow_upward), 85 | onPressed: () { 86 | //返回到顶部时执行动画 87 | _controller.animateTo(.0, 88 | duration: Duration(milliseconds: 400), curve: Curves.ease); 89 | }), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /flutter_learn/lib/page/widget/tab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TabPage extends StatefulWidget { 4 | TabPage(this.title, {Key key}) : super(key: key); 5 | final String title; 6 | @override 7 | _TabPageState createState() => _TabPageState(); 8 | } 9 | 10 | class _TabPageState extends State with SingleTickerProviderStateMixin { 11 | final List mTabs = [ 12 | Tab(text: '语文'), 13 | Tab(text: '数学'), 14 | Tab(text: '英语') 15 | ]; 16 | 17 | TabController _tabController; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | _tabController = TabController(vsync: this, length: mTabs.length); 23 | } 24 | 25 | @override 26 | void dispose() { 27 | _tabController.dispose(); 28 | super.dispose(); 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return Scaffold( 34 | appBar: AppBar( 35 | title: Text(widget.title), 36 | bottom: TabBar( 37 | controller: _tabController, 38 | tabs: mTabs, 39 | ), 40 | ), 41 | body: TabBarView( 42 | controller: _tabController, 43 | children: mTabs.map((Tab tab) { 44 | return Center(child: Text(tab.text)); 45 | }).toList(), 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /flutter_learn/lib/router/router.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_learn/router/switch_animation.dart'; 4 | import 'package:flutter_learn/view/web_view_page.dart'; 5 | import 'package:umeng_analytics_plugin/umeng_analytics_plugin.dart'; 6 | 7 | class XRouter { 8 | static FluroRouter router; 9 | 10 | static void init() { 11 | router = FluroRouter(); 12 | configureRoutes(router); 13 | } 14 | 15 | static void configureRoutes(FluroRouter router) { 16 | router.notFoundHandler = Handler( 17 | handlerFunc: (BuildContext context, Map> params) { 18 | print("route is not find !"); 19 | return null; 20 | }); 21 | 22 | router.define('/web', handler: webViewPageHand); 23 | } 24 | 25 | static void goto(BuildContext context, String pageName) { 26 | Navigator.push(context, SlidePageRoute(routeName: pageName)); 27 | } 28 | 29 | static void gotoWidget(BuildContext context, Widget widget) { 30 | Navigator.push(context, SlidePageRoute(widget: widget)); 31 | } 32 | } 33 | 34 | Handler webViewPageHand = Handler( 35 | handlerFunc: (BuildContext context, Map> params) { 36 | String title = params['title']?.first; 37 | String url = params['url']?.first; 38 | return WebViewPage(url, title); 39 | }); 40 | 41 | class AppAnalysis extends NavigatorObserver { 42 | @override 43 | void didPush(Route route, Route previousRoute) { 44 | if (previousRoute.settings.name != null) { 45 | UmengAnalyticsPlugin.pageEnd(previousRoute.settings.name); 46 | } 47 | 48 | if (route.settings.name != null) { 49 | UmengAnalyticsPlugin.pageStart(route.settings.name); 50 | } 51 | } 52 | 53 | @override 54 | void didPop(Route route, Route previousRoute) { 55 | if (route.settings.name != null) { 56 | UmengAnalyticsPlugin.pageEnd(route.settings.name); 57 | } 58 | 59 | if (previousRoute.settings.name != null) { 60 | UmengAnalyticsPlugin.pageStart(previousRoute.settings.name); 61 | } 62 | } 63 | 64 | @override 65 | void didReplace({Route newRoute, Route oldRoute}) { 66 | if (oldRoute.settings.name != null) { 67 | UmengAnalyticsPlugin.pageEnd(oldRoute.settings.name); 68 | } 69 | 70 | if (newRoute.settings.name != null) { 71 | UmengAnalyticsPlugin.pageStart(newRoute.settings.name); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /flutter_learn/lib/router/switch_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/router/route.dart'; 3 | 4 | //右进右出动画 5 | class SlidePageRoute extends PageRouteBuilder { 6 | final String routeName; 7 | final Widget widget; 8 | 9 | SlidePageRoute({this.routeName, this.widget}) 10 | : super( 11 | transitionDuration: const Duration(milliseconds: 500), 12 | pageBuilder: (BuildContext context, Animation animation1, 13 | Animation animation2) { 14 | return widget != null ? widget : RouteMap.routes[routeName](context); 15 | }, 16 | transitionsBuilder: (BuildContext context, 17 | Animation animation1, 18 | Animation animation2, 19 | Widget child) { 20 | return SlideTransition( 21 | position: Tween( 22 | //1.0为右进右出,-1.0为左进左出 23 | begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)) 24 | .animate(CurvedAnimation( 25 | parent: animation1, curve: Curves.fastOutSlowIn)), 26 | child: child, 27 | ); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/bugly.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter_bugly/flutter_bugly.dart'; 3 | import 'package:flutter_learn/utils/device.dart'; 4 | 5 | class Bugly { 6 | Bugly._internal(); 7 | 8 | static const String BUGLY_APP_ID_ANDROID = "ee68b0a303"; 9 | static const String BUGLY_APP_ID_IOS = "79aa609366"; 10 | 11 | //============================统计==================================// 12 | 13 | ///初始化Bugly 14 | static void init() { 15 | FlutterBugly.init( 16 | androidAppId: BUGLY_APP_ID_ANDROID, 17 | iOSAppId: BUGLY_APP_ID_IOS, 18 | channel: "github") 19 | .then((_result) { 20 | print("Bugly初始化结果: " + _result.appId); 21 | }); 22 | //初始化UserId 23 | DeviceUtils.getDeviceID().then((deviceID) { 24 | print("Bugly初始化UserId: $deviceID"); 25 | FlutterBugly.setUserId(deviceID); 26 | }); 27 | //同步设备信息 28 | DeviceUtils.getDeviceInfo().then((deviceInfo) { 29 | print("Bugly同步设备信息: $deviceInfo"); 30 | FlutterBugly.putUserData(key: "deviceInfo", value: deviceInfo.toString()); 31 | }); 32 | } 33 | 34 | ///自定义渠道标识 android专用 35 | static Future setAppChannel(String channel) { 36 | return FlutterBugly.setAppChannel(channel); 37 | } 38 | 39 | ///设置用户标识 40 | static Future setUserId(String userId) { 41 | return FlutterBugly.setUserId(userId); 42 | } 43 | 44 | ///设置标签 45 | ///userTag 标签ID,可在网站生成 46 | static Future setUserTag(int userTag) { 47 | return FlutterBugly.setUserTag(userTag); 48 | } 49 | 50 | ///设置关键数据,随崩溃信息上报 51 | static Future putUserData(String key, String value) { 52 | return FlutterBugly.putUserData(key: key, value: value); 53 | } 54 | 55 | //============================更新==================================// 56 | 57 | ///检查更新 58 | static Future checkUpgrade() { 59 | return FlutterBugly.checkUpgrade(); 60 | } 61 | 62 | //============================日志上传==================================// 63 | 64 | ///手动上报自定义异常信息 65 | static Future uploadException( 66 | String title, //标题 67 | String detail, //内容 68 | {Map data} //data为文本附件, Android 错误分析=>跟踪数据=>extraMessage.txt 69 | //iOS 错误分析=>跟踪数据=>crash_attach.log 70 | ) { 71 | return FlutterBugly.uploadException( 72 | message: title, detail: detail, data: data); 73 | } 74 | 75 | ///异常上报 76 | static void postCatchedException( 77 | T callback(), { 78 | FlutterExceptionHandler handler, //异常捕捉,用于自定义打印异常 79 | String filterRegExp, //异常上报过滤正则,针对message 80 | bool debugUpload = false, 81 | }) { 82 | return FlutterBugly.postCatchedException(callback, 83 | handler: handler, filterRegExp: filterRegExp, debugUpload: debugUpload); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/camera.dart: -------------------------------------------------------------------------------- 1 | import 'package:camera/camera.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CameraUtils { 5 | CameraUtils._internal(); 6 | 7 | static List cameras; 8 | 9 | static Future> init() async { 10 | if (cameras == null) { 11 | cameras = await getAvailableCameras(); 12 | } 13 | return cameras; 14 | } 15 | 16 | ///获取可使用的摄像头 17 | static Future> getAvailableCameras() => 18 | availableCameras(); 19 | 20 | /// 获取不同摄像头的图标(前置、后置、其它) 21 | static IconData getCameraLensIcon(CameraLensDirection direction) { 22 | switch (direction) { 23 | case CameraLensDirection.back: 24 | return Icons.camera_rear; 25 | case CameraLensDirection.front: 26 | return Icons.camera_front; 27 | case CameraLensDirection.external: 28 | return Icons.camera; 29 | } 30 | throw ArgumentError('Unknown lens direction'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/click.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/utils/toast.dart'; 3 | 4 | class ClickUtils { 5 | ClickUtils._internal(); 6 | 7 | static DateTime _lastPressedAt; //上次点击时间 8 | 9 | //双击返回 10 | static Future exitBy2Click( 11 | {int duration = 1000, ScaffoldState status}) async { 12 | if (status != null && status.isDrawerOpen) { 13 | return Future.value(true); 14 | } 15 | 16 | if (_lastPressedAt == null || 17 | DateTime.now().difference(_lastPressedAt) > 18 | Duration(milliseconds: duration)) { 19 | //两次点击间隔超过1秒则重新计时 20 | XToast.toast("再按一次退出程序"); 21 | _lastPressedAt = DateTime.now(); 22 | return Future.value(false); 23 | } 24 | return Future.value(true); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DialogUtils { 4 | DialogUtils._internal(); 5 | 6 | static Future show(BuildContext context, Widget dialog, 7 | {bool dismissible = false}) { 8 | return showDialog( 9 | context: context, 10 | barrierDismissible: dismissible, 11 | builder: (BuildContext context) { 12 | return WillPopScope( 13 | onWillPop: () => Future.value(dismissible), child: dialog); 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/download.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_downloader/flutter_downloader.dart'; 2 | 3 | class DownloadUtils { 4 | DownloadUtils._internal(); 5 | 6 | static init() { 7 | FlutterDownloader.initialize(debug: true); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/event.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:event_bus/event_bus.dart'; 4 | 5 | //EventBus工具类 6 | class XEvent { 7 | XEvent._internal(); 8 | 9 | static Map sEventPool = {}; 10 | 11 | static Map> sStreamPool = {}; 12 | 13 | static EventBus getEvent(String eventName, {bool isSync = false}) { 14 | EventBus event = sEventPool[eventName]; 15 | if (event == null) { 16 | event = new EventBus(sync: isSync); 17 | sEventPool[eventName] = event; 18 | } 19 | return event; 20 | } 21 | 22 | //订阅信息, 默认是异步的 23 | static StreamSubscription on(String eventName, void onData(T event), 24 | {bool isSync = false, 25 | Function onError, 26 | void onDone(), 27 | bool cancelOnError}) { 28 | StreamSubscription stream = getEvent(eventName, isSync: isSync) 29 | .on() 30 | .listen(onData, 31 | onError: onError, onDone: onDone, cancelOnError: cancelOnError); 32 | 33 | List streams = sStreamPool[eventName]; 34 | if (streams == null) { 35 | streams = []; 36 | streams.add(stream); 37 | sStreamPool[eventName] = streams; 38 | } else { 39 | streams.add(stream); 40 | } 41 | return stream; 42 | } 43 | 44 | //事件发送 45 | static void post(String eventName, event) { 46 | EventBus eventBus = getEvent(eventName); 47 | eventBus.fire(event); 48 | } 49 | 50 | //订阅取消 51 | static void cancelAll(String eventName) { 52 | List streams = sStreamPool[eventName]; 53 | if (streams != null) { 54 | for (StreamSubscription item in streams) { 55 | item.cancel(); 56 | } 57 | streams.clear(); 58 | } 59 | } 60 | 61 | //订阅取消 62 | static void cancel(String eventName, StreamSubscription subscription) { 63 | if (subscription == null) return; 64 | List streams = sStreamPool[eventName]; 65 | if (streams != null) { 66 | subscription.cancel(); 67 | streams.remove(subscription); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/http.dart: -------------------------------------------------------------------------------- 1 | import 'package:cookie_jar/cookie_jar.dart'; 2 | import 'package:dio/dio.dart'; 3 | import 'package:dio_cookie_manager/dio_cookie_manager.dart'; 4 | import 'package:flutter_learn/utils/path.dart'; 5 | 6 | class XHttp { 7 | XHttp._internal(); 8 | 9 | static final Dio dio = Dio(BaseOptions( 10 | baseUrl: "https://www.wanandroid.com", 11 | connectTimeout: 5000, 12 | receiveTimeout: 3000, 13 | )); 14 | 15 | ///初始化dio 16 | static init() { 17 | ///初始化cookie 18 | PathUtils.getDocumentsDirPath().then((value) { 19 | var cookieJar = PersistCookieJar(dir: value + "/.cookies/"); 20 | dio.interceptors.add(CookieManager(cookieJar)); 21 | }); 22 | 23 | //添加拦截器 24 | dio.interceptors 25 | .add(InterceptorsWrapper(onRequest: (RequestOptions options) { 26 | print("请求之前"); 27 | return options; 28 | }, onResponse: (Response response) { 29 | print("响应之前"); 30 | return response; 31 | }, onError: (DioError e) { 32 | print("错误之前"); 33 | handleError(e); 34 | return e; 35 | })); 36 | } 37 | 38 | ///error统一处理 39 | static void handleError(DioError e) { 40 | switch (e.type) { 41 | case DioErrorType.CONNECT_TIMEOUT: 42 | print("连接超时"); 43 | break; 44 | case DioErrorType.SEND_TIMEOUT: 45 | print("请求超时"); 46 | break; 47 | case DioErrorType.RECEIVE_TIMEOUT: 48 | print("响应超时"); 49 | break; 50 | case DioErrorType.RESPONSE: 51 | print("出现异常"); 52 | break; 53 | case DioErrorType.CANCEL: 54 | print("请求取消"); 55 | break; 56 | default: 57 | print("未知错误"); 58 | break; 59 | } 60 | } 61 | 62 | ///get请求 63 | static Future get(String url, [Map params]) async { 64 | Response response; 65 | if (params != null) { 66 | response = await dio.get(url, queryParameters: params); 67 | } else { 68 | response = await dio.get(url); 69 | } 70 | return response.data; 71 | } 72 | 73 | ///post 表单请求 74 | static Future post(String url, [Map params]) async { 75 | Response response = await dio.post(url, queryParameters: params); 76 | return response.data; 77 | } 78 | 79 | ///post body请求 80 | static Future postJson(String url, [Map data]) async { 81 | Response response = await dio.post(url, data: data); 82 | return response.data; 83 | } 84 | 85 | ///下载文件 86 | static Future downloadFile(urlPath, savePath) async { 87 | Response response; 88 | try { 89 | response = await dio.download(urlPath, savePath, 90 | onReceiveProgress: (int count, int total) { 91 | //进度 92 | print("$count $total"); 93 | }); 94 | } on DioError catch (e) { 95 | handleError(e); 96 | } 97 | return response.data; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/notification.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 4 | 5 | import 'oktoast.dart'; 6 | 7 | const CHANNEL_ID = 'channel_id_flutter'; 8 | const CHANNEL_NAME = 'channel_name_flutter'; 9 | const CHANNEL_DESCRIPTION = 'channel_description_flutter'; 10 | 11 | ///通知栏消息工具 12 | class NotificationUtils { 13 | NotificationUtils._internal(); 14 | 15 | static final FlutterLocalNotificationsPlugin plugin = 16 | FlutterLocalNotificationsPlugin(); 17 | 18 | static bool hasInit = false; 19 | 20 | static void init() { 21 | if (!hasInit) { 22 | ///Android初始化项 23 | var initializationSettingsAndroid = 24 | AndroidInitializationSettings('ic_splash_app_logo'); 25 | 26 | ///IOS初始化项 27 | var initializationSettingsIOS = IOSInitializationSettings( 28 | onDidReceiveLocalNotification: onDidReceiveLocalNotification); 29 | var initializationSettings = InitializationSettings( 30 | initializationSettingsAndroid, initializationSettingsIOS); 31 | plugin.initialize(initializationSettings, 32 | onSelectNotification: onSelectNotification); 33 | hasInit = true; 34 | } 35 | } 36 | 37 | ///IOS申请通知权限 38 | static void requestIOSPermissions() { 39 | if (Platform.isIOS) { 40 | plugin 41 | .resolvePlatformSpecificImplementation< 42 | IOSFlutterLocalNotificationsPlugin>() 43 | ?.requestPermissions( 44 | alert: true, 45 | badge: true, 46 | sound: true, 47 | ); 48 | } 49 | } 50 | 51 | ///IOS 52 | static Future onDidReceiveLocalNotification( 53 | int id, String title, String body, String payload) async { 54 | print('onDidReceiveLocalNotification:$payload'); 55 | ToastUtils.toast('点击通知:$payload'); 56 | } 57 | 58 | ///点击事件 59 | static Future onSelectNotification(String payload) async { 60 | print('onSelectNotification:$payload'); 61 | ToastUtils.toast('点击通知:$payload'); 62 | } 63 | 64 | ///发送普通消息 65 | static Future showNotification(int id, String title, String body, 66 | {String ticker, String payload}) { 67 | var androidPlatformChannelSpecifics = AndroidNotificationDetails( 68 | CHANNEL_ID, CHANNEL_NAME, CHANNEL_DESCRIPTION, 69 | importance: Importance.Max, priority: Priority.High, ticker: ticker); 70 | var iOSPlatformChannelSpecifics = IOSNotificationDetails(); 71 | var platformChannelSpecifics = NotificationDetails( 72 | androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); 73 | return NotificationUtils.plugin 74 | .show(id, title, body, platformChannelSpecifics, payload: payload); 75 | } 76 | 77 | ///取消所有通知 78 | static Future cancelAll() { 79 | return NotificationUtils.plugin.cancelAll(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/oktoast.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:oktoast/oktoast.dart'; 3 | 4 | const DEFAULT_TOAST_DURATION = Duration(seconds: 2); 5 | const DEFAULT_TOAST_COLOR = Color(0xFF424242); 6 | 7 | class ToastUtils { 8 | ToastUtils._internal(); 9 | 10 | ///全局初始化Toast配置, child为MaterialApp 11 | static init(Widget child) { 12 | return OKToast( 13 | ///字体大小 14 | textStyle: TextStyle(fontSize: 16, color: Colors.white), 15 | backgroundColor: DEFAULT_TOAST_COLOR, 16 | radius: 10, 17 | dismissOtherOnShow: true, 18 | textPadding: EdgeInsets.fromLTRB(20, 10, 20, 10), 19 | child: child, 20 | duration: DEFAULT_TOAST_DURATION, 21 | ); 22 | } 23 | 24 | static void toast(String msg, 25 | {Duration duration = DEFAULT_TOAST_DURATION, 26 | Color color = DEFAULT_TOAST_COLOR}) { 27 | showToast(msg, duration: duration, backgroundColor: color); 28 | } 29 | 30 | static void waring(String msg, {Duration duration = DEFAULT_TOAST_DURATION}) { 31 | showToast(msg, duration: duration, backgroundColor: Colors.yellow); 32 | } 33 | 34 | static void error(String msg, {Duration duration = DEFAULT_TOAST_DURATION}) { 35 | showToast(msg, duration: duration, backgroundColor: Colors.red); 36 | } 37 | 38 | static void success(String msg, 39 | {Duration duration = DEFAULT_TOAST_DURATION}) { 40 | showToast(msg, duration: duration, backgroundColor: Colors.lightGreen); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/path.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path_provider/path_provider.dart'; 4 | 5 | ///文件路径工具类 6 | class PathUtils { 7 | PathUtils._internal(); 8 | 9 | ///获取缓存目录路径 10 | static Future getCacheDirPath() async { 11 | Directory directory = await getTemporaryDirectory(); 12 | return directory.path; 13 | } 14 | 15 | ///获取文件缓存目录路径 16 | static Future getFilesDirPath() async { 17 | Directory directory = await getApplicationSupportDirectory(); 18 | return directory.path; 19 | } 20 | 21 | ///获取文档存储目录路径 22 | static Future getDocumentsDirPath() async { 23 | Directory directory = await getApplicationDocumentsDirectory(); 24 | return directory.path; 25 | } 26 | 27 | ///获取下载缓存路径 28 | static Future getDownloadDirPath() async { 29 | Directory directory = Platform.isAndroid 30 | ? await getExternalStorageDirectory() 31 | : await getApplicationDocumentsDirectory(); 32 | return directory.path; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/shared_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class SPUtils { 4 | /// 内部构造方法,可避免外部暴露构造函数,进行实例化 5 | SPUtils._internal(); 6 | 7 | static SharedPreferences _spf; 8 | 9 | static Future init() async { 10 | if (_spf == null) { 11 | _spf = await SharedPreferences.getInstance(); 12 | } 13 | return _spf; 14 | } 15 | 16 | static String getString(String key) { 17 | return _spf.getString(key); 18 | } 19 | 20 | static Future putString(String key, String value) { 21 | return _spf.setString(key, value); 22 | } 23 | 24 | static bool getBool(String key) { 25 | return _spf.getBool(key); 26 | } 27 | 28 | static Future putBool(String key, bool value) { 29 | return _spf.setBool(key, value); 30 | } 31 | 32 | static int getInt(String key) { 33 | return _spf.getInt(key); 34 | } 35 | 36 | static Future putInt(String key, int value) { 37 | return _spf.setInt(key, value); 38 | } 39 | 40 | static Future saveThemeColorIndex(int value) { 41 | return _spf.setInt('key_theme_color', value); 42 | } 43 | 44 | static int getThemeColorIndex() { 45 | if (_spf.containsKey('key_theme_color')) { 46 | return _spf.getInt('key_theme_color'); 47 | } 48 | return 0; 49 | } 50 | 51 | static Future saveLocale(String locale) { 52 | return _spf.setString('key_locale', locale); 53 | } 54 | 55 | static String getLocale() { 56 | return _spf.getString('key_locale'); 57 | } 58 | 59 | static Future saveNickName(String nickName) { 60 | return _spf.setString('key_nickname', nickName); 61 | } 62 | 63 | static String getNickName() { 64 | return _spf.getString('key_nickname'); 65 | } 66 | 67 | static Future saveAppBadgeNumber(int number) { 68 | return _spf.setInt('key_App_Badge_number', number); 69 | } 70 | 71 | static int getAppBadgeNumber() { 72 | int result = _spf.getInt('key_App_Badge_number'); 73 | return result == null ? 0 : result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/sql_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:path/path.dart'; 6 | import 'package:sqflite/sqflite.dart'; 7 | import 'package:flutter/services.dart' show rootBundle; 8 | 9 | class SQLHelper { 10 | static Database db; 11 | 12 | // 获取数据库中所有的表 13 | static Future getTables() async { 14 | if (db == null) { 15 | return Future.value([]); 16 | } 17 | List tables = await db 18 | .rawQuery('SELECT name FROM sqlite_master WHERE type = "table"'); 19 | List targetList = []; 20 | tables.forEach((item) { 21 | targetList.add(item['name']); 22 | }); 23 | return targetList; 24 | } 25 | 26 | //当前存在的表 27 | static List expectTables = ['userInfo', 'collection']; 28 | 29 | // 检查数据库中, 表是否完整, 在部份android中, 会出现表丢失的情况 30 | static Future checkTableIsRight() async { 31 | List tables = await getTables(); 32 | for (int i = 0; i < expectTables.length; i++) { 33 | if (!tables.contains(expectTables[i])) { 34 | return false; 35 | } 36 | } 37 | return true; 38 | } 39 | 40 | //初始化数据库 41 | static Future init() async { 42 | //Get a location using getDatabasesPath 43 | String databasesPath = await getDatabasesPath(); 44 | String path = join(databasesPath, 'flutter.db'); 45 | print(path); 46 | try { 47 | db = await openDatabase(path); 48 | } catch (e) { 49 | print("Error $e"); 50 | } 51 | bool tableIsRight = await checkTableIsRight(); 52 | 53 | if (!tableIsRight) { 54 | // 关闭上面打开的db,否则无法执行open 55 | db.close(); 56 | // Delete the database 57 | await deleteDatabase(path); 58 | 59 | db = await openDatabase(path, version: 1, 60 | onCreate: (Database db, int version) async { 61 | print('db created version is $version'); 62 | createDB(db); 63 | }, onOpen: (Database db) async { 64 | print('new db opened'); 65 | }); 66 | } else { 67 | print("Opening existing database"); 68 | } 69 | } 70 | 71 | //创建数据库 72 | static void createDB(Database db) { 73 | db.execute(createSql['userInfo'], null); 74 | db.execute(createSql['collection'], null); 75 | } 76 | 77 | //拷贝数据库 78 | static Future copyDB(String dbPath) async { 79 | ByteData data = await rootBundle.load(join("assets", "app.db")); 80 | List bytes = 81 | data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 82 | await new File(dbPath).writeAsBytes(bytes); 83 | } 84 | } 85 | 86 | //数据库创建脚本 87 | const createSql = { 88 | 'userInfo': """ 89 | CREATE TABLE IF NOT EXISTS userInfo ( 90 | id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 91 | userName TEXT NOT NULL UNIQUE, 92 | password TEXT NOT NULL, 93 | nickName TEXT, 94 | age INTEGER NOT NULL DEFAULT 20, 95 | sex INTEGER NOT NULL DEFAULT 0 96 | ) 97 | """, 98 | 'collection': """ 99 | CREATE TABLE IF NOT EXISTS collection (id INTEGER PRIMARY KEY NOT NULL UNIQUE, name TEXT NOT NULL, router TEXT) 100 | """, 101 | }; 102 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttertoast/fluttertoast.dart'; 3 | 4 | class XToast { 5 | XToast._internal(); 6 | 7 | static void toast(String msg, {Toast length = Toast.LENGTH_SHORT}) { 8 | Fluttertoast.cancel(); 9 | Fluttertoast.showToast( 10 | msg: msg, 11 | toastLength: length, 12 | gravity: ToastGravity.CENTER, 13 | backgroundColor: Colors.grey[800], 14 | textColor: Colors.white, 15 | fontSize: 16.0); 16 | } 17 | 18 | static void waring(String msg, {Toast length = Toast.LENGTH_SHORT}) { 19 | Fluttertoast.cancel(); 20 | Fluttertoast.showToast( 21 | msg: msg, 22 | toastLength: length, 23 | gravity: ToastGravity.CENTER, 24 | backgroundColor: Colors.yellow, 25 | textColor: Colors.white, 26 | fontSize: 16.0); 27 | } 28 | 29 | static void error(String msg, {Toast length = Toast.LENGTH_SHORT}) { 30 | Fluttertoast.cancel(); 31 | Fluttertoast.showToast( 32 | msg: msg, 33 | toastLength: length, 34 | gravity: ToastGravity.CENTER, 35 | backgroundColor: Colors.red, 36 | textColor: Colors.white, 37 | fontSize: 16.0); 38 | } 39 | 40 | static void success(String msg, {Toast toastLength = Toast.LENGTH_SHORT}) { 41 | Fluttertoast.cancel(); 42 | Fluttertoast.showToast( 43 | msg: msg, 44 | toastLength: toastLength, 45 | gravity: ToastGravity.CENTER, 46 | backgroundColor: Colors.lightGreen, 47 | textColor: Colors.white, 48 | fontSize: 16.0); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/umeng.dart: -------------------------------------------------------------------------------- 1 | import 'package:umeng_analytics_plugin/umeng_analytics_plugin.dart'; 2 | 3 | class UMeng { 4 | UMeng._internal(); 5 | 6 | static const String UMeng_APP_KEY_ANDROID = "5e382b330cafb2eacc0000a1"; 7 | static const String UMeng_APP_KEY_IOS = "5e3822f0570df3425700018c"; 8 | 9 | //============================统计==================================// 10 | 11 | ///初始化UMengSDK 12 | static Future init() { 13 | return UmengAnalyticsPlugin.init( 14 | androidKey: UMeng_APP_KEY_ANDROID, 15 | iosKey: UMeng_APP_KEY_IOS, 16 | channel: "github", 17 | logEnabled: true); 18 | } 19 | 20 | //============================事件埋点==================================// 21 | 22 | ///异常上报 23 | static Future event(String eventId, {String label}) { 24 | return UmengAnalyticsPlugin.event(eventId, label: label); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:battery/battery.dart'; 4 | import 'package:date_format/date_format.dart'; 5 | import 'package:flutter_learn/utils/toast.dart'; 6 | import 'package:package_info/package_info.dart'; 7 | import 'package:url_launcher/url_launcher.dart'; 8 | 9 | class Utils { 10 | Utils._internal(); 11 | 12 | static Battery _battery = Battery(); 13 | static StreamSubscription _subscription; 14 | 15 | //=============url_launcher==================// 16 | 17 | ///处理链接 18 | static void launchURL(String url) async { 19 | if (await canLaunch(url)) { 20 | await launch(url); 21 | } else { 22 | XToast.error("暂不能处理这条链接:$url"); 23 | } 24 | } 25 | 26 | //=============battery==================// 27 | 28 | ///获取电池电量 29 | static Future getBattery() { 30 | return _battery.batteryLevel; 31 | } 32 | 33 | ///注册电量变化 34 | static void registerBatteryChanged(void onData(BatteryState event)) { 35 | if (_subscription != null) { 36 | _subscription.cancel(); 37 | } 38 | _subscription = _battery.onBatteryStateChanged.listen(onData); 39 | } 40 | 41 | ///注销电量变化 42 | static void unregisterBatteryChanged() { 43 | if (_subscription != null) { 44 | _subscription.cancel(); 45 | } 46 | } 47 | 48 | //=============package_info==================// 49 | 50 | ///获取应用包信息 51 | static Future getPackageInfo() { 52 | return PackageInfo.fromPlatform(); 53 | } 54 | 55 | ///获取应用包信息 56 | static Future> getPackageInfoMap() async { 57 | PackageInfo packageInfo = await PackageInfo.fromPlatform(); 58 | return { 59 | 'appName': packageInfo.appName, 60 | 'packageName': packageInfo.packageName, 61 | 'version': packageInfo.version, 62 | 'buildNumber': packageInfo.buildNumber, 63 | }; 64 | } 65 | 66 | static String timestamp() => DateTime.now().millisecondsSinceEpoch.toString(); 67 | 68 | static String formatDateTime(DateTime dateTime) => formatDate(dateTime, [yyyy, '-', mm, '-', dd]); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/xuifont.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | //自定义字体库 4 | class XUIIcons { 5 | XUIIcons._internal(); 6 | 7 | static const List icons = [ 8 | file, 9 | chat, 10 | voice, 11 | delete, 12 | delete1, 13 | delete2, 14 | delete3, 15 | back, 16 | back1, 17 | add, 18 | add1, 19 | add2, 20 | reset, 21 | complete, 22 | complete1, 23 | collect, 24 | emoj, 25 | boy, 26 | girl, 27 | eye_on, 28 | eye_off, 29 | logout 30 | ]; 31 | 32 | static const IconData file = 33 | const IconData(0xe600, fontFamily: 'xuifont', matchTextDirection: true); 34 | static const IconData chat = 35 | const IconData(0xe601, fontFamily: 'xuifont', matchTextDirection: true); 36 | static const IconData voice = 37 | const IconData(0xe602, fontFamily: 'xuifont', matchTextDirection: true); 38 | static const IconData delete = 39 | const IconData(0xe603, fontFamily: 'xuifont', matchTextDirection: true); 40 | static const IconData delete1 = 41 | const IconData(0xe613, fontFamily: 'xuifont', matchTextDirection: true); 42 | static const IconData delete2 = 43 | const IconData(0xe630, fontFamily: 'xuifont', matchTextDirection: true); 44 | static const IconData delete3 = 45 | const IconData(0xe658, fontFamily: 'xuifont', matchTextDirection: true); 46 | static const IconData back = 47 | const IconData(0xe609, fontFamily: 'xuifont', matchTextDirection: true); 48 | static const IconData back1 = 49 | const IconData(0xe614, fontFamily: 'xuifont', matchTextDirection: true); 50 | static const IconData add = 51 | const IconData(0xe612, fontFamily: 'xuifont', matchTextDirection: true); 52 | static const IconData add1 = 53 | const IconData(0xe615, fontFamily: 'xuifont', matchTextDirection: true); 54 | static const IconData add2 = 55 | const IconData(0xe631, fontFamily: 'xuifont', matchTextDirection: true); 56 | static const IconData reset = 57 | const IconData(0xe616, fontFamily: 'xuifont', matchTextDirection: true); 58 | static const IconData complete = 59 | const IconData(0xe650, fontFamily: 'xuifont', matchTextDirection: true); 60 | static const IconData complete1 = 61 | const IconData(0xe673, fontFamily: 'xuifont', matchTextDirection: true); 62 | static const IconData collect = 63 | const IconData(0xe77f, fontFamily: 'xuifont', matchTextDirection: true); 64 | static const IconData emoj = 65 | const IconData(0xe628, fontFamily: 'xuifont', matchTextDirection: true); 66 | static const IconData boy = 67 | const IconData(0xe6c5, fontFamily: 'xuifont', matchTextDirection: true); 68 | static const IconData girl = 69 | const IconData(0xe61b, fontFamily: 'xuifont', matchTextDirection: true); 70 | static const IconData eye_on = 71 | const IconData(0xe632, fontFamily: 'xuifont', matchTextDirection: true); 72 | static const IconData eye_off = 73 | const IconData(0xe749, fontFamily: 'xuifont', matchTextDirection: true); 74 | static const IconData logout = 75 | const IconData(0xe723, fontFamily: 'xuifont', matchTextDirection: true); 76 | } 77 | -------------------------------------------------------------------------------- /flutter_learn/lib/utils/xupdate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_learn/utils/device.dart'; 2 | import 'package:flutter_learn/utils/toast.dart'; 3 | import 'package:flutter_xupdate/flutter_xupdate.dart'; 4 | 5 | class XUpdate { 6 | XUpdate._internal(); 7 | 8 | static const String UPDATE_URL = 9 | "https://gitee.com/xuexiangjys/FlutterSample/raw/master/flutter_learn/jsonapi/update_api.json"; 10 | 11 | static void initAndCheck() { 12 | if (DeviceUtils.isAndroid()) { 13 | init(url: UPDATE_URL); 14 | } 15 | } 16 | 17 | ///初始化XUpdate 18 | static void init({String url = ""}) { 19 | FlutterXUpdate.init( 20 | debug: true, 21 | enableRetry: true, 22 | retryContent: "Github下载速度太慢了,是否考虑切换蒲公英下载?", 23 | retryUrl: "https://www.pgyer.com/flutter_learn") 24 | .then((_result) { 25 | print("XUpdate初始化结果: $_result"); 26 | if (url.isNotEmpty) { 27 | checkUpdate(url); 28 | } 29 | }); 30 | FlutterXUpdate.setErrorHandler( 31 | onUpdateError: (Map message) async { 32 | ///2004是无最新版本 33 | if (message['code'] != 2004) { 34 | ///4000是下载失败 35 | if (message['code'] == 4000) { 36 | FlutterXUpdate.showRetryUpdateTipDialog( 37 | retryContent: "Github被墙无法继续下载,是否考虑切换蒲公英下载?", 38 | retryUrl: "https://www.pgyer.com/flutter_learn"); 39 | } else { 40 | XToast.error(message['detailMsg']); 41 | } 42 | } 43 | }); 44 | } 45 | 46 | ///初始化XUpdate 47 | static void checkUpdate(String url) { 48 | FlutterXUpdate.checkUpdate(url: url, widthRatio: 0.7); 49 | } 50 | 51 | ///初始化XUpdate 52 | static void checkUpdateWithErrorTip({String url = UPDATE_URL}) { 53 | FlutterXUpdate.setErrorHandler( 54 | onUpdateError: (Map message) async { 55 | ///4000是下载失败 56 | if (message['code'] == 4000) { 57 | FlutterXUpdate.showRetryUpdateTipDialog( 58 | retryContent: "Github被墙无法继续下载,是否考虑切换蒲公英下载?", 59 | retryUrl: "https://www.pgyer.com/flutter_learn"); 60 | } else { 61 | XToast.error(message['message']); 62 | } 63 | }); 64 | FlutterXUpdate.checkUpdate(url: url, widthRatio: 0.7); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/gridview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/router/router.dart'; 3 | import 'package:flutter_learn/view/listview_page.dart'; 4 | 5 | class GridViewPage extends StatefulWidget { 6 | GridViewPage({Key key, this.items}) : super(key: key); 7 | final List items; 8 | @override 9 | _GridViewPageState createState() => _GridViewPageState(); 10 | } 11 | 12 | class _GridViewPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Center( 16 | child: GridView.builder( 17 | padding: const EdgeInsets.all(10), 18 | itemCount: widget.items.length, 19 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 20 | //横轴元素个数 21 | crossAxisCount: 3, 22 | //纵轴间距 23 | mainAxisSpacing: 10.0, 24 | //横轴间距 25 | crossAxisSpacing: 10.0, 26 | //子组件宽高长度比例 27 | childAspectRatio: 1.0), 28 | itemBuilder: (BuildContext context, int index) { 29 | return getItemContainer(widget.items[index]); 30 | }), 31 | ); 32 | } 33 | 34 | Widget getItemContainer(ListItem item) { 35 | return InkWell( 36 | child: Container( 37 | alignment: Alignment.center, 38 | child: Column( 39 | children: [ 40 | Expanded( 41 | flex: 5, 42 | child: Icon( 43 | item.icon, 44 | color: Theme.of(context).primaryColor, 45 | ), 46 | ), 47 | Expanded( 48 | flex: 2, 49 | child: Text(item.title, style: TextStyle(fontSize: 12)), 50 | ), 51 | SizedBox(height: 15) 52 | ], 53 | ), 54 | decoration: BoxDecoration( 55 | border: Border.all( 56 | color: Color.fromRGBO(233, 233, 233, 0.9), width: 1)), 57 | ), 58 | onTap: () { 59 | XRouter.goto(context, item.pageName); 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/home/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/i10n/localization_intl.dart'; 3 | import 'package:flutter_learn/utils/provider.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class LanguagePage extends StatefulWidget { 7 | @override 8 | _LanguagePageState createState() => _LanguagePageState(); 9 | } 10 | 11 | class _LanguagePageState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | Color color = Theme.of(context).primaryColor; 15 | LocaleModel localeModel = Provider.of(context); 16 | Languages S = Languages.of(context); 17 | 18 | Widget _buildLanguageItem(String lan, value) { 19 | return ListTile( 20 | title: Text( 21 | lan, 22 | // 对APP当前语言进行高亮显示 23 | style: TextStyle(color: localeModel.locale == value ? color : null), 24 | ), 25 | trailing: 26 | localeModel.locale == value ? Icon(Icons.done, color: color) : null, 27 | onTap: () { 28 | // 此行代码会通知MaterialApp重新build 29 | localeModel.locale = value; 30 | }, 31 | ); 32 | } 33 | 34 | return Scaffold( 35 | appBar: AppBar(title: Text(S.language)), 36 | body: ListView( 37 | children: [ 38 | _buildLanguageItem(S.chinese, "zh_CN"), 39 | _buildLanguageItem(S.english, "en_US"), 40 | _buildLanguageItem(S.auto, null), 41 | ], 42 | )); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/home/theme_color.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/i10n/localization_intl.dart'; 3 | import 'package:flutter_learn/utils/provider.dart'; 4 | 5 | class ThemeColorPage extends StatefulWidget { 6 | @override 7 | _ThemeColorPageState createState() => _ThemeColorPageState(); 8 | } 9 | 10 | class _ThemeColorPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar(title: Text(Languages.of(context).theme)), 15 | body: GridView.builder( 16 | padding: const EdgeInsets.all(10), 17 | itemCount: AppTheme.materialColors.length, 18 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 19 | //横轴元素个数 20 | crossAxisCount: 3, 21 | //纵轴间距 22 | mainAxisSpacing: 10.0, 23 | //横轴间距 24 | crossAxisSpacing: 10.0, 25 | //子组件宽高长度比例 26 | childAspectRatio: 1.0), 27 | itemBuilder: (context, index) { 28 | return GestureDetector( 29 | onTap: () { 30 | Store.value(context).changeColor(index); 31 | }, 32 | child: Container(color: AppTheme.materialColors[index]), 33 | ); 34 | }, 35 | ), 36 | ); 37 | } 38 | 39 | void showColorDialog() { 40 | showDialog( 41 | context: context, 42 | barrierDismissible: false, // user must tap button! 43 | builder: (BuildContext context) { 44 | return Dialog( 45 | child: Container( 46 | height: 300, 47 | child: ListView.builder( 48 | itemCount: AppTheme.materialColors.length, 49 | itemBuilder: (context, index) { 50 | return GestureDetector( 51 | onTap: () { 52 | Store.value(context).changeColor(index); 53 | Navigator.of(context).pop(); 54 | }, 55 | child: Container( 56 | color: AppTheme.materialColors[index], height: 40)); 57 | }, 58 | ), 59 | )); 60 | }, 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/listview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/router/router.dart'; 3 | 4 | class ListViewPage extends StatefulWidget { 5 | ListViewPage({Key key, this.items}) : super(key: key); 6 | 7 | final List items; 8 | 9 | @override 10 | _ListViewPageState createState() => _ListViewPageState(); 11 | } 12 | 13 | class _ListViewPageState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Center( 17 | child: SizedBox( 18 | child: ListView.separated( 19 | scrollDirection: Axis.vertical, 20 | itemCount: widget.items.length, // item 的个数 21 | separatorBuilder: (BuildContext context, int index) => 22 | Divider(height: 1.0, color: Colors.grey), // 添加分割线 23 | itemBuilder: (BuildContext context, int index) { 24 | return ListTile( 25 | title: Text(widget.items[index].title), // item 标题 26 | leading: Icon(widget.items[index].icon), // item 前置图标 27 | subtitle: Text(widget.items[index].subTitle), // item 副标题 28 | trailing: Icon(Icons.keyboard_arrow_right), // item 后置图标 29 | isThreeLine: false, // item 是否三行显示 30 | dense: true, // item 直观感受是整体大小 31 | contentPadding: EdgeInsets.only( 32 | left: 20, right: 10, top: 5, bottom: 5), // item 内容内边距 33 | enabled: true, 34 | onTap: () { 35 | XRouter.goto(context, widget.items[index].pageName); 36 | }, 37 | onLongPress: () { 38 | print('长按:$index'); 39 | }, // item onLongPress 长按事件 40 | selected: false, // item 是否选中状态 41 | ); 42 | }, 43 | ), 44 | ), 45 | ); 46 | } 47 | } 48 | 49 | class ListItem { 50 | final IconData icon; 51 | final String title; 52 | final String subTitle; 53 | final String pageName; 54 | const ListItem(this.icon, this.title, this.subTitle, this.pageName); 55 | } 56 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/loading_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | //loading加载框 4 | class LoadingDialog extends Dialog { 5 | //loading动画 6 | final Widget loadingView; 7 | //提示内容 8 | final String content; 9 | //是否显示提示文字 10 | final bool showContent; 11 | //圆角大小 12 | final double radius; 13 | //背景颜色 14 | final Color backgroundColor; 15 | 16 | LoadingDialog( 17 | {Key key, 18 | this.loadingView, 19 | this.content = "加载中...", 20 | this.showContent = true, 21 | this.radius = 10, 22 | this.backgroundColor = Colors.white}) 23 | : super(key: key); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Material( 28 | type: MaterialType.transparency, 29 | child: Center( 30 | child: SizedBox( 31 | width: showContent ? 120 : 80, 32 | height: showContent ? 120 : 80, 33 | child: Container( 34 | decoration: ShapeDecoration( 35 | color: backgroundColor, 36 | shape: RoundedRectangleBorder( 37 | borderRadius: BorderRadius.all( 38 | Radius.circular(radius), 39 | ), 40 | ), 41 | ), 42 | child: Column( 43 | mainAxisAlignment: MainAxisAlignment.center, 44 | crossAxisAlignment: CrossAxisAlignment.center, 45 | children: [ 46 | loadingView == null ? CircularProgressIndicator() : loadingView, 47 | showContent 48 | ? Padding( 49 | padding: const EdgeInsets.only( 50 | top: 16, 51 | ), 52 | child: Text(content), 53 | ) 54 | : SizedBox(), 55 | ], 56 | ), 57 | ), 58 | ), 59 | ), 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/number_progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 带进度文字的圆角进度条 4 | class NumberProgress extends StatelessWidget { 5 | /// 进度条的高度 6 | final double height; 7 | 8 | /// 进度 9 | final double value; 10 | 11 | /// 进度条的背景颜色 12 | final Color backgroundColor; 13 | 14 | /// 进度条的色值 15 | final Color valueColor; 16 | 17 | /// 文字的颜色 18 | final Color textColor; 19 | 20 | /// 文字的大小 21 | final double textSize; 22 | 23 | /// 文字的对齐方式 24 | final AlignmentGeometry textAlignment; 25 | 26 | /// 边距 27 | final EdgeInsetsGeometry padding; 28 | 29 | NumberProgress( 30 | {Key key, 31 | this.height = 10.0, 32 | this.value = 0.0, 33 | this.backgroundColor, 34 | this.valueColor, 35 | this.textColor = Colors.white, 36 | this.textSize = 8.0, 37 | this.padding = EdgeInsets.zero, 38 | this.textAlignment = Alignment.center}) 39 | : super(key: key); 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return Padding( 44 | padding: padding, 45 | child: Stack( 46 | alignment: Alignment.center, 47 | children: [ 48 | SizedBox( 49 | height: height, 50 | child: ClipRRect( 51 | borderRadius: BorderRadius.all(Radius.circular(height)), 52 | child: LinearProgressIndicator( 53 | value: value, 54 | backgroundColor: backgroundColor, 55 | valueColor: AlwaysStoppedAnimation(valueColor), 56 | ), 57 | ), 58 | ), 59 | Container( 60 | height: height, 61 | alignment: textAlignment, 62 | child: Text( 63 | value >= 1 ? '100%' : '${(value * 100).toInt()}%', 64 | style: TextStyle( 65 | color: textColor, 66 | fontSize: textSize, 67 | ), 68 | ), 69 | ), 70 | ], 71 | )); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/simple_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_learn/view/listview_page.dart'; 3 | 4 | class SimpleListPage extends StatefulWidget { 5 | SimpleListPage(this.title, this.items, {Key key}) : super(key: key); 6 | final String title; 7 | final List items; 8 | @override 9 | _SimpleListPageState createState() => _SimpleListPageState(); 10 | } 11 | 12 | class _SimpleListPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(widget.title), 18 | ), 19 | body: Container( 20 | child: ListViewPage(items: widget.items))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /flutter_learn/lib/view/titlebar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | //自定义标题栏 4 | class TitleBar { 5 | 6 | /* 7 | * 仅含 左侧返回按钮 及中间标题 8 | * appBar: TitleBar().backAppbar(context, '个人资料'), 9 | * appBar: TitleBar().backAppbar(context, '个人资料',(){}), 10 | */ 11 | static backAppbar(BuildContext context, String title, { 12 | double heigth = 48, 13 | VoidCallback onPressed 14 | }) { 15 | return PreferredSize( 16 | preferredSize: Size.fromHeight(heigth), 17 | child: AppBar( 18 | title: Text( 19 | title, 20 | style: TextStyle(color: Colors.black, fontSize: 16), 21 | ), 22 | centerTitle: true, 23 | leading: _leading(context, onPressed), 24 | brightness: Brightness.light, 25 | backgroundColor: Colors.white, 26 | elevation: 0, 27 | iconTheme: IconThemeData(color: Colors.black), 28 | )); 29 | } 30 | 31 | static _leading(BuildContext context, VoidCallback onPressed) { 32 | return Column( 33 | mainAxisAlignment: MainAxisAlignment.center, 34 | crossAxisAlignment: CrossAxisAlignment.start, 35 | children: < Widget > [ 36 | Container( 37 | width: 44, 38 | padding: EdgeInsets.all(0), 39 | child: IconButton( 40 | padding: EdgeInsets.only(left: 16, right: 16), 41 | icon: Icon(Icons.chevron_left), 42 | onPressed: () { 43 | if (onPressed == null) { 44 | _popThis(context); 45 | } else { 46 | onPressed(); 47 | } 48 | }, 49 | ), 50 | ), 51 | ], 52 | ); 53 | } 54 | 55 | static _popThis(BuildContext context) { 56 | Navigator.of(context).pop(); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /flutter_learn/lib/view/web_view_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 5 | 6 | class WebViewPage extends StatefulWidget { 7 | final String url; 8 | final String title; 9 | 10 | WebViewPage(this.url, this.title); 11 | _WebViewPageState createState() => _WebViewPageState(); 12 | } 13 | 14 | class _WebViewPageState extends State { 15 | 16 | final GlobalKey _scaffoldKey = GlobalKey(); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | key: _scaffoldKey, 22 | appBar: AppBar( 23 | title: Text(widget.title), 24 | ), 25 | body: getWebView(widget.url), 26 | ); 27 | } 28 | 29 | Widget getWebView(String url) { 30 | return WebviewScaffold( 31 | url: widget.url, 32 | withZoom: false, 33 | withLocalStorage: true, 34 | withJavascript: true, 35 | hidden: true, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flutter_learn/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_learn/init/normal_app.dart'; 10 | import 'package:flutter_test/flutter_test.dart'; 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(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 | --------------------------------------------------------------------------------