├── .gitignore
├── .idea
├── checkstyle-idea.xml
├── codeStyles
│ └── Project.xml
├── libraries
│ ├── Dart_Packages.xml
│ ├── Dart_SDK.xml
│ ├── Flutter_Plugins.xml
│ └── Flutter_for_Android.xml
├── misc.xml
├── modules.xml
├── runConfigurations
│ └── main_dart.xml
├── vcs.xml
└── workspace.xml
├── .metadata
├── README.md
├── android
├── .gitignore
├── .idea
│ ├── caches
│ │ └── build_file_checksums.ser
│ ├── checkstyle-idea.xml
│ ├── codeStyles
│ │ └── Project.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── runConfigurations.xml
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── jzhu
│ │ │ └── flutterstudy
│ │ │ ├── MainActivity.java
│ │ │ ├── OneActivity.java
│ │ │ ├── TwoActivity.java
│ │ │ └── plugin
│ │ │ ├── FlutterPluginAMap.java
│ │ │ ├── FlutterPluginCounter.java
│ │ │ ├── FlutterPluginJumpToAct.java
│ │ │ └── FlutterPluginPermissions.java
│ │ └── res
│ │ ├── drawable
│ │ └── launch_background.xml
│ │ ├── layout
│ │ ├── activity_one.xml
│ │ └── activity_two.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ └── styles.xml
├── build.gradle
├── building_system
│ └── jz.jks
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── flutter_study.iml
├── flutter_study_android.iml
├── images
├── 2.0x
│ └── ic_assignment_ind_36pt.png
├── 3.0x
│ └── ic_assignment_ind_36pt.png
├── ic_assignment_ind_36pt.png
└── lifecycle.png
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── 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.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── lib
├── common
│ ├── constant.dart
│ └── widget
│ │ ├── common_webview.dart
│ │ └── progreess_dialog.dart
├── main.dart
├── model
│ ├── ai_model.dart
│ ├── base_model.dart
│ ├── fl_model.dart
│ ├── hot_news_model.dart
│ ├── inherited_test_model.dart
│ └── search_model.dart
├── mvp
│ ├── mvp.dart
│ ├── presenter
│ │ ├── ai_presenter.dart
│ │ ├── ai_presenter_impl.dart
│ │ ├── fl_presenter.dart
│ │ └── fl_presenter_impl.dart
│ └── repository
│ │ ├── ai_repository.dart
│ │ ├── ai_repository_impl.dart
│ │ ├── fl_repository.dart
│ │ └── fl_repository_impl.dart
├── theme
│ └── custom_theme.dart
├── util
│ ├── dio_factory.dart
│ ├── fix_url_util.dart
│ └── routes_util.dart
└── widget
│ ├── advanced_page.dart
│ ├── architecture_page.dart
│ ├── demo_admob
│ └── admob_page.dart
│ ├── demo_animation
│ └── animation_page.dart
│ ├── demo_base_widget
│ ├── base_widget_page.dart
│ └── container_page.dart
│ ├── demo_common
│ ├── hide_and_show_page.dart
│ └── test.dart
│ ├── demo_custom_toast
│ ├── blinking_toast.dart
│ ├── show_notification.dart
│ └── toast_page.dart
│ ├── demo_database
│ └── data_page.dart
│ ├── demo_gesture
│ ├── dismissed_page.dart
│ ├── drag_page.dart
│ ├── gesture_page.dart
│ └── multi_touch_page.dart
│ ├── demo_inherited
│ ├── inherited_w_page.dart
│ ├── inherited_w_test_a.dart
│ ├── inherited_w_test_b.dart
│ └── inherited_w_test_c.dart
│ ├── demo_key
│ └── globalkey_form_page.dart
│ ├── demo_lifecycle
│ └── lifecycle_page.dart
│ ├── demo_loadimg
│ ├── loadIm_by_loc_page.dart
│ ├── loadImg_by_net_page.dart
│ └── loadImg_page.dart
│ ├── demo_localizations
│ └── localizations_study.dart
│ ├── demo_native
│ └── channel_page.dart
│ ├── demo_network
│ └── network_page.dart
│ ├── demo_notification
│ └── notification_page.dart
│ ├── demo_route
│ ├── route_page.dart
│ ├── route_page_with_value.dart
│ └── route_page_with_value_one.dart
│ ├── demo_simple_bloc
│ ├── search_bloc.dart
│ └── search_page.dart
│ ├── demo_simple_redux
│ ├── count_middleware.dart
│ ├── count_redux.dart
│ ├── count_redux_page.dart
│ ├── redux_w_test_a.dart
│ ├── redux_w_test_b.dart
│ └── redux_w_test_c.dart
│ ├── demo_stream
│ └── streams_page.dart
│ ├── drawer_page.dart
│ ├── home_page.dart
│ ├── tab_android_page.dart
│ ├── tab_girl_page.dart
│ └── tab_ios_page.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshot
├── 1.jpeg
├── 10.jpeg
├── 11.jpeg
├── 12.jpeg
├── 13.jpeg
├── 14.jpeg
├── 15.jpeg
├── 16.jpeg
├── 17.jpeg
├── 18.jpeg
├── 19.jpeg
├── 20.png
├── 3.jpeg
├── 4.png
├── 5.jpeg
├── 6.jpeg
├── 8.jpeg
└── 9.jpeg
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 |
9 | .flutter-plugins
10 |
--------------------------------------------------------------------------------
/.idea/checkstyle-idea.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_Plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_for_Android.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
27 |
28 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: f9bb4289e9fd861d70ae78bcc3a042ef1b35cc9d
8 | channel: beta
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_study
2 |
3 | 感谢 http://gank.io 提供的api帮助完成这个demo
4 | 该项目完全开源,单纯为了学习与交流,希望大家喜欢,多多提意见。
5 | 后续会将未来学到的新知识点用到该项目,持续更新
6 |
7 |
8 | 
9 |
10 |










11 |
12 | 
13 |
14 | ## 知识点(每一个都有一个独立的例子)
15 | 1.基础布局
16 | 2.数据请求
17 | 3.MVP实现
18 | 4.上拉加载(监测到最底端直接刷新,待优化),下拉刷新
19 | 5.主题学习
20 | 6.路由
21 | 7.drawer
22 | 8.数据存储三种方式(文件,SharedPreference,sqflite)
23 | 9.手势
24 | 10.图片加载
25 | 11.生命周期
26 | 12.网络请求(dio,http,原生)
27 | 13.多点触控
28 | 14.InheritedWidget
29 | 15.TabBarView & TabBar ,切换的时候,每次都会执行initState。
30 | 16.GlobalKey(简单使用)
31 | 17.国际化
32 | 18.Notification自下而上传递数据
33 | 19.显示/隐藏widget
34 | 20.drag
35 | 21.Animation
36 | 22.StreamController
37 | 23.[Business Logic Component](https://medium.com/lacolaco-blog/bloc-design-pattern-with-angular-1c2f0339f6a3)
38 | 24.Simple Redux & Simple BLoC
39 | 25.Channel(目前使用Android设备学习,高德,权限)
40 |
41 |
42 | ## 部分问题记录
43 | 1.[SnackBar弹不出怎么办](https://www.jianshu.com/p/6520e0173049)
44 | 2.[如何监听实体返回键和AppBar返回键](https://www.jianshu.com/p/f9f496652807)
45 | 3.[刘海和状态栏没有填充当前主题颜色怎么办](https://www.jianshu.com/p/90cd38aeee65)
46 |
47 |
48 | ## 第三方库
49 | 第三方库搜索:
50 | https://pub.dartlang.org/
51 |
52 | 持久化
53 | sqflite:https://pub.dartlang.org/packages/sqflite
54 | shared_preferences:https://pub.dartlang.org/packages/shared_preferences
55 | path_provider:https://pub.dartlang.org/packages/path_provider
56 |
57 | 图片加载
58 | cached_network_image:https://pub.dartlang.org/packages/cached_network_image
59 | transparent_image:https://pub.dartlang.org/packages/transparent_image
60 |
61 | 网络请求
62 | dio:https://pub.dartlang.org/packages/dio
63 | http:https://pub.dartlang.org/packages/http
64 |
65 | WebView
66 | flutter_webview_plugin:https://pub.dartlang.org/packages/flutter_webview_plugin
67 |
68 | ## 推荐资源
69 | Flutter英文网:https://flutter.io
70 | Flutter中文网:https://flutterchina.club
71 | Flutter社区:http://flutter-dev.cn/
72 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.class
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | GeneratedPluginRegistrant.java
11 |
--------------------------------------------------------------------------------
/android/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/android/.idea/checkstyle-idea.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
--------------------------------------------------------------------------------
/android/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
--------------------------------------------------------------------------------
/android/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | apply plugin: 'com.android.application'
15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
16 |
17 | android {
18 | compileSdkVersion 27
19 |
20 | lintOptions {
21 | disable 'InvalidPackage'
22 | }
23 |
24 | defaultConfig {
25 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
26 | applicationId "com.jzhu.flutterstudy"
27 | minSdkVersion 16
28 | targetSdkVersion 27
29 | versionCode 1
30 | versionName "1.0"
31 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
32 |
33 | ndk { abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86","arm64-v8a","x86_64" }
34 |
35 | }
36 |
37 | signingConfigs {
38 | release {
39 | keyAlias 'jz'
40 | keyPassword '123456'
41 | storeFile file('../building_system/jz.jks')
42 | storePassword '123456'
43 | }
44 | }
45 |
46 | buildTypes {
47 | release {
48 | // minifyEnabled true
49 | signingConfig signingConfigs.release
50 | // proguardFile 'proguard-rules.pro'
51 | }
52 | debug {
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 | }
57 |
58 | flutter {
59 | source '../..'
60 | }
61 |
62 | dependencies {
63 | implementation fileTree(dir: 'libs', include: ['*.jar'])
64 | testImplementation 'junit:junit:4.12'
65 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
67 | implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
68 | implementation 'com.amap.api:location:4.2.0'
69 | implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'
70 | // implementation 'com.android.support:support-compat:27.1.1'
71 | // implementation 'com.android.support:appcompat-v7:27.1.1'
72 | // implementation 'com.android.support:support-fragment:27.1.1'
73 | // implementation 'com.android.support:support-core-utils:27.1.1'
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
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 |
37 |
41 |
48 |
52 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy;
2 |
3 | import android.os.Bundle;
4 | import com.jzhu.flutterstudy.plugin.FlutterPluginAMap;
5 | import com.jzhu.flutterstudy.plugin.FlutterPluginCounter;
6 | import com.jzhu.flutterstudy.plugin.FlutterPluginJumpToAct;
7 | import com.jzhu.flutterstudy.plugin.FlutterPluginPermissions;
8 | import io.flutter.app.FlutterActivity;
9 | import io.flutter.plugin.common.PluginRegistry;
10 | import io.flutter.plugins.GeneratedPluginRegistrant;
11 |
12 | public class MainActivity extends FlutterActivity {
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 |
17 | GeneratedPluginRegistrant.registerWith(this);
18 | registerCustomPlugin(this);
19 | }
20 |
21 | private static void registerCustomPlugin(PluginRegistry registrar) {
22 |
23 | FlutterPluginJumpToAct.registerWith(registrar.registrarFor(FlutterPluginJumpToAct.CHANNEL));
24 |
25 | FlutterPluginCounter.registerWith(registrar.registrarFor(FlutterPluginCounter.CHANNEL));
26 |
27 | FlutterPluginPermissions.registerWith(registrar.registrarFor(FlutterPluginPermissions.CHANNEL));
28 |
29 | FlutterPluginAMap.registerWith(registrar.registrarFor(FlutterPluginAMap.EVENT_CHANNEL));
30 |
31 | }
32 |
33 |
34 |
35 |
36 | }
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/OneActivity.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.Button;
8 |
9 | public class OneActivity extends Activity implements View.OnClickListener {
10 |
11 | private Button mGoFlutterBtn;
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 |
17 | setContentView(R.layout.activity_one);
18 |
19 | mGoFlutterBtn = findViewById(R.id.go_flutter);
20 |
21 | mGoFlutterBtn.setOnClickListener(this);
22 |
23 | }
24 |
25 | @Override
26 | public void onClick(View view) {
27 | switch (view.getId()) {
28 | case R.id.go_flutter:
29 | Intent intent = new Intent(this, MainActivity.class);
30 | startActivity(intent);
31 | break;
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/TwoActivity.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.widget.TextView;
6 |
7 | public class TwoActivity extends Activity{
8 |
9 | private TextView mTextView;
10 |
11 | public static final String VALUE = "value";
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 |
17 | setContentView(R.layout.activity_two);
18 |
19 | mTextView = findViewById(R.id.text);
20 |
21 | String text = getIntent().getStringExtra(VALUE);
22 |
23 | mTextView.setText(text);
24 |
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/plugin/FlutterPluginAMap.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy.plugin;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 | import com.amap.api.location.AMapLocation;
6 | import com.amap.api.location.AMapLocationClient;
7 | import com.amap.api.location.AMapLocationClientOption;
8 | import com.amap.api.location.AMapLocationListener;
9 | import io.flutter.plugin.common.EventChannel;
10 | import io.flutter.plugin.common.PluginRegistry;
11 |
12 | import java.util.HashMap;
13 |
14 | public class FlutterPluginAMap implements EventChannel.StreamHandler {
15 |
16 | public static String EVENT_CHANNEL = "com.jzhu.amap.loc/plugin";
17 |
18 | public static String METHOD_CHANNEL = "com.jzhu.amap.fun/plugin";
19 |
20 | private static EventChannel mEventChannel;
21 |
22 | private Activity mActivity;
23 |
24 | private AMapLocationClient mlocationClient;
25 |
26 | private AMapLocationClientOption mLocationOption = null;
27 |
28 | private EventChannel.EventSink mEventSink;
29 |
30 | private HashMap mLocation = new HashMap<>();
31 |
32 | private static FlutterPluginAMap instance;
33 |
34 | private FlutterPluginAMap(Activity activity) {
35 | this.mActivity = activity;
36 | initAMap();
37 | }
38 |
39 | public static void registerWith(PluginRegistry.Registrar registrar) {
40 |
41 | if (null == instance) {
42 | instance = new FlutterPluginAMap(registrar.activity());
43 | }
44 |
45 | mEventChannel = new EventChannel(registrar.messenger(), EVENT_CHANNEL);
46 | mEventChannel.setStreamHandler(instance);
47 |
48 | }
49 |
50 |
51 | private void initAMap() {
52 | mlocationClient = new AMapLocationClient(mActivity);
53 | mLocationOption = new AMapLocationClientOption();
54 | mlocationClient.setLocationListener(new AMapLocationListener() {
55 | @Override
56 | public void onLocationChanged(AMapLocation aMapLocation) {
57 | if (aMapLocation != null) {
58 | if (aMapLocation.getErrorCode() == 0) {
59 | //定位成功回调信息,设置相关消息
60 | // aMapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
61 | // aMapLocation.getLatitude();//获取纬度
62 | // aMapLocation.getLongitude();//获取经度
63 | // aMapLocation.getAccuracy();//获取精度信息
64 | // SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
65 | // Date date = new Date(aMapLocation.getTime());
66 | // df.format(date);//定位时间
67 |
68 | mLocation.put("province", aMapLocation.getProvince());
69 | mLocation.put("city", aMapLocation.getCity());
70 | mLocation.put("latitude", aMapLocation.getLatitude());
71 | mLocation.put("longitude", aMapLocation.getLongitude());
72 | mLocation.put("address", aMapLocation.getAddress());
73 |
74 | if (null != mEventSink) {
75 | mEventSink.success(mLocation);
76 | }
77 | }
78 | else {
79 | //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
80 | Log.e("zj", "location Error, ErrCode:"
81 | + aMapLocation.getErrorCode() + ", errInfo:"
82 | + aMapLocation.getErrorInfo());
83 | }
84 | }
85 | }
86 | });
87 | mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
88 | mLocationOption.setInterval(10 * 1000);
89 | mlocationClient.setLocationOption(mLocationOption);
90 | mlocationClient.startLocation();
91 |
92 | }
93 |
94 | @Override
95 | public void onListen(Object o, final EventChannel.EventSink eventSink) {
96 |
97 | mEventSink = eventSink;
98 |
99 | }
100 |
101 | @Override
102 | public void onCancel(Object o) {
103 |
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/plugin/FlutterPluginCounter.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy.plugin;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 | import io.flutter.plugin.common.BasicMessageChannel;
6 | import io.flutter.plugin.common.EventChannel;
7 | import io.flutter.plugin.common.PluginRegistry;
8 | import io.flutter.plugin.common.StringCodec;
9 | import io.reactivex.Observable;
10 | import io.reactivex.Observer;
11 | import io.reactivex.disposables.Disposable;
12 |
13 | import java.util.concurrent.TimeUnit;
14 |
15 | public class FlutterPluginCounter implements EventChannel.StreamHandler {
16 |
17 | public static String CHANNEL = "com.jzhu.counter/plugin";
18 |
19 | static EventChannel channel;
20 |
21 | private Activity activity;
22 |
23 | // static BasicMessageChannel basicMessageChannel;
24 |
25 | private FlutterPluginCounter(Activity activity) {
26 | this.activity = activity;
27 | }
28 |
29 | public static void registerWith(PluginRegistry.Registrar registrar) {
30 | channel = new EventChannel(registrar.messenger(), CHANNEL);
31 | FlutterPluginCounter instance = new FlutterPluginCounter(registrar.activity());
32 | channel.setStreamHandler(instance);
33 | // basicMessageChannel = new BasicMessageChannel ("foo", StringCodec.INSTANCE);
34 | }
35 |
36 | @Override
37 | public void onListen(Object o, final EventChannel.EventSink eventSink) {
38 |
39 | Observable.interval(1000, TimeUnit.MILLISECONDS).subscribe(new Observer() {
40 | @Override
41 | public void onSubscribe(Disposable d) {
42 |
43 | }
44 |
45 | @Override
46 | public void onNext(Long aLong) {
47 | eventSink.success(aLong.intValue());
48 | }
49 |
50 | @Override
51 | public void onError(Throwable e) {
52 | eventSink.error("计时器异常", "异常", e.getMessage());
53 | }
54 |
55 | @Override
56 | public void onComplete() {
57 | }
58 | });
59 |
60 | }
61 |
62 | @Override
63 | public void onCancel(Object o) {
64 | Log.i("FlutterPluginCounter", "FlutterPluginCounter:onCancel");
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/plugin/FlutterPluginJumpToAct.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy.plugin;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import com.jzhu.flutterstudy.OneActivity;
6 | import com.jzhu.flutterstudy.TwoActivity;
7 | import io.flutter.plugin.common.MethodCall;
8 | import io.flutter.plugin.common.MethodChannel;
9 | import io.flutter.plugin.common.PluginRegistry;
10 |
11 | public class FlutterPluginJumpToAct implements MethodChannel.MethodCallHandler {
12 |
13 | public static String CHANNEL = "com.jzhu.jump/plugin";
14 |
15 | static MethodChannel channel;
16 |
17 | private Activity activity;
18 |
19 | private FlutterPluginJumpToAct(Activity activity) {
20 | this.activity = activity;
21 | }
22 |
23 | public static void registerWith(PluginRegistry.Registrar registrar) {
24 | channel = new MethodChannel(registrar.messenger(), CHANNEL);
25 | FlutterPluginJumpToAct instance = new FlutterPluginJumpToAct(registrar.activity());
26 | //setMethodCallHandler在此通道上接收方法调用的回调
27 | channel.setMethodCallHandler(instance);
28 | }
29 |
30 | @Override
31 | public void onMethodCall(MethodCall call, MethodChannel.Result result) {
32 |
33 | //通过MethodCall可以获取参数和方法名,然后再寻找对应的平台业务,本案例做了2个跳转的业务
34 |
35 | //接收来自flutter的指令oneAct
36 | if (call.method.equals("oneAct")) {
37 |
38 | //跳转到指定Activity
39 | Intent intent = new Intent(activity, OneActivity.class);
40 | activity.startActivity(intent);
41 |
42 | //返回给flutter的参数
43 | result.success("success");
44 | }
45 | //接收来自flutter的指令twoAct
46 | else if (call.method.equals("twoAct")) {
47 |
48 | //解析参数
49 | String text = call.argument("flutter");
50 |
51 | //带参数跳转到指定Activity
52 | Intent intent = new Intent(activity, TwoActivity.class);
53 | intent.putExtra(TwoActivity.VALUE, text);
54 | activity.startActivity(intent);
55 |
56 | //返回给flutter的参数
57 | result.success("success");
58 | }
59 | else {
60 | result.notImplemented();
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jzhu/flutterstudy/plugin/FlutterPluginPermissions.java:
--------------------------------------------------------------------------------
1 | package com.jzhu.flutterstudy.plugin;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.provider.Settings;
9 | import com.tbruyelle.rxpermissions2.RxPermissions;
10 | import io.flutter.plugin.common.MethodCall;
11 | import io.flutter.plugin.common.MethodChannel;
12 | import io.flutter.plugin.common.PluginRegistry;
13 | import io.reactivex.functions.Consumer;
14 |
15 | import java.util.ArrayList;
16 | import java.util.HashMap;
17 | import java.util.List;
18 |
19 | public class FlutterPluginPermissions implements MethodChannel.MethodCallHandler {
20 |
21 | public static String CHANNEL = "com.jzhu.permisstions/plugin";
22 |
23 | static MethodChannel channel;
24 |
25 | private Activity activity;
26 |
27 | private HashMap permissionsMap = new HashMap<>();
28 |
29 | private RxPermissions rxPermissions;
30 |
31 | private FlutterPluginPermissions(Activity activity) {
32 | this.activity = activity;
33 | rxPermissions = new RxPermissions(activity);
34 | initPermissions();
35 | }
36 |
37 | public static void registerWith(PluginRegistry.Registrar registrar) {
38 | channel = new MethodChannel(registrar.messenger(), CHANNEL);
39 | FlutterPluginPermissions instance = new FlutterPluginPermissions(registrar.activity());
40 | channel.setMethodCallHandler(instance);
41 | }
42 |
43 | @Override
44 | public void onMethodCall(MethodCall call, final MethodChannel.Result result) {
45 |
46 | if (call.method.equals("askPermissions")) {
47 |
48 |
49 | //如果小于6。0的不需要判断权限
50 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
51 | result.success(true);
52 | return;
53 | }
54 |
55 |
56 | List list = (List) call.arguments;
57 |
58 | List permissionslist = new ArrayList<>();
59 |
60 | for (String per : list) {
61 | permissionslist.add(permissionsMap.get(per));
62 | }
63 |
64 | String[] permissions = new String[list.size()];
65 |
66 | permissionslist.toArray(permissions);
67 |
68 | rxPermissions
69 | .request(permissions)
70 | .subscribe(new Consumer() {
71 | @Override
72 | public void accept(Boolean aBoolean) throws Exception {
73 | result.success(aBoolean);
74 | }
75 | });
76 |
77 | }else if(call.method.equals("openSetting")){
78 | openSettings();
79 | }
80 | else {
81 | result.notImplemented();
82 | }
83 | }
84 |
85 | private void openSettings() {
86 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
87 | Uri.parse("package:" + activity.getPackageName()));
88 | intent.addCategory(Intent.CATEGORY_DEFAULT);
89 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
90 | activity.startActivity(intent);
91 | }
92 |
93 |
94 | /**
95 | * 权限
96 | */
97 |
98 | private void initPermissions() {
99 | permissionsMap.put("ACCESS_COARSE_LOCATION", Manifest.permission.ACCESS_COARSE_LOCATION);
100 | permissionsMap.put("ACCESS_FINE_LOCATION", Manifest.permission.ACCESS_FINE_LOCATION);
101 | permissionsMap.put("ACCESS_NETWORK_STATE", Manifest.permission.ACCESS_NETWORK_STATE);
102 | permissionsMap.put("Permissions.ACCESS_WIFI_STATE", Manifest.permission.ACCESS_WIFI_STATE);
103 | permissionsMap.put("CHANGE_WIFI_STATE", Manifest.permission.CHANGE_WIFI_STATE);
104 | permissionsMap.put("INTERNET", Manifest.permission.INTERNET);
105 | permissionsMap.put("READ_PHONE_STATE", Manifest.permission.READ_PHONE_STATE);
106 | permissionsMap.put("WRITE_EXTERNAL_STORAGE", Manifest.permission.WRITE_EXTERNAL_STORAGE);
107 | permissionsMap.put("ACCESS_LOCATION_EXTRA_COMMANDS", Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS);
108 | permissionsMap.put("BLUETOOTH", Manifest.permission.BLUETOOTH);
109 | permissionsMap.put("BLUETOOTH_ADMIN", Manifest.permission.BLUETOOTH_ADMIN);
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/activity_one.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/activity_two.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | mavenCentral()
6 | maven { url 'https://jitpack.io' }
7 | }
8 |
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | maven { url 'https://jitpack.io' }
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/android/building_system/jz.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/building_system/jz.jks
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/flutter_study.iml:
--------------------------------------------------------------------------------
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 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/flutter_study_android.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/images/2.0x/ic_assignment_ind_36pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/images/2.0x/ic_assignment_ind_36pt.png
--------------------------------------------------------------------------------
/images/3.0x/ic_assignment_ind_36pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/images/3.0x/ic_assignment_ind_36pt.png
--------------------------------------------------------------------------------
/images/ic_assignment_ind_36pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/images/ic_assignment_ind_36pt.png
--------------------------------------------------------------------------------
/images/lifecycle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/images/lifecycle.png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/app.flx
37 | /Flutter/app.zip
38 | /Flutter/flutter_assets/
39 | /Flutter/App.framework
40 | /Flutter/Flutter.framework
41 | /Flutter/Generated.xcconfig
42 | /ServiceDefinitions.json
43 |
44 | Pods/
45 | .symlinks/
46 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | def parse_KV_file(file, separator='=')
8 | file_abs_path = File.expand_path(file)
9 | if !File.exists? file_abs_path
10 | return [];
11 | end
12 | pods_ary = []
13 | skip_line_start_symbols = ["#", "/"]
14 | File.foreach(file_abs_path) { |line|
15 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
16 | plugin = line.split(pattern=separator)
17 | if plugin.length == 2
18 | podname = plugin[0].strip()
19 | path = plugin[1].strip()
20 | podpath = File.expand_path("#{path}", file_abs_path)
21 | pods_ary.push({:name => podname, :path => podpath});
22 | else
23 | puts "Invalid plugin specification: #{line}"
24 | end
25 | }
26 | return pods_ary
27 | end
28 |
29 | target 'Runner' do
30 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
31 | # referring to absolute paths on developers' machines.
32 | system('rm -rf .symlinks')
33 | system('mkdir -p .symlinks/plugins')
34 |
35 | # Flutter Pods
36 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
37 | if generated_xcode_build_settings.empty?
38 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
39 | end
40 | generated_xcode_build_settings.map { |p|
41 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
42 | symlink = File.join('.symlinks', 'flutter')
43 | File.symlink(File.dirname(p[:path]), symlink)
44 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
45 | end
46 | }
47 |
48 | # Plugin Pods
49 | plugin_pods = parse_KV_file('../.flutter-plugins')
50 | plugin_pods.map { |p|
51 | symlink = File.join('.symlinks', 'plugins', p[:name])
52 | File.symlink(p[:path], symlink)
53 | pod p[:name], :path => File.join(symlink, 'ios')
54 | }
55 | end
56 |
57 | post_install do |installer|
58 | installer.pods_project.targets.each do |target|
59 | target.build_configurations.each do |config|
60 | config.build_settings['ENABLE_BITCODE'] = 'NO'
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_webview_plugin (0.0.1):
4 | - Flutter
5 | - FMDB (2.7.2):
6 | - FMDB/standard (= 2.7.2)
7 | - FMDB/standard (2.7.2)
8 | - path_provider (0.0.1):
9 | - Flutter
10 | - shared_preferences (0.0.1):
11 | - Flutter
12 | - sqflite (0.0.1):
13 | - Flutter
14 | - FMDB (~> 2.7.2)
15 |
16 | DEPENDENCIES:
17 | - Flutter (from `.symlinks/flutter/ios`)
18 | - flutter_webview_plugin (from `.symlinks/plugins/flutter_webview_plugin/ios`)
19 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
20 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
21 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
22 |
23 | SPEC REPOS:
24 | https://github.com/cocoapods/specs.git:
25 | - FMDB
26 |
27 | EXTERNAL SOURCES:
28 | Flutter:
29 | :path: ".symlinks/flutter/ios"
30 | flutter_webview_plugin:
31 | :path: ".symlinks/plugins/flutter_webview_plugin/ios"
32 | path_provider:
33 | :path: ".symlinks/plugins/path_provider/ios"
34 | shared_preferences:
35 | :path: ".symlinks/plugins/shared_preferences/ios"
36 | sqflite:
37 | :path: ".symlinks/plugins/sqflite/ios"
38 |
39 | SPEC CHECKSUMS:
40 | Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
41 | flutter_webview_plugin: 116575b48572029304775b768e9f15ebfc316274
42 | FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
43 | path_provider: 09407919825bfe3c2deae39453b7a5b44f467873
44 | shared_preferences: 5a1d487c427ee18fcd3ea1f2a131569481834b53
45 | sqflite: d1612813fa7db7c667bed9f1d1b508deffc56999
46 |
47 | PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
48 |
49 | COCOAPODS: 1.5.2
50 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 | @implementation AppDelegate
4 |
5 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
6 | [GeneratedPluginRegistrant registerWithRegistry:self];
7 | // Override point for customization after application launch.
8 | // Use Firebase library to configure APIs
9 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
10 | }
11 |
12 | @end
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_study
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char * argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/common/constant.dart:
--------------------------------------------------------------------------------
1 |
2 | class Constant {
3 |
4 | static const String baseUrl="http://gank.io/api/data/";
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/lib/common/widget/common_webview.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
3 |
4 | class CommonWebView extends StatefulWidget {
5 | final String title;
6 |
7 | final String url;
8 |
9 | CommonWebView(this.title, this.url);
10 |
11 | @override
12 | State createState() {
13 | return new _CommonWebViewPageState();
14 | }
15 | }
16 |
17 |
18 | class _CommonWebViewPageState extends State {
19 |
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return new WebviewScaffold(
24 | url: widget.url,
25 | appBar: new AppBar(
26 | title: new Text(widget.title),
27 | ),
28 | withZoom: true,
29 | withLocalStorage: true,
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/common/widget/progreess_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | Widget getProgressDialog() {
4 | return new Center(child: new CircularProgressIndicator());
5 | }
6 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_localizations/flutter_localizations.dart';
3 | import 'package:flutter_study/widget/architecture_page.dart';
4 | import 'package:flutter_study/widget/advanced_page.dart';
5 | import 'package:flutter_study/widget/demo_animation/animation_page.dart';
6 | import 'package:flutter_study/widget/demo_gesture/drag_page.dart';
7 | import 'package:flutter_study/widget/demo_key/globalkey_form_page.dart';
8 | import 'package:flutter_study/widget/demo_common/hide_and_show_page.dart';
9 | import 'package:flutter_study/widget/demo_inherited/inherited_w_page.dart';
10 | import 'package:flutter_study/widget/demo_native/channel_page.dart';
11 | import 'package:flutter_study/widget/demo_notification/notification_page.dart';
12 | import 'package:flutter_study/widget/demo_simple_redux/count_redux_page.dart';
13 | import 'package:flutter_study/widget/demo_stream/streams_page.dart';
14 | import 'package:flutter_study/widget/demo_base_widget/base_widget_page.dart';
15 | import 'package:flutter_study/widget/demo_base_widget/container_page.dart';
16 | import 'package:flutter_study/widget/demo_simple_bloc/search_page.dart';
17 | import 'package:flutter_study/widget/demo_database/data_page.dart';
18 | import 'package:flutter_study/widget/demo_gesture/dismissed_page.dart';
19 | import 'package:flutter_study/widget/demo_gesture/gesture_page.dart';
20 | import 'package:flutter_study/widget/demo_lifecycle/lifecycle_page.dart';
21 | import 'package:flutter_study/widget/demo_loadimg/loadImg_page.dart';
22 | import 'package:flutter_study/widget/demo_localizations/localizations_study.dart';
23 | import 'package:flutter_study/widget/demo_network/network_page.dart';
24 | import 'package:flutter_study/widget/demo_route/route_page.dart';
25 | import 'package:flutter_study/widget/demo_route/route_page_with_value_one.dart';
26 | import 'package:flutter_study/widget/home_page.dart';
27 | //import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
28 |
29 | void main() {
30 | // debugPaintSizeEnabled = true; //打开视觉调试开关
31 |
32 | runApp(new MaterialApp(
33 | // theme: defaultTargetPlatform == TargetPlatform.iOS
34 | // ? kiOSTheme
35 | // : kAndroidTheme,
36 | // theme: kAndroidTheme,
37 | localizationsDelegates: [
38 | GlobalMaterialLocalizations.delegate,
39 | GlobalWidgetsLocalizations.delegate,
40 | StudyLocalizationsDelegate.delegate,
41 | ], supportedLocales: [
42 | const Locale('zh', 'CH'),
43 | const Locale('en', 'US'),
44 | ], routes: {
45 | '/RoutePage': (BuildContext context) => new RoutePage(),
46 | '/RoutePageWithValue1': (BuildContext context) => new RoutePageWithValue1(),
47 | '/DataPage': (BuildContext context) => new DataAppPage(),
48 | '/GesturePage': (BuildContext context) => new GesturePage(),
49 | '/DismissedPage': (BuildContext context) => new DismissedPage(),
50 | '/LoadImgPage': (BuildContext context) => new LoadImgPage(),
51 | '/LifecyclePage': (BuildContext context) => new LifecyclePage(),
52 | '/NetworkPage': (BuildContext context) => new NetworkPage(),
53 | '/AdvancedPage': (BuildContext context) => new AdvancedPage(),
54 | '/InheritedWidgetTestPage': (BuildContext context) => new InheritedWidgetTestContainer(),
55 | '/GlobalKeyFromPage': (BuildContext context) => new GlobalKeyFromPage(),
56 | '/NotificationPage': (BuildContext context) => new NotificationPage(),
57 | '/HideAndShowPage': (BuildContext context) => new HideAndShowPage(),
58 | '/StreamPage': (BuildContext context) => new StreamPage(),
59 | '/DragPage': (BuildContext context) => new DragPage(),
60 | '/ContainerPage': (BuildContext context) => new ContainerPage(),
61 | '/BaseWidgetPage': (BuildContext context) => new BaseWidgetPage(),
62 | '/AnimationPage': (BuildContext context) => new AnimationPage(),
63 | '/SearchPage': (BuildContext context) => new SearchPage(),
64 | '/HomePage': (BuildContext context) => new HomePage(),
65 | '/CountReduxPage': (BuildContext context) => new CountReduxPage(),
66 | '/ArchitecturePage': (BuildContext context) => new ArchitecturePage(),
67 | '/ChannelPage': (BuildContext context) => new ChannelPage(),
68 | }, home: new HomePage()));
69 | }
70 |
--------------------------------------------------------------------------------
/lib/model/ai_model.dart:
--------------------------------------------------------------------------------
1 | class AIModel{
2 |
3 | final String desc;
4 | final List images;
5 | final String publishedAt;
6 | final String url;
7 | final String who;
8 |
9 | const AIModel({this.desc,this.images,this.publishedAt,this.url,this.who});
10 |
11 | AIModel.fromJson(Map json)
12 | :
13 | desc=json['desc'],
14 | images=json['images'],
15 | publishedAt = json['publishedAt'],
16 | url = json['url'],
17 | who = json['who']
18 | ;
19 |
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/lib/model/base_model.dart:
--------------------------------------------------------------------------------
1 |
2 | class BaseModel{
3 |
4 | final bool error;
5 |
6 | final T results;
7 |
8 | const BaseModel({this.error, this.results});
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/lib/model/fl_model.dart:
--------------------------------------------------------------------------------
1 |
2 | class FLModel{
3 |
4 | final String url;
5 |
6 | const FLModel({this.url});
7 |
8 | FLModel.fromJson(Map json)
9 | : url = json['url'];
10 |
11 | Map toJson() =>
12 | {
13 | 'url': url,
14 | };
15 |
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/lib/model/hot_news_model.dart:
--------------------------------------------------------------------------------
1 | class HotNewsModel {
2 |
3 | final String date;
4 |
5 | final List stories;
6 |
7 | final List top_stories;
8 |
9 | const HotNewsModel({this.date, this.stories, this.top_stories});
10 |
11 | }
12 |
13 | class HotNewsStoriesModel {
14 | final List images;
15 | final int type;
16 | final int id;
17 | final String title;
18 |
19 | const HotNewsStoriesModel({this.images, this.type, this.id, this.title});
20 |
21 | HotNewsStoriesModel.fromJson(Map json)
22 | : images = json['images'],
23 | type = json['type'],
24 | id = json['id'],
25 | title = json['title'];
26 | }
27 |
28 | class HotNewsTopStoriesModel {
29 | final String image;
30 | final int type;
31 | final int id;
32 | final String title;
33 |
34 | const HotNewsTopStoriesModel({this.image, this.type, this.id, this.title});
35 |
36 | HotNewsTopStoriesModel.fromJson(Map json)
37 | : image = json['image'],
38 | type = json['type'],
39 | id = json['id'],
40 | title = json['title'];
41 | }
42 |
--------------------------------------------------------------------------------
/lib/model/inherited_test_model.dart:
--------------------------------------------------------------------------------
1 |
2 | class InheritedTestModel {
3 |
4 | final int count;
5 |
6 | const InheritedTestModel(this.count);
7 |
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/lib/model/search_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:dio/dio.dart';
5 | import 'package:flutter_study/model/base_model.dart';
6 | import 'package:flutter_study/util/dio_factory.dart';
7 |
8 | class SearchModel {
9 | final String desc;
10 | final String publishedAt;
11 | final String url;
12 | final String who;
13 |
14 | const SearchModel({this.desc, this.publishedAt, this.url, this.who});
15 |
16 | SearchModel.fromJson(Map json)
17 | : desc = json['desc'],
18 | publishedAt = json['publishedAt'],
19 | url = json['url'],
20 | who = json['who'];
21 | }
22 |
23 | class SearchApi {
24 | final Dio _dio = DioFactory.getInstance().getDio();
25 |
26 | static const String _url =
27 | "http://gank.io/api/search/query/listview/category/{type}/count/10/page/1";
28 |
29 | Future>> getSearchResult(String type) async {
30 |
31 |
32 | if(type.isEmpty){
33 | return null;
34 | }
35 |
36 | Response response = await _dio.get(_url.replaceFirst('{type}', type));
37 |
38 | BaseModel> model = new BaseModel(error: true, results: null);
39 |
40 | List list;
41 |
42 | if (response.statusCode == HttpStatus.OK) {
43 | bool error = response.data['error'];
44 | if (!error) {
45 | List searchModels = response.data['results'];
46 | list = searchModels.map((model) {
47 | return new SearchModel.fromJson(model);
48 | }).toList();
49 | }
50 | model = new BaseModel(error: error, results: list);
51 | }
52 |
53 | print(model.results.length);
54 | return model;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/lib/mvp/mvp.dart:
--------------------------------------------------------------------------------
1 |
2 | abstract class IView {
3 | setPresenter(T presenter);
4 | }
5 |
6 | abstract class IPresenter{
7 | init();
8 | }
9 |
--------------------------------------------------------------------------------
/lib/mvp/presenter/ai_presenter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_study/model/ai_model.dart';
2 | import 'package:flutter_study/mvp/mvp.dart';
3 |
4 |
5 | abstract class AIPresenter implements IPresenter{
6 | loadAIData(String type,int pageNum,int pageSize);
7 | }
8 |
9 |
10 | abstract class AIView implements IView{
11 | void onloadFLSuc(List list);
12 | void onloadFLFail();
13 | }
14 |
--------------------------------------------------------------------------------
/lib/mvp/presenter/ai_presenter_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_study/mvp/presenter/ai_presenter.dart';
2 | import 'package:flutter_study/mvp/repository/ai_repository_impl.dart';
3 | import 'package:flutter_study/mvp/repository/ai_repository.dart';
4 |
5 | class AIPresenterImpl implements AIPresenter {
6 | AIView _view;
7 |
8 | AIRepository _repository;
9 |
10 | AIPresenterImpl(this._view) {
11 | _view.setPresenter(this);
12 | }
13 |
14 | @override
15 | void loadAIData(String type, int pageNum, int pageSize) {
16 | assert(_view != null);
17 |
18 | _repository.fetch(type, pageNum, pageSize).then((data) {
19 | _view.onloadFLSuc(data);
20 | }).catchError((error) {
21 | print(error);
22 | _view.onloadFLFail();
23 | });
24 | }
25 |
26 | @override
27 | init() {
28 | _repository = new AIRepositoryImpl();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/mvp/presenter/fl_presenter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_study/model/fl_model.dart';
2 | import 'package:flutter_study/mvp/mvp.dart';
3 |
4 |
5 | abstract class FLPresenter implements IPresenter{
6 | loadFLData(int pageNum,int pageSize);
7 | }
8 |
9 |
10 | abstract class FLView implements IView{
11 | void onloadFLSuc(List list);
12 | void onloadFLFail();
13 | }
14 |
--------------------------------------------------------------------------------
/lib/mvp/presenter/fl_presenter_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_study/mvp/presenter/fl_presenter.dart';
2 | import 'package:flutter_study/mvp/repository/fl_repository_impl.dart';
3 | import 'package:flutter_study/mvp/repository/fl_repository.dart';
4 |
5 | class FLPresenterImpl implements FLPresenter {
6 | FLView _view;
7 |
8 | FLRepository _repository;
9 |
10 | FLPresenterImpl(this._view) {
11 | _view.setPresenter(this);
12 | }
13 |
14 | @override
15 | void loadFLData(int pageNum, int pageSize) {
16 | assert(_view != null);
17 |
18 | _repository.fetch(pageNum,pageSize).then((data) {
19 | _view.onloadFLSuc(data);
20 | }).catchError((error) {
21 | print(error);
22 | _view.onloadFLFail();
23 | });
24 | }
25 |
26 | @override
27 | init() {
28 | _repository = new FLRepositoryImpl();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/mvp/repository/ai_repository.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'dart:async';
4 | import 'package:flutter_study/model/ai_model.dart';
5 |
6 |
7 | abstract class AIRepository{
8 | Future> fetch(String type,int pageNum,int pageSize);
9 | }
10 |
--------------------------------------------------------------------------------
/lib/mvp/repository/ai_repository_impl.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | import 'package:flutter_study/common/constant.dart';
6 | import 'package:flutter_study/model/ai_model.dart';
7 | import 'package:flutter_study/mvp/repository/ai_repository.dart';
8 |
9 | class AIRepositoryImpl implements AIRepository {
10 | @override
11 | Future> fetch(String type, int pageNum, int pageSize) {
12 | return _getData(type, pageNum, pageSize);
13 | }
14 | }
15 |
16 | Future> _getData(String type, int pageNum, int pageSize) async {
17 | var httpClient = new HttpClient();
18 | var url = Constant.baseUrl + '$type/$pageSize/$pageNum';
19 |
20 | print(url);
21 |
22 | List aiModels;
23 |
24 | try {
25 | var request = await httpClient.getUrl(Uri.parse(url));
26 | var response = await request.close();
27 | if (response.statusCode == HttpStatus.OK) {
28 | var json = await response.transform(Utf8Decoder()).join();
29 | aiModels = jsonDecode(json)['results'];
30 |
31 | } else {
32 | //todo
33 | }
34 | } catch (exception) {
35 | //todo
36 | }
37 |
38 | return aiModels.map((model) {
39 | return new AIModel.fromJson(model);
40 | }).toList();
41 | }
42 |
43 |
44 |
--------------------------------------------------------------------------------
/lib/mvp/repository/fl_repository.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'dart:async';
4 | import 'package:flutter_study/model/fl_model.dart';
5 |
6 |
7 | abstract class FLRepository{
8 | Future> fetch(int pageNum,int pageSize);
9 | }
10 |
--------------------------------------------------------------------------------
/lib/mvp/repository/fl_repository_impl.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter_study/model/fl_model.dart';
3 | import 'dart:convert';
4 | import 'dart:io';
5 | import 'package:flutter_study/common/constant.dart';
6 | import 'package:flutter_study/mvp/repository/fl_repository.dart';
7 | //分类数据: http://gank.io/api/data/数据类型/请求个数/第几页
8 | //数据类型: 福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all
9 | //请求个数: 数字,大于0
10 | //第几页:数字,大于0
11 | //@param rows
12 | //@param pageNum
13 | //@return
14 |
15 |
16 | class FLRepositoryImpl implements FLRepository {
17 | @override
18 | Future> fetch(int pageNum,int pageSize) {
19 | return _getData(pageNum,pageSize);
20 | }
21 | }
22 |
23 | Future> _getData(int pageNum,int pageSize) async {
24 | var httpClient = new HttpClient();
25 | var url = Constant.baseUrl + '福利/$pageSize/$pageNum';
26 |
27 | print(url);
28 |
29 | List flModels;
30 | try {
31 | var request = await httpClient.getUrl(Uri.parse(url));
32 | var response = await request.close();
33 | if (response.statusCode == HttpStatus.OK) {
34 | var json = await response.transform(Utf8Decoder()).join();
35 | flModels = jsonDecode(json)['results'];
36 | } else {
37 | //todo
38 | }
39 | } catch (exception) {
40 | //todo
41 | }
42 |
43 | return flModels.map((model) {
44 | return new FLModel.fromJson(model);
45 | }).toList();
46 | }
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/lib/theme/custom_theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | ///主题切换
4 |
5 | //iOS系统主题
6 | final ThemeData kiOSTheme = new ThemeData(
7 | primarySwatch: Colors.red,
8 | );
9 |
10 |
11 | // Android系统主题
12 | final ThemeData kAndroidTheme = new ThemeData(
13 | primarySwatch: Colors.blue,
14 |
15 | );
16 |
--------------------------------------------------------------------------------
/lib/util/dio_factory.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | //总觉得怪怪的,但是打印出来确实是只有一个dio对象。。
4 |
5 | class DioFactory {
6 | static Dio _dio;
7 |
8 | static DioFactory _instance;
9 |
10 | static DioFactory getInstance() {
11 | if (_instance == null) {
12 | _instance = new DioFactory._();
13 | _instance._init();
14 | }
15 | return _instance;
16 | }
17 |
18 | DioFactory._();
19 |
20 | _init(){
21 | _dio = new Dio();
22 | }
23 |
24 | getDio() {
25 | return _dio;
26 | }
27 | }
28 |
29 | //测试是否是单例
30 | void main() {
31 | print(DioFactory.getInstance().getDio() == DioFactory.getInstance().getDio());
32 | }
33 |
--------------------------------------------------------------------------------
/lib/util/fix_url_util.dart:
--------------------------------------------------------------------------------
1 | //苹果不支持http的网页浏览,这个修改只针对本api,让服务器都改成https才是最终解决方案
2 | class FixUrlUtil {
3 | static getFixUrl(String url) {
4 | String fixUrl = url;
5 |
6 | if (url.startsWith('http')) {
7 | fixUrl = url.replaceAll('http', 'https');
8 | }
9 |
10 | return fixUrl;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/util/routes_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/common/widget/common_webview.dart';
3 | import 'package:flutter_study/util/fix_url_util.dart';
4 |
5 | class RouteUtil {
6 | static route2Web(BuildContext context, String title, String url) {
7 | if (null == url) {
8 | return;
9 | }
10 | Navigator.of(context).push(new PageRouteBuilder(
11 | opaque: false,
12 | pageBuilder: (BuildContext context, _, __) {
13 | print('$url');
14 | return new CommonWebView(title, url);
15 | },
16 | transitionsBuilder: (_, Animation animation, __, Widget child) {
17 | return new FadeTransition(
18 | opacity: animation,
19 | child: new FadeTransition(
20 | opacity:
21 | new Tween(begin: 0.5, end: 1.0).animate(animation),
22 | child: child,
23 | ),
24 | );
25 | }));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/widget/advanced_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AdvancedPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _AdvancedPageState();
8 | }
9 | }
10 |
11 | class _AdvancedPageState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return new Scaffold(
16 | appBar: new AppBar(
17 | title: new Text('进阶 学习'),
18 | centerTitle: true,
19 | ),
20 | body: new ListView(
21 | children: [
22 | new Padding(
23 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
24 | child: new RaisedButton(
25 | textColor: Colors.black,
26 | child: new Text('InheritedWidget使用'),
27 | onPressed: () {
28 | Navigator.pushNamed(context, "/InheritedWidgetTestPage");
29 | }),
30 | ),
31 |
32 | new Padding(
33 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
34 | child: new RaisedButton(
35 | textColor: Colors.black,
36 | child: new Text('GlobalKey使用'),
37 | onPressed: () {
38 | Navigator.pushNamed(context, "/GlobalKeyFromPage");
39 | }),
40 | ),
41 | new Padding(
42 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
43 | child: new RaisedButton(
44 | textColor: Colors.black,
45 | child: new Text('Notification从下往上数据传递'),
46 | onPressed: () {
47 | Navigator.pushNamed(context, "/NotificationPage");
48 | }),
49 | ),
50 | new Padding(
51 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
52 | child: new RaisedButton(
53 | textColor: Colors.black,
54 | child: new Text('widget显示与隐藏'),
55 | onPressed: () {
56 | Navigator.pushNamed(context, "/HideAndShowPage");
57 | }),
58 | ),
59 | new Padding(
60 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
61 | child: new RaisedButton(
62 | textColor: Colors.black,
63 | child: new Text('StreamController'),
64 | onPressed: () {
65 | Navigator.pushNamed(context, "/StreamPage");
66 | }),
67 | ),
68 | new Padding(
69 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
70 | child: new RaisedButton(
71 | textColor: Colors.black,
72 | child: new Text('drag'),
73 | onPressed: () {
74 | Navigator.pushNamed(context, "/DragPage");
75 | }),
76 | ),
77 | new Padding(
78 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
79 | child: new RaisedButton(
80 | textColor: Colors.black,
81 | child: new Text('Animation'),
82 | onPressed: () {
83 | Navigator.pushNamed(context, "/AnimationPage");
84 | }),
85 | ),
86 | new Padding(
87 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
88 | child: new RaisedButton(
89 | textColor: Colors.black,
90 | child: new Text('Channel (目前只在Android设备上学习)'),
91 | onPressed: () {
92 | Navigator.pushNamed(context, "/ChannelPage");
93 | }),
94 | ),
95 | ],
96 | ),
97 | );
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/lib/widget/architecture_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ArchitecturePage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _ArchitecturePageState();
8 | }
9 | }
10 |
11 | class _ArchitecturePageState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return new Scaffold(
16 | appBar: new AppBar(
17 | title: new Text('Architecture 学习'),
18 | centerTitle: true,
19 | ),
20 | body: new ListView(
21 | children: [
22 | new Padding(
23 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
24 | child: new RaisedButton(
25 | textColor: Colors.black,
26 | child: new Text('MVP(参考主页tab)'),
27 | onPressed: () {
28 | Navigator.of(context).pushReplacementNamed('/HomePage');
29 | }),
30 | ),
31 | new Padding(
32 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
33 | child: new RaisedButton(
34 | textColor: Colors.black,
35 | child: new Text('Simple BLoC'),
36 | onPressed: () {
37 | Navigator.pushNamed(context, "/SearchPage");
38 | }),
39 | ),
40 | new Padding(
41 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
42 | child: new RaisedButton(
43 | textColor: Colors.black,
44 | child: new Text('Simple Redux'),
45 | onPressed: () {
46 | Navigator.pushNamed(context, "/CountReduxPage");
47 | }),
48 | ),
49 | ],
50 | ),
51 | );
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/lib/widget/demo_admob/admob_page.dart:
--------------------------------------------------------------------------------
1 | //import 'package:firebase_admob/firebase_admob.dart';
2 | //import 'package:flutter/material.dart';
3 | //
4 | //class AdmobPage extends StatefulWidget {
5 | // @override
6 | // State createState() {
7 | // return new _AdmobPageState();
8 | // }
9 | //}
10 | //
11 | //class _AdmobPageState extends State {
12 | // static final MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
13 | // testDevices: ["8C21509A809BAC1D40DCE688BE5E959A"],
14 | // keywords: ['flutterio', 'beautiful apps'],
15 | // );
16 | //
17 | // BannerAd bannerAd;
18 | // InterstitialAd interstitialAd;
19 | //
20 | // BannerAd buildBanner() {
21 | // return BannerAd(
22 | // adUnitId: BannerAd.testAdUnitId,
23 | // size: AdSize.banner,
24 | // listener: (MobileAdEvent event) {
25 | // print('BannerAd:$event');
26 | // bannerAd
27 | // ..load()
28 | // ..show();
29 | // });
30 | // }
31 | //
32 | // InterstitialAd buildInterstitial() {
33 | // return InterstitialAd(
34 | // adUnitId: InterstitialAd.testAdUnitId,
35 | // targetingInfo: targetingInfo,
36 | // listener: (MobileAdEvent event) {
37 | // if (event == MobileAdEvent.failedToLoad) {
38 | // interstitialAd..load();
39 | // } else if (event == MobileAdEvent.closed) {
40 | // interstitialAd = buildInterstitial()..load();
41 | // }
42 | // print('InterstitialAd:$event');
43 | // });
44 | // }
45 | //
46 | // @override
47 | // void initState() {
48 | // FirebaseAdMob.instance.initialize(appId: FirebaseAdMob.testAppId);
49 | // bannerAd = buildBanner()..load();
50 | // interstitialAd = buildInterstitial()..load();
51 | // super.initState();
52 | // }
53 | //
54 | // @override
55 | // void dispose() {
56 | // bannerAd?.dispose();
57 | // interstitialAd?.dispose();
58 | // super.dispose();
59 | // }
60 | //
61 | // @override
62 | // Widget build(BuildContext context) {
63 | // return new Scaffold(
64 | // appBar: new AppBar(
65 | // title: new Text("Admob"),
66 | // centerTitle: true,
67 | // ),
68 | // floatingActionButton: new FloatingActionButton(
69 | // child: new Text("ad"),
70 | // onPressed: () {
71 | // interstitialAd
72 | // ..load()
73 | // ..show();
74 | // }),
75 | // );
76 | // }
77 | //}
78 |
--------------------------------------------------------------------------------
/lib/widget/demo_base_widget/base_widget_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class BaseWidgetPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _BaseWidgetPageState();
8 | }
9 | }
10 |
11 | class _BaseWidgetPageState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return new Scaffold(
16 | appBar: new AppBar(
17 | title: new Text('基础Widget 学习'),
18 | centerTitle: true,
19 | ),
20 | body: new ListView(
21 | children: [
22 | new Padding(
23 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
24 | child: new RaisedButton(
25 | textColor: Colors.black,
26 | child: new Text('Container'),
27 | onPressed: () {
28 | Navigator.pushNamed(context, "/ContainerPage");
29 | }),
30 | ),
31 | ],
32 | ),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/widget/demo_base_widget/container_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ContainerPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | return new _ContainerPageState();
7 | }
8 | }
9 |
10 | class _ContainerPageState extends State {
11 | @override
12 | Widget build(BuildContext context) {
13 | return new Scaffold(
14 | appBar: new AppBar(
15 | title: new Text("Container"),
16 | centerTitle: true,
17 | ),
18 | body: new Container(
19 | child: new Center(
20 | child: Transform(
21 | transform: Matrix4.identity(),
22 | child: new Container(
23 | height: 200.0,
24 | width: 200.0,
25 | decoration: new BoxDecoration(
26 | //圆形渐变
27 | gradient: new RadialGradient(
28 | colors: [Colors.blue, Colors.blue[100]]),
29 | //Container形状
30 | // borderRadius: BorderRadius.circular(100.0),
31 | //改变线的颜色
32 | // border: Border.all(color: Colors.black),
33 | //增加阴影
34 | // boxShadow: [
35 | // BoxShadow(
36 | // color: Colors.blue[100],
37 | // offset: new Offset(0.0, 2.0),
38 | // blurRadius: 5.0,
39 | // )
40 | // ],
41 | //Container形状
42 | shape: BoxShape.circle,
43 | ),
44 | ),
45 | ),
46 | ),
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/widget/demo_common/hide_and_show_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class HideAndShowPage extends StatefulWidget {
5 | @override
6 | State createState() {
7 | return new _HideAndShowPageState();
8 | }
9 | }
10 |
11 | class _HideAndShowPageState extends State {
12 | bool visible = true;
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return new Scaffold(
17 | appBar: new AppBar(
18 | title: new Text('widget显示与隐藏'),
19 | centerTitle: true,
20 | ),
21 | body: new ListView(
22 | children: [
23 | new Padding(
24 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
25 | child: new RaisedButton(
26 | textColor: Colors.black,
27 | child: new Text(visible ? '隐藏B 隐藏c 显示A ' : '隐藏A 显示c 显示B'),
28 | onPressed: () {
29 | visible = !visible;
30 | setState(() {});
31 | }),
32 | ),
33 | new Padding(
34 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
35 | child: new Stack(
36 | children: [
37 | new TestAWidget(
38 | visible: visible,
39 | ),
40 | new TestBWidget(
41 | visible: !visible,
42 | ),
43 | ],
44 | ),
45 | ),
46 | new Padding(
47 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
48 | child: new TestCWidget(visible: visible),
49 | ),
50 | ],
51 | ),
52 | );
53 | }
54 | }
55 |
56 |
57 |
58 |
59 |
60 | class TestAWidget extends StatelessWidget {
61 | final bool visible;
62 |
63 | const TestAWidget({Key key, this.visible}) : super(key: key);
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 | return AnimatedOpacity(
68 | duration: Duration(milliseconds: 300),
69 | opacity: visible ? 1.0 : 0.0,
70 | child: new Container(
71 | color: Colors.blue,
72 | height: 100.0,
73 | child: new Center(
74 | child: new Text('TestAWidget'),
75 | ),
76 | ),
77 | );
78 | }
79 | }
80 |
81 | class TestBWidget extends StatelessWidget {
82 | final bool visible;
83 |
84 | const TestBWidget({Key key, this.visible}) : super(key: key);
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | return AnimatedOpacity(
89 | duration: Duration(milliseconds: 300),
90 | opacity: visible ? 1.0 : 0.0,
91 | child: new Container(
92 | color: Colors.green,
93 | height: 100.0,
94 | child: new Center(
95 | child: new Text('TestBWidget'),
96 | ),
97 | ),
98 | );
99 | }
100 | }
101 |
102 |
103 |
104 |
105 | class TestCWidget extends StatelessWidget {
106 | final bool visible;
107 |
108 | const TestCWidget({Key key, this.visible}) : super(key: key);
109 |
110 | @override
111 | Widget build(BuildContext context) {
112 | return new Offstage(
113 | offstage: visible,
114 | child:new Container(
115 | color: Colors.orange,
116 | height: 100.0,
117 | child: new Center(
118 | child: new Text('TestCWidget'),
119 | ),
120 | ),
121 | );
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/lib/widget/demo_common/test.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_study/model/search_model.dart';
4 | import 'package:rxdart/rxdart.dart';
5 |
6 | Stream timedCounter(Duration interval, [int maxCount]) {
7 | StreamController controller;
8 | Timer timer;
9 | int counter = 0;
10 |
11 | void tick(_) {
12 | counter++;
13 | controller.add(counter); // Ask stream to send counter values as event.
14 | if (maxCount != null && counter >= maxCount) {
15 | timer.cancel();
16 | controller.close(); // Ask stream to shut down and tell listeners.
17 | }
18 | }
19 |
20 | void startTimer() {
21 | timer = new Timer.periodic(interval, tick);
22 | }
23 |
24 | void stopTimer() {
25 | if (timer != null) {
26 | timer.cancel();
27 | timer = null;
28 | }
29 | }
30 |
31 | controller = new StreamController(
32 | onListen: startTimer,
33 | onPause: stopTimer,
34 | onResume: startTimer,
35 | onCancel: stopTimer);
36 |
37 | return controller.stream;
38 | }
39 |
40 | main() {
41 | // Stream counterStream = timedCounter(const Duration(seconds: 1), 10).map((int x){
42 | // return x * 1;
43 | // });
44 | //
45 | // StreamSubscription subscription;
46 | // subscription = counterStream.listen((int counter) {
47 | // print(counter); // Print an integer every second.
48 | // if (counter == 5) {
49 | // // After 5 ticks, pause for five seconds, then resume.
50 | // subscription.pause();
51 | // new Timer(const Duration(seconds: 5), subscription.resume);
52 | // }
53 | // });
54 |
55 | // new Timer(new Duration(seconds: 5), (){
56 | // counterStream.listen((int x){
57 | // print(x);
58 | // });
59 | // });
60 |
61 |
62 | // new Observable(new Stream.fromIterable([1]))
63 | // .interval(new Duration(seconds: 1))
64 | // .flatMap((i) => new Observable.just([1,2,3,4]))
65 | // .take(1)
66 | // .listen(print);
67 |
68 | // final subject = new PublishSubject();
69 |
70 | // observer1 will receive all data and done events
71 | // subject.stream.listen((int x){
72 | // print('observer1:$x');
73 | // });
74 | // subject.add(1);
75 | // subject.add(2);
76 |
77 | // observer2 will only receive 3 and done event
78 | // subject.stream.listen((int x){
79 | // print('observer2:$x');
80 | // });
81 | // subject.add(3);
82 | // subject.close();
83 |
84 |
85 | // final subject = new BehaviorSubject(); // ignore: close_sinks
86 |
87 | // subject.add(1);
88 | // subject.add(2);
89 | // subject.add(3);
90 | //
91 | // subject.stream.listen(print); // prints 3
92 | // subject.stream.listen(print); // prints 3
93 | // subject.stream.listen(print); // prints 3
94 |
95 |
96 | // final subject = new ReplaySubject(maxSize: 2);
97 | //
98 | // subject.add(1);
99 | // subject.add(2);
100 | // subject.add(3);
101 | //
102 | // subject.stream.listen(print); // prints 1, 2, 3
103 | // subject.stream.listen(print); // prints 1, 2, 3
104 | // subject.stream.listen(print); // prints 1, 2, 3
105 |
106 |
107 | // new ConcatStream([
108 | // new Stream.fromIterable([1]),
109 | // new TimerStream(2, new Duration(days: 1)),
110 | // new Stream.fromIterable([3])
111 | // ])
112 | // .listen(print);
113 |
114 |
115 | // new Observable.fromIterable([1, 2]).withLatestFrom(
116 | // new Observable.fromIterable([2, 3]), (a, b) => a + b)
117 | // .listen(print);
118 |
119 |
120 |
121 | var data = [1,2,3,4,5];
122 | var stream = new Stream.fromIterable(data);
123 | var broadcastStream = stream.asBroadcastStream();
124 |
125 | broadcastStream
126 | .any((value) => value < 5)
127 | .then((result) => print("Any less than 5?: $result")); // true
128 |
129 | broadcastStream
130 | .every((value) => value < 5)
131 | .then((result) => print("All less than 5?: $result")); // false
132 |
133 | broadcastStream
134 | .contains(4)
135 | .then((result) => print("Contains 4?: $result")); // true
136 | }
137 |
138 |
--------------------------------------------------------------------------------
/lib/widget/demo_custom_toast/blinking_toast.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_study/widget/demo_custom_toast/toast_page.dart';
4 |
5 | class BlinkingToast {
6 | bool _isVisible = false;
7 |
8 | ///
9 | /// BuildContext context: the context from which we need to retrieve the Overlay
10 | /// WidgetBuilder externalBuilder: (compulsory) external routine that builds the Widget to be displayed
11 | /// Duration duration: (optional) duration after which the Widget will be removed
12 | /// Offset position: (optional) position where you want to show the Widget
13 | ///
14 | void show({
15 | @required BuildContext context,
16 | @required WidgetBuilder externalBuilder,
17 | Duration duration = const Duration(seconds: 2),
18 | Offset position = Offset.zero,
19 | }) async {
20 |
21 | // Prevent from showing multiple Widgets at the same time
22 | if (_isVisible){
23 | return;
24 | }
25 |
26 | _isVisible = true;
27 |
28 | OverlayState overlayState = Overlay.of(context);
29 | OverlayEntry overlayEntry = new OverlayEntry(
30 | builder: (BuildContext context) => new BlinkingToastWidget(
31 | widget: externalBuilder(context),
32 | position: position,
33 | ),
34 | );
35 | overlayState.insert(overlayEntry);
36 |
37 | await new Future.delayed(duration);
38 |
39 | overlayEntry.remove();
40 |
41 | _isVisible = false;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/widget/demo_custom_toast/show_notification.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 |
4 | class ShowNotificationIcon {
5 |
6 | void show(BuildContext context) async {
7 | OverlayState overlayState = Overlay.of(context);
8 | OverlayEntry overlayEntry = new OverlayEntry(builder: _build);
9 |
10 | overlayState.insert(overlayEntry);
11 |
12 | await new Future.delayed(const Duration(seconds: 2));
13 |
14 | overlayEntry.remove();
15 | }
16 |
17 | Widget _build(BuildContext context){
18 | return new Positioned(
19 | top: 50.0,
20 | left: 50.0,
21 | child: new Material(
22 | color: Colors.transparent,
23 | child: new Icon(Icons.warning, color: Colors.purple),
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/widget/demo_custom_toast/toast_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class BlinkingToastWidget extends StatefulWidget {
4 | BlinkingToastWidget({
5 | Key key,
6 | @required this.widget,
7 | @required this.position,
8 | }): super(key: key);
9 |
10 | final Widget widget;
11 | final Offset position;
12 |
13 | @override
14 | _BlinkingToastWidgetState createState() => new _BlinkingToastWidgetState();
15 | }
16 |
17 | class _BlinkingToastWidgetState extends State
18 | with SingleTickerProviderStateMixin {
19 |
20 | AnimationController _controller;
21 | Animation _animation;
22 |
23 | @override
24 | void initState() {
25 | super.initState();
26 | _controller = new AnimationController(
27 | duration: const Duration(milliseconds: 500), vsync: this);
28 | _animation = new Tween(begin: 0.0, end: 1.0).animate(new CurvedAnimation(
29 | parent: _controller,
30 | curve: new Interval(0.0, 0.5)
31 | ))
32 | ..addListener(() {
33 | if (mounted){
34 | setState(() {
35 | // Refresh
36 | });
37 | }
38 | })
39 | ..addStatusListener((AnimationStatus status){
40 | if (status == AnimationStatus.completed){
41 | _controller.reverse().orCancel;
42 | } else if (status == AnimationStatus.dismissed){
43 | _controller.forward().orCancel;
44 | }
45 | });
46 | _controller.forward().orCancel;
47 | }
48 |
49 | @override
50 | void dispose() {
51 | _controller.dispose();
52 | super.dispose();
53 | }
54 |
55 | @override
56 | Widget build(BuildContext context) {
57 | return new Positioned(
58 | top: widget.position.dy,
59 | left: widget.position.dx,
60 | child: new IgnorePointer(
61 | child: new Material(
62 | color: Colors.transparent,
63 | child: new Opacity(
64 | opacity: _animation.value,
65 | child: widget.widget,
66 | ),
67 | ),
68 | ));
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/widget/demo_gesture/dismissed_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class DismissedAppPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _DismissedAppPageState();
8 | }
9 | }
10 |
11 | class _DismissedAppPageState extends State {
12 | List list = [
13 | 'A',
14 | 'B',
15 | 'C',
16 | 'D',
17 | 'E',
18 | 'F',
19 | 'G',
20 | 'H',
21 | 'I',
22 | 'J',
23 | 'K',
24 | 'L'
25 | ];
26 |
27 | _showSnakeBar(String str) {
28 | final snackBar = new SnackBar(content: new Text(str));
29 | Scaffold.of(context).showSnackBar(snackBar);
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | // TODO: implement build
35 | return new Scaffold(
36 | appBar: new AppBar(
37 | title: new Text('Dismissed 学习'),
38 | centerTitle: true,
39 | ),
40 | body: new ListView.builder(
41 | itemCount: list.length,
42 | itemBuilder: (context, index) {
43 | final String curItem = list[index];
44 |
45 | return new Dismissible(
46 | key: new Key(curItem),
47 | direction: DismissDirection.endToStart,
48 | onDismissed: (direction) {
49 | list.removeAt(index);
50 | _showSnakeBar("$curItem 被划走了");
51 | },
52 | background: new Container(
53 | child: new Center(
54 | child: new Text('即将被删除'),
55 | ),
56 | color: Colors.red),
57 | child: new ListTile(
58 | title: new Text(curItem),
59 | ));
60 | }),
61 | );
62 | }
63 | }
64 |
65 | class DismissedPage extends StatelessWidget {
66 | @override
67 | Widget build(BuildContext context) {
68 | // TODO: implement build
69 | return new Scaffold(
70 | body: new DismissedAppPage(),
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/widget/demo_gesture/gesture_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class GestureAppPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _GestureAppPageState();
8 | }
9 | }
10 |
11 | class _GestureAppPageState extends State {
12 |
13 | var tapEvent = '';
14 |
15 | _showSnakeBar(String str) {
16 | final snackBar = new SnackBar(content: new Text(str));
17 | Scaffold.of(context).showSnackBar(snackBar);
18 | }
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | // TODO: implement build
23 | return new Scaffold(
24 | appBar: new AppBar(
25 | title: new Text('Gesture 学习'),
26 | centerTitle: true,
27 | ),
28 | body: new ListView(
29 | children: [
30 | new Padding(
31 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
32 | child: new RaisedButton(
33 | textColor: Colors.black,
34 | child: new Text('RaisedButton 点击'),
35 | onPressed: () {
36 | _showSnakeBar("这是一个 RaisedButton 点击事件,onPressed处理");
37 | }),
38 | ),
39 | new Padding(
40 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
41 | child: new GestureDetector(
42 | onTap: () {
43 | _showSnakeBar("这是一个GestureDetector监听的onTap事件");
44 | },
45 | child: new BorderButton('GestureDetector onTap 按钮'),
46 | ),
47 | ),
48 | new Padding(
49 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
50 | child:
51 | new Text(tapEvent, style: Theme.of(context).textTheme.display1),
52 | ),
53 | new Padding(
54 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
55 | child: new GestureDetector(
56 | onTapDown: (tapDown) {
57 | setState(() {
58 | tapEvent = '这是GestureDetector监听的onTapDown事件';
59 | });
60 | },
61 | onTapUp: (tapUp) {
62 | setState(() {
63 | tapEvent = '这是GestureDetector监听的onTapUp事件';
64 | });
65 | },
66 | onTapCancel: () {
67 | setState(() {
68 | tapEvent = '这是GestureDetector监听的onTapCancel事件';
69 | });
70 | },
71 | onDoubleTap: () {
72 | setState(() {
73 | tapEvent = '这是GestureDetector监听的onDoubleTap事件';
74 | });
75 | },
76 | onLongPress: () {
77 | setState(() {
78 | tapEvent = '这是GestureDetector监听的onLongPress事件';
79 | });
80 | },
81 | child: new BorderButton('GestureDetector onTap 分解事件按钮'),
82 | ),
83 | ),
84 | new Padding(
85 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
86 | child: new Text('上面的按钮通过GestureDetector监听事件后,涟漪效果消失了,使用下面的方案解决'),
87 | ),
88 | new Padding(
89 | padding:
90 | const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
91 | child: new InkWell(
92 | borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
93 | onTap: () {
94 | _showSnakeBar("这是一个InkWell监听的onTap事件");
95 | },
96 | child: new BorderButton('InkWell 按钮'),
97 | )),
98 | new Padding(
99 | padding:
100 | const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
101 | child: new InkWell(
102 | borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
103 | onTap: () {
104 | Navigator.pushNamed(context, '/DismissedPage');
105 | },
106 | child: new BorderButton('Dismissed 手势'),
107 | )),
108 | ],
109 | ),
110 | );
111 | }
112 | }
113 |
114 | class BorderButton extends StatelessWidget {
115 | final String text;
116 |
117 | BorderButton(this.text);
118 |
119 | @override
120 | Widget build(BuildContext context) {
121 | // TODO: implement build
122 | return new Container(
123 | alignment: Alignment.center,
124 | padding: const EdgeInsets.only(
125 | left: 10.0, top: 10.0, right: 10.0, bottom: 10.0),
126 | height: 48.0,
127 | decoration: new BoxDecoration(
128 | border: new Border.all(
129 | width: 1.0,
130 | color: Colors.blue,
131 | ),
132 | borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
133 | ),
134 | // foregroundDecoration: new BoxDecoration(
135 | // border: new Border.all(
136 | // width: 1.0,
137 | // color: Colors.red,
138 | // ),
139 | // borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
140 | // ),
141 | child: new Text(text),
142 | );
143 | }
144 | }
145 |
146 | class GesturePage extends StatelessWidget {
147 | @override
148 | Widget build(BuildContext context) {
149 | // TODO: implement build
150 | return new Scaffold(
151 | body: new GestureAppPage(),
152 | );
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/lib/widget/demo_gesture/multi_touch_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const double _kMinFlingVelocity = 800.0;
4 |
5 | class MultiTouchAppPage extends StatefulWidget {
6 | final String imgUrl;
7 |
8 | MultiTouchAppPage(this.imgUrl);
9 |
10 | @override
11 | State createState() {
12 | return new _MultiTouchAppPage();
13 | }
14 | }
15 |
16 | class _MultiTouchAppPage extends State
17 | with SingleTickerProviderStateMixin {
18 | AnimationController _controller;
19 | Animation _flingAnimation;
20 | Offset _offset = Offset.zero;
21 | double _scale = 1.0;
22 | Offset _normalizedOffset;
23 | double _previousScale;
24 |
25 | @override
26 | void initState() {
27 | super.initState();
28 | _controller = new AnimationController(vsync: this)
29 | ..addListener(_handleFlingAnimation);
30 | }
31 |
32 | @override
33 | void dispose() {
34 | _controller.dispose();
35 | super.dispose();
36 | }
37 |
38 | // The maximum offset value is 0,0. If the size of this renderer's box is w,h
39 | // then the minimum offset value is w - _scale * w, h - _scale * h.
40 | Offset _clampOffset(Offset offset) {
41 | final Size size = context.size;
42 | final Offset minOffset =
43 | new Offset(size.width, size.height) * (1.0 - _scale);
44 | return new Offset(
45 | offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0));
46 | }
47 |
48 | void _handleFlingAnimation() {
49 | setState(() {
50 | _offset = _flingAnimation.value;
51 | });
52 | }
53 |
54 | void _handleOnScaleStart(ScaleStartDetails details) {
55 | setState(() {
56 | _previousScale = _scale;
57 | _normalizedOffset = (details.focalPoint - _offset) / _scale;
58 | // The fling animation stops if an input gesture starts.
59 | _controller.stop();
60 | });
61 | }
62 |
63 | void _handleOnScaleUpdate(ScaleUpdateDetails details) {
64 | setState(() {
65 | _scale = (_previousScale * details.scale).clamp(1.0, 4.0);
66 | // Ensure that image location under the focal point stays in the same place despite scaling.
67 | _offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale);
68 | });
69 | }
70 |
71 | void _handleOnScaleEnd(ScaleEndDetails details) {
72 | final double magnitude = details.velocity.pixelsPerSecond.distance;
73 | if (magnitude < _kMinFlingVelocity) return;
74 | final Offset direction = details.velocity.pixelsPerSecond / magnitude;
75 | final double distance = (Offset.zero & context.size).shortestSide;
76 | _flingAnimation = new Tween(
77 | begin: _offset, end: _clampOffset(_offset + direction * distance))
78 | .animate(_controller);
79 | _controller
80 | ..value = 0.0
81 | ..fling(velocity: magnitude / 1000.0);
82 | }
83 |
84 | @override
85 | Widget build(BuildContext context) {
86 | return new GestureDetector(
87 | onScaleStart: _handleOnScaleStart,
88 | onScaleUpdate: _handleOnScaleUpdate,
89 | onScaleEnd: _handleOnScaleEnd,
90 | child: new ClipRect(
91 | child: new Transform(
92 | transform: new Matrix4.identity()
93 | ..translate(_offset.dx, _offset.dy)
94 | ..scale(_scale),
95 | child: new Image.network(
96 | widget.imgUrl,
97 | fit: BoxFit.cover,
98 | ),
99 | ),
100 | ),
101 | );
102 | }
103 | }
104 |
105 | class MultiTouchPage extends StatelessWidget {
106 | final String imgUrl;
107 |
108 | MultiTouchPage(this.imgUrl);
109 |
110 | @override
111 | Widget build(BuildContext context) {
112 | return new Scaffold(
113 | appBar: new AppBar(
114 | title: new Text('多点触控'),
115 | centerTitle: true,
116 | ),
117 | body: new MultiTouchAppPage(imgUrl),
118 | );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/lib/widget/demo_inherited/inherited_w_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/model/inherited_test_model.dart';
3 | import 'package:flutter_study/widget/demo_inherited/inherited_w_test_a.dart';
4 | import 'package:flutter_study/widget/demo_inherited/inherited_w_test_b.dart';
5 | import 'package:flutter_study/widget/demo_inherited/inherited_w_test_c.dart';
6 |
7 | class InheritedContext extends InheritedWidget {
8 |
9 | //数据
10 | final InheritedTestModel inheritedTestModel;
11 |
12 | //点击+号的方法
13 | final Function() increment;
14 |
15 | //点击-号的方法
16 | final Function() decrement;
17 |
18 | InheritedContext({
19 | Key key,
20 | @required this.inheritedTestModel,
21 | @required this.increment,
22 | @required this.decrement,
23 | @required Widget child,
24 | }) : super(key: key, child: child);
25 |
26 | static InheritedContext of(BuildContext context) {
27 | return context.inheritFromWidgetOfExactType(InheritedContext);
28 | }
29 |
30 | //是否重建widget就取决于数据是否相同
31 | @override
32 | bool updateShouldNotify(InheritedContext oldWidget) {
33 | return inheritedTestModel != oldWidget.inheritedTestModel;
34 | }
35 | }
36 |
37 | class InheritedWidgetTestContainer extends StatefulWidget {
38 | @override
39 | State createState() {
40 | return new _InheritedWidgetTestContainerState();
41 | }
42 | }
43 |
44 | class _InheritedWidgetTestContainerState
45 | extends State {
46 | InheritedTestModel inheritedTestModel;
47 |
48 | _initData() {
49 | inheritedTestModel = new InheritedTestModel(0);
50 | }
51 |
52 | @override
53 | void initState() {
54 | _initData();
55 | super.initState();
56 | }
57 |
58 | _incrementCount() {
59 | setState(() {
60 | inheritedTestModel = new InheritedTestModel(inheritedTestModel.count + 1);
61 | });
62 | }
63 |
64 | _decrementCount() {
65 | setState(() {
66 | inheritedTestModel = new InheritedTestModel(inheritedTestModel.count - 1);
67 | });
68 | }
69 |
70 | @override
71 | Widget build(BuildContext context) {
72 | return new InheritedContext(
73 | inheritedTestModel: inheritedTestModel,
74 | increment: _incrementCount,
75 | decrement: _decrementCount,
76 | child: new Scaffold(
77 | appBar: new AppBar(
78 | title: new Text('InheritedWidget'),
79 | centerTitle: true,
80 | ),
81 | body: new Column(
82 | children: [
83 | new Padding(
84 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
85 | child: new Text('我们常使用的\nTheme.of(context).textTheme\nMediaQuery.of(context).size等\n就是通过InheritedWidget实现的',
86 | style: new TextStyle(fontSize: 20.0),),
87 | ),
88 | new TestWidgetA(),
89 | new TestWidgetB(),
90 | new TestWidgetC(),
91 | ],
92 | ),
93 | ));
94 | }
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/lib/widget/demo_inherited/inherited_w_test_a.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_inherited/inherited_w_test_b.dart';
3 | import 'package:flutter_study/widget/demo_inherited/inherited_w_page.dart';
4 |
5 | class TestWidgetA extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | final inheritedContext = InheritedContext.of(context);
9 |
10 | final inheritedTestModel = inheritedContext.inheritedTestModel;
11 |
12 | print('TestWidgetA 中count的值: ${inheritedTestModel.count}');
13 | return new Padding(
14 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
15 | child: new RaisedButton(
16 | textColor: Colors.black,
17 | child: new Text('+'),
18 | onPressed: inheritedContext.increment),
19 | );
20 | }
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/lib/widget/demo_inherited/inherited_w_test_b.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_inherited/inherited_w_page.dart';
3 |
4 |
5 | class TestWidgetB extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 |
9 | final inheritedContext = InheritedContext.of(context);
10 |
11 | final inheritedTestModel = inheritedContext.inheritedTestModel;
12 |
13 | print('TestWidgetB 中count的值: ${inheritedTestModel.count}');
14 |
15 | return new Padding(
16 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
17 | child: new Text('当前count:${inheritedTestModel.count}',style: new TextStyle(fontSize: 20.0),),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/widget/demo_inherited/inherited_w_test_c.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_inherited/inherited_w_page.dart';
3 |
4 |
5 | class TestWidgetC extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 |
9 | final inheritedContext = InheritedContext.of(context);
10 |
11 | final inheritedTestModel = inheritedContext.inheritedTestModel;
12 |
13 | print('TestWidgetC 中count的值: ${inheritedTestModel.count}');
14 |
15 | return new Padding(
16 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
17 | child: new RaisedButton(
18 | textColor: Colors.black,
19 | child: new Text('-'),
20 | onPressed: inheritedContext.decrement),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/widget/demo_key/globalkey_form_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class GlobalKeyFromPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | return new _GlobalKeyFromPageState();
7 | }
8 | }
9 |
10 | class _GlobalKeyFromPageState extends State {
11 |
12 | final scaffoldKey = GlobalKey();
13 |
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return new Scaffold(
18 | key: scaffoldKey,
19 | appBar: new AppBar(
20 | title: new Text("GlobalKey"),
21 | centerTitle: true,
22 | ),
23 | body: new ListView(
24 | children: [
25 | new FormOnePage(scaffoldKey),
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
32 | class FormOnePage extends StatefulWidget {
33 |
34 | final _key;
35 |
36 | FormOnePage(this._key);
37 |
38 | @override
39 | State createState() {
40 | return new _FormOnePageState();
41 | }
42 | }
43 |
44 | class _FormOnePageState extends State {
45 | final formKey = GlobalKey();
46 |
47 |
48 | String _phoneNum;
49 |
50 | @override
51 | Widget build(BuildContext context) {
52 | return new Padding(
53 | padding: EdgeInsets.all(10.0),
54 | child: new Form(
55 | key: formKey,
56 | child: new Column(
57 | children: [
58 | TextFormField(
59 | autocorrect: false,
60 | decoration: new InputDecoration(
61 | hintText: '请输入手机号',
62 | ),
63 | maxLines: 1,
64 | maxLength: 11,
65 | //键盘展示为号码
66 | keyboardType: TextInputType.phone,
67 | validator: (str) {
68 | return str.isEmpty?"手机号不能为空":null;
69 | },
70 | onSaved: (str) {
71 | _phoneNum = str;
72 | },
73 | ),
74 | RaisedButton(
75 | child: Text( "提交"),
76 | onPressed: onPressed,
77 | ),
78 | ],
79 | )));
80 | }
81 |
82 | void onPressed() {
83 | var form = formKey.currentState;
84 |
85 | if (form.validate()) {
86 | form.save();
87 | var snackBar = SnackBar(content: Text('phone: $_phoneNum'));
88 |
89 | widget._key.currentState.showSnackBar(snackBar);
90 |
91 | }
92 | }
93 | }
94 |
95 | class FormTwoPage extends StatefulWidget {
96 | @override
97 | State createState() {
98 | return new _FormTwoPageState();
99 | }
100 | }
101 |
102 | class _FormTwoPageState extends State {
103 | @override
104 | Widget build(BuildContext context) {
105 | return new Text("form b");
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/widget/demo_lifecycle/lifecycle_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class LifecycleAppPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | return new _LifecycleAppPageState('构造函数');
7 | }
8 | }
9 |
10 | class _LifecycleAppPageState extends State
11 | with WidgetsBindingObserver {
12 | String str;
13 |
14 | _LifecycleAppPageState(this.str);
15 |
16 | @override
17 | void initState() {
18 | print(str);
19 | print('initState');
20 | super.initState();
21 | WidgetsBinding.instance.addObserver(this);
22 | }
23 |
24 | @override
25 | void didChangeDependencies() {
26 | print('didChangeDependencies');
27 | super.didChangeDependencies();
28 | }
29 |
30 | @override
31 | void didUpdateWidget(LifecycleAppPage oldWidget) {
32 | print('didUpdateWidget');
33 | super.didUpdateWidget(oldWidget);
34 | }
35 |
36 | @override
37 | void deactivate() {
38 | print('deactivate');
39 | super.deactivate();
40 | }
41 |
42 | @override
43 | void dispose() {
44 | print('dispose');
45 | WidgetsBinding.instance.removeObserver(this);
46 | super.dispose();
47 | }
48 |
49 | @override
50 | void didChangeAppLifecycleState(AppLifecycleState state) {
51 | switch (state) {
52 | case AppLifecycleState.inactive:
53 | print('AppLifecycleState.inactive');
54 | break;
55 | case AppLifecycleState.paused:
56 | print('AppLifecycleState.paused');
57 | break;
58 | case AppLifecycleState.resumed:
59 | print('AppLifecycleState.resumed');
60 | break;
61 | case AppLifecycleState.suspending:
62 | print('AppLifecycleState.suspending');
63 | break;
64 | }
65 |
66 | super.didChangeAppLifecycleState(state);
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | print('build');
72 | return new Scaffold(
73 | appBar: new AppBar(
74 | title: new Text('lifecycle 学习'),
75 | centerTitle: true,
76 | ),
77 | body: new Column(
78 | children: [
79 | new Image.asset('images/lifecycle.png'),
80 | new Text('查看日志打印的状态'),
81 | ],
82 | ),
83 | );
84 | }
85 | }
86 |
87 | class LifecyclePage extends StatelessWidget {
88 | @override
89 | Widget build(BuildContext context) {
90 | // TODO: implement build
91 | return new Scaffold(
92 | body: new LifecycleAppPage(),
93 | );
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/lib/widget/demo_loadimg/loadIm_by_loc_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class LoadImgByLocAppPage extends StatefulWidget {
4 | @override
5 | State createState() {
6 | // TODO: implement createState
7 | return new _LoadImgByLocAppPageState();
8 | }
9 | }
10 |
11 | class _LoadImgByLocAppPageState extends State{
12 |
13 | @override
14 | void initState() {
15 | // TODO: implement initState
16 | super.initState();
17 | print('_LoadImgByLocAppPageState initState');
18 | }
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | // TODO: implement build
23 | return new Scaffold(
24 | body: new ListView(
25 | key: new PageStorageKey(_LoadImgByLocAppPageState),
26 | children: [
27 | new Image.asset('images/ic_assignment_ind_36pt.png'),
28 | new Divider(),
29 | new Image(
30 | image: new AssetImage('images/ic_assignment_ind_36pt.png'),
31 | ),
32 | new Divider(),
33 | ],
34 | ),
35 | );
36 | }
37 |
38 | }
39 |
40 | class LoadImgByLocPage extends StatelessWidget {
41 | @override
42 | Widget build(BuildContext context) {
43 | // TODO: implement build
44 | return new Scaffold(
45 | body: new LoadImgByLocAppPage(),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/widget/demo_loadimg/loadImg_by_net_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:transparent_image/transparent_image.dart';
3 | import 'package:cached_network_image/cached_network_image.dart';
4 | const String imgNormalUrl =
5 | 'https://ww1.sinaimg.cn/large/0065oQSqly1fs02a9b0nvj30sg10vk4z.jpg';
6 |
7 | const String imgGifUrl =
8 | 'http://s1.dwstatic.com/group1/M00/B3/31/6b640ceb4277d3993abb7422d61dd288.gif';
9 |
10 | const int loadNormalImg = 0;
11 | const int loadGifImg = 1;
12 | const int loadImgWithCache = 2;
13 | const int loadImgWithFade = 3;
14 |
15 | class LoadImgByNetAppPage extends StatefulWidget {
16 | @override
17 | State createState() {
18 | // TODO: implement createState
19 | return new _LoadImgByNetAppPageState();
20 | }
21 | }
22 |
23 | class _LoadImgByNetAppPageState extends State{
24 | int curLoadWay = loadNormalImg;
25 |
26 | String curImageUrl = imgNormalUrl;
27 |
28 | _loadNormalImg() {
29 | curLoadWay = loadNormalImg;
30 | curImageUrl = imgNormalUrl;
31 | setState(() {});
32 | }
33 |
34 | _loadGifImg() {
35 | curLoadWay = loadGifImg;
36 | curImageUrl = imgGifUrl;
37 | setState(() {});
38 | }
39 |
40 | _loadImgWithCache() {
41 | curLoadWay = loadImgWithCache;
42 | curImageUrl = imgNormalUrl;
43 | setState(() {});
44 | }
45 |
46 | _loadImgWithFade() {
47 | curLoadWay = loadImgWithFade;
48 | curImageUrl = imgNormalUrl;
49 | setState(() {});
50 | }
51 |
52 | @override
53 | void initState() {
54 | // TODO: implement initState
55 | super.initState();
56 | print('_LoadImgByNetAppPageState initState');
57 | }
58 |
59 | @override
60 | Widget build(BuildContext context) {
61 | // TODO: implement build
62 | return new Scaffold(
63 | body: new ListView(
64 | key: new PageStorageKey(_LoadImgByNetAppPageState),
65 | children: [
66 | new Padding(
67 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
68 | child: new RaisedButton(
69 | child: new Text('加载普通图片'), onPressed: _loadNormalImg),
70 | ),
71 | new Padding(
72 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
73 | child: new RaisedButton(
74 | child: new Text('加载gif图片'), onPressed: _loadGifImg),
75 | ),
76 | new Padding(
77 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
78 | child: new RaisedButton(
79 | child: new Text('加载缓存图片'), onPressed: _loadImgWithCache),
80 | ),
81 | new Padding(
82 | padding: const EdgeInsets.only(
83 | left: 10.0, top: 10.0, right: 10.0, bottom: 10.0),
84 | child: new RaisedButton(
85 | child: new Text('淡入动画加载图片'), onPressed: _loadImgWithFade),
86 | ),
87 | new ImageView(curImageUrl, curLoadWay),
88 | ],
89 | ),
90 | );
91 | }
92 |
93 | }
94 |
95 | class ImageView extends StatelessWidget {
96 |
97 | final String imgUrl;
98 |
99 | final int loadWay;
100 |
101 | ImageView(this.imgUrl, this.loadWay);
102 |
103 | @override
104 | Widget build(BuildContext context) {
105 |
106 | Widget widget = new Icon(Icons.error);
107 |
108 | switch (loadWay) {
109 | case loadNormalImg:
110 | case loadGifImg:
111 | widget = new Image.network(imgUrl);
112 | break;
113 | case loadImgWithCache:
114 | widget = new CachedNetworkImage(
115 | imageUrl: imgUrl,
116 | placeholder: new CircularProgressIndicator(),
117 | errorWidget: new Icon(Icons.error),
118 | );
119 | break;
120 | case loadImgWithFade:
121 | widget = new FadeInImage.memoryNetwork(
122 | placeholder: kTransparentImage, image: imgUrl);
123 | break;
124 | }
125 |
126 | return widget;
127 | }
128 | }
129 |
130 | class LoadImgByNetPage extends StatelessWidget {
131 | @override
132 | Widget build(BuildContext context) {
133 | // TODO: implement build
134 | return new Scaffold(
135 | body: new LoadImgByNetAppPage(),
136 | );
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/lib/widget/demo_loadimg/loadImg_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_loadimg/loadIm_by_loc_page.dart';
3 | import 'package:flutter_study/widget/demo_loadimg/loadImg_by_net_page.dart';
4 |
5 | const List tabs = ['网络加载','本地加载'];
6 |
7 | class LoadImgAppPage extends StatefulWidget {
8 | @override
9 | State createState() {
10 | // TODO: implement createState
11 | return new _LoadImgAppPageState();
12 | }
13 | }
14 |
15 | class _LoadImgAppPageState extends State
16 | with SingleTickerProviderStateMixin {
17 | TabController _tabController;
18 |
19 | @override
20 | void initState() {
21 | // TODO: implement initState
22 | super.initState();
23 | _tabController = new TabController(
24 | vsync: this,
25 | length: tabs.length,
26 | );
27 | }
28 |
29 | @override
30 | void dispose() {
31 | _tabController.dispose();
32 | super.dispose();
33 | }
34 |
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | // TODO: implement build
39 | return new Scaffold(
40 | appBar: new AppBar(
41 | title: new TabBar(
42 | controller: _tabController,
43 | isScrollable: true,
44 | indicatorColor: Colors.white,
45 | tabs: tabs.map((String title) {
46 | return new Tab(
47 | text: title,
48 | );
49 | }).toList(),
50 | ),
51 | ),
52 | body: new TabBarView(
53 | controller: _tabController,
54 | children: [
55 | new LoadImgByNetPage(),
56 | new LoadImgByLocPage(),
57 | ]),
58 | );
59 | }
60 | }
61 |
62 | class LoadImgPage extends StatelessWidget {
63 | @override
64 | Widget build(BuildContext context) {
65 | // TODO: implement build
66 | return new Scaffold(
67 | body: new LoadImgAppPage(),
68 | );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/widget/demo_localizations/localizations_study.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class StudyLocalizations {
7 | StudyLocalizations(this.locale);
8 |
9 | final Locale locale;
10 |
11 | static StudyLocalizations of(BuildContext context) {
12 | return Localizations.of(context, StudyLocalizations);
13 | }
14 |
15 | static Map> _localizedValues = {
16 | 'en': {
17 | 'appTitle': 'FlutterStudy',
18 | },
19 | 'zh': {
20 | 'appTitle': 'Flutter学习',
21 | },
22 | };
23 |
24 | String get appTitle {
25 | print(locale.languageCode);
26 | return _localizedValues[locale.languageCode]['appTitle'];
27 | }
28 | }
29 |
30 | class StudyLocalizationsDelegate
31 | extends LocalizationsDelegate {
32 | const StudyLocalizationsDelegate();
33 |
34 | @override
35 | bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);
36 |
37 | @override
38 | Future load(Locale locale) {
39 | return new SynchronousFuture(
40 | new StudyLocalizations(locale));
41 | }
42 |
43 | @override
44 | bool shouldReload(StudyLocalizationsDelegate old) => false;
45 |
46 | static StudyLocalizationsDelegate delegate =
47 | const StudyLocalizationsDelegate();
48 | }
49 |
--------------------------------------------------------------------------------
/lib/widget/demo_notification/notification_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:math';
3 |
4 | class TestNotification extends Notification {
5 | TestNotification({
6 | @required this.count,
7 | });
8 |
9 | final int count;
10 | }
11 |
12 | final GlobalKey key = new GlobalKey();
13 |
14 | final GlobalKey scaffoldStateKey = new GlobalKey();
15 |
16 |
17 | class NotificationPage extends StatefulWidget {
18 |
19 | @override
20 | State createState() {
21 | return new _NotificationPageState();
22 | }
23 | }
24 |
25 |
26 | class _NotificationPageState extends State {
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return new Scaffold(
31 | key: scaffoldStateKey,
32 | appBar: new AppBar(
33 | title: new Text('Notification从下往上数据传递'),
34 | centerTitle: true,
35 | ),
36 | body: new Column(
37 | children: [
38 | new NotificationListener(
39 | onNotification: (TestNotification n) {
40 | scaffoldStateKey.currentState.showSnackBar(new SnackBar(content: new Text('随机数:${n.count}')));
41 | return true;
42 | },
43 | child: new TestAPage(
44 | key: key,
45 | )),
46 | ],
47 | ),
48 | );
49 | }
50 |
51 | }
52 |
53 |
54 | class TestAPage extends StatefulWidget {
55 | TestAPage({Key key}) : super(key: key);
56 |
57 | @override
58 | State createState() {
59 | return new _TestAPageState();
60 | }
61 | }
62 |
63 | class _TestAPageState extends State {
64 | @override
65 | void initState() {
66 | super.initState();
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | return new Padding(
72 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
73 | child: new RaisedButton(
74 | textColor: Colors.black,
75 | child: new Center(
76 | child: new Text('点击传递随机数给上层Widget'),
77 | ),
78 | onPressed: () {
79 | new TestNotification(count: new Random().nextInt(100)).dispatch(key.currentContext);
80 | }),
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/lib/widget/demo_route/route_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_route/route_page_with_value.dart';
3 |
4 | class RouteAppPage extends StatefulWidget {
5 | @override
6 | State createState() {
7 | // TODO: implement createState
8 | return new _RouteAppPageState();
9 | }
10 | }
11 |
12 | class _RouteAppPageState extends State {
13 | var _result;
14 |
15 | _onPressed1() async {
16 | bool value = await Navigator.push(context,
17 | new MaterialPageRoute(builder: (BuildContext context) {
18 | return new Center(
19 | child: new GestureDetector(
20 | child: new Text('OK'),
21 | onTap: () {
22 | Navigator.pop(context, true);
23 | }),
24 | );
25 | }));
26 |
27 | setState(() {
28 | _result = value;
29 | });
30 | }
31 |
32 | _onPresse2() {
33 | showDialog(
34 | context: context,
35 | child: new AlertDialog(content: new Text('这是一个弹窗'), actions: [
36 | new FlatButton(
37 | onPressed: () {
38 | Navigator.pop(context);
39 | },
40 | child: new Text('确定'))
41 | ]),
42 | );
43 | }
44 |
45 | void _onPresse3() {
46 | Navigator.of(context).push(new PageRouteBuilder(
47 | opaque: false,
48 | pageBuilder: (BuildContext context, _, __) {
49 | return new RoutePageWithValue('来自RoutePage路由测试3');
50 | },
51 | transitionsBuilder: (_, Animation animation, __, Widget child) {
52 | return new FadeTransition(
53 | opacity: animation,
54 | child: new RotationTransition(
55 | turns: new Tween(begin: 0.5, end: 1.0).animate(animation),
56 | child: child,
57 | ),
58 | );
59 | }));
60 | }
61 |
62 | void _onPresse4() {
63 | // 带返回值
64 | Navigator.of(context).pushNamed('/RoutePageWithValue1').then((value) {
65 | _result = value;
66 | });
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | return new Scaffold(
72 | appBar: new AppBar(
73 | title: new Text('Route 学习'),
74 | centerTitle: true,
75 | ),
76 | body: new Center(
77 | child: new ListView(
78 | children: [
79 | new Padding(
80 | padding: const EdgeInsets.only(
81 | left: 10.0, top: 10.0, right: 10.0),
82 | child: new RaisedButton(
83 | child: new Text('路由测试1-MaterialPageRoute'),
84 | onPressed: _onPressed1),
85 | ),
86 |
87 | new Padding(
88 | padding: const EdgeInsets.only(
89 | left: 10.0, top: 10.0, right: 10.0),
90 | child: new RaisedButton(
91 | child: new Text('路由测试2-showDialog'), onPressed: _onPresse2),
92 | ),
93 |
94 | new Padding(
95 | padding: const EdgeInsets.only(
96 | left: 10.0, top: 10.0, right: 10.0),
97 | child:
98 | new RaisedButton(
99 | child: new Text('路由测试3-传递参数'), onPressed: _onPresse3),
100 | ),
101 |
102 | new Padding(
103 | padding: const EdgeInsets.only(
104 | left: 10.0, top: 10.0, right: 10.0),
105 | child:
106 | new RaisedButton(
107 | child: new Text('路由测试4-带返回值'), onPressed: _onPresse4),
108 | ),
109 | new Padding(
110 | padding: const EdgeInsets.only(
111 | left: 10.0, top: 10.0, right: 10.0),
112 | child:
113 | new Text('参数: $_result'),
114 |
115 | ),
116 |
117 | ],
118 | ),
119 | ),
120 | );
121 | }
122 | }
123 |
124 | class RoutePage extends StatelessWidget {
125 | @override
126 | Widget build(BuildContext context) {
127 | // TODO: implement build
128 | return new Scaffold(
129 | body: new RouteAppPage(),
130 | );
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/lib/widget/demo_route/route_page_with_value.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class RoutePageWithValue extends StatelessWidget {
6 | final String lastPageName;
7 |
8 | BuildContext context;
9 |
10 | RoutePageWithValue(this.lastPageName);
11 |
12 | _showDialog() {
13 | showDialog(
14 | context: context,
15 | child: new AlertDialog(content: new Text('退出当前界面'), actions: [
16 | new FlatButton(
17 | onPressed: () {
18 | Navigator.pop(context);
19 | Navigator.of(context).pop();
20 | },
21 | child: new Text('确定'))
22 | ]),
23 | );
24 | }
25 |
26 | Future _requestPop() {
27 | _showDialog();
28 | return new Future.value(false);
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | this.context = context;
34 | //监听左上角返回和实体返回
35 | return new WillPopScope(
36 | child: new Scaffold(
37 | appBar: new AppBar(
38 | title: new Text('RoutePageWithValue'),
39 | centerTitle: true,
40 | ),
41 | body: new Center(
42 | child: new Text('$lastPageName'),
43 | )),
44 | onWillPop: _requestPop);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/widget/demo_route/route_page_with_value_one.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class RoutePageWithValue1 extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | _onPressed() {
7 | Navigator.of(context).pop('这是来自RoutePageWithValue1的返回值');
8 | }
9 |
10 | _onPressed1() {
11 | Navigator.of(context).pushNamedAndRemoveUntil(
12 | '/HomePage', (Route route) => false);
13 | }
14 |
15 | _onPressed2() {
16 | Navigator.of(context).pushNamedAndRemoveUntil(
17 | '/HomePage', ModalRoute.withName('/HomePage'));
18 | }
19 |
20 | _onPressed3() {
21 | Navigator.popUntil(context, ModalRoute.withName('/HomePage'));
22 | }
23 |
24 | _onPressed4() {
25 | Navigator.of(context).pushReplacementNamed('/StreamPage');
26 | }
27 |
28 |
29 | _onPressed5() {
30 | Navigator.popAndPushNamed(context, '/StreamPage');
31 | }
32 |
33 |
34 |
35 | // TODO: implement build
36 | return new Scaffold(
37 | appBar: new AppBar(
38 | title: new Text('RoutePageWithValue1'),
39 | centerTitle: true,
40 | ),
41 | body: new Center(
42 | child: ListView(
43 | children: [
44 |
45 | new Padding(
46 | padding: const EdgeInsets.only(
47 | left: 10.0, top: 10.0, right: 10.0),
48 | child: new RaisedButton(
49 | child: new Text('点击带参数返回'),
50 | onPressed: _onPressed),
51 | ),
52 | new Padding(
53 | padding: const EdgeInsets.only(
54 | left: 10.0, top: 10.0, right: 10.0),
55 | child: new RaisedButton(
56 | child: new Text('销毁其他所有的页面,点击直接去新的HomePage'),
57 | onPressed: _onPressed1),
58 | ),
59 | new Padding(
60 | padding: const EdgeInsets.only(
61 | left: 10.0, top: 10.0, right: 10.0),
62 | child: new RaisedButton(
63 | child: new Text('销毁栈内除了HomePage的页面,点击直接去栈内HomePage'),
64 | onPressed: _onPressed2),
65 | ),
66 | new Padding(
67 | padding: const EdgeInsets.only(
68 | left: 10.0, top: 10.0, right: 10.0),
69 | child: new RaisedButton(
70 | child: new Text('销毁除了栈顶的所有页面'),
71 | onPressed: _onPressed3),
72 | ),
73 | new Padding(
74 | padding: const EdgeInsets.only(
75 | left: 10.0, top: 10.0, right: 10.0),
76 | child: new RaisedButton(
77 | child: new Text('跳转并销毁当前页面(1)'),
78 | onPressed: _onPressed4),
79 | ),
80 | new Padding(
81 | padding: const EdgeInsets.only(
82 | left: 10.0, top: 10.0, right: 10.0),
83 | child: new RaisedButton(
84 | child: new Text('跳转并销毁当前页面(2)'),
85 | onPressed: _onPressed5),
86 | ),
87 |
88 | ],
89 | ),
90 | ),
91 |
92 | );
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_bloc/search_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_study/model/search_model.dart';
4 | import 'package:rxdart/rxdart.dart';
5 |
6 | class SearchBloc {
7 | final SearchApi api;
8 |
9 | //初始化
10 | Stream> _results = Stream.empty();
11 |
12 | Stream _log = Stream.empty();
13 |
14 | ReplaySubject _query = ReplaySubject();
15 |
16 | Stream get log => _log;
17 |
18 | Stream> get results => _results;
19 |
20 | Sink get query => _query;
21 |
22 |
23 | SearchBloc(this.api) {
24 |
25 | _results =
26 | _query.distinct().asyncMap(api.getSearchResult).map((value) => (!value
27 | .error && null != value.results && value.results.length > 0) ? value
28 | .results : null).asBroadcastStream();
29 |
30 | _log = new Observable(_query.stream).map((value) => '当前搜索关键字:$value').asBroadcastStream();
31 |
32 | // _log = new Observable(_results).map((list) {
33 | // if(null == list || list.isEmpty){
34 | // return '无结果';
35 | // }else{
36 | // return '';
37 | // }
38 | // }
39 | // ).asBroadcastStream();
40 | }
41 |
42 | void dispose() {
43 | _query.close();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_bloc/search_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/model/search_model.dart';
3 | import 'package:flutter_study/widget/demo_simple_bloc/search_bloc.dart';
4 |
5 | class SearchPage extends StatefulWidget {
6 | @override
7 | State createState() {
8 | return new _SearchPageState();
9 | }
10 | }
11 |
12 | class _SearchPageState extends State {
13 | SearchBloc searchBloc;
14 |
15 | @override
16 | void initState() {
17 | searchBloc = new SearchBloc(new SearchApi());
18 | super.initState();
19 | }
20 |
21 | @override
22 | void dispose() {
23 | searchBloc?.dispose();
24 | super.dispose();
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return new Scaffold(
30 | appBar: new AppBar(
31 | title: new Text('Simple BLoC'),
32 | centerTitle: true,
33 | ),
34 | body: new Column(
35 | children: [
36 | new Padding(
37 | padding: EdgeInsets.all(10.0),
38 | child: new Text('索索如下关键字,查10条数据\n福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all'),
39 | ),
40 | Container(
41 | padding: EdgeInsets.all(10.0),
42 | child: TextField(
43 | onChanged: searchBloc.query.add,
44 | decoration: InputDecoration(
45 | border: OutlineInputBorder(),
46 | hintText: 'Search',
47 | ),
48 | ),
49 | ),
50 | StreamBuilder(
51 | stream: searchBloc.log,
52 | builder: (context, snapshot) => Container(
53 | child: Text(snapshot?.data ?? ''),
54 | ),
55 | ),
56 | Flexible(
57 | child: StreamBuilder(
58 | stream: searchBloc.results,
59 | builder: (context, snapshot) {
60 | if (!snapshot.hasData)
61 | return Center(
62 | child: CircularProgressIndicator(),
63 | );
64 |
65 | return ListView.builder(
66 | itemCount: snapshot.data.length,
67 | itemBuilder: (context, index) => ListTile(
68 | title: Text(snapshot.data[index].desc),
69 | ),
70 | );
71 | },
72 | ),
73 | ),
74 | ],
75 | ));
76 | }
77 | }
78 |
79 |
80 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/count_middleware.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_study/widget/demo_simple_redux/count_redux.dart';
3 | import 'package:redux/redux.dart';
4 |
5 | class CountMiddleware extends MiddlewareClass {
6 |
7 | final GlobalKey key;
8 |
9 | CountMiddleware(this.key);
10 |
11 | call(Store store, action, NextDispatcher next) {
12 | if(store.state == 0 && action == Actions.Decrement){
13 | key.currentState.showSnackBar(new SnackBar(content: new Text('数字不能为负'))) ;
14 | return;
15 | }
16 | next(action);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/count_redux.dart:
--------------------------------------------------------------------------------
1 | enum Actions { Increment, Decrement }
2 |
3 | int counterReducer(int state, dynamic action) {
4 | if (action == Actions.Increment) {
5 | return state + 1;
6 | } else if (action == Actions.Decrement) {
7 | return state - 1;
8 | }
9 |
10 | return state;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/count_redux_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_redux/flutter_redux.dart';
3 | import 'package:flutter_study/widget/demo_simple_redux/count_middleware.dart';
4 | import 'package:flutter_study/widget/demo_simple_redux/count_redux.dart';
5 | import 'package:flutter_study/widget/demo_simple_redux/redux_w_test_a.dart';
6 | import 'package:flutter_study/widget/demo_simple_redux/redux_w_test_b.dart';
7 | import 'package:flutter_study/widget/demo_simple_redux/redux_w_test_c.dart';
8 | import 'package:redux/redux.dart';
9 |
10 |
11 |
12 | class CountReduxPage extends StatelessWidget {
13 |
14 | static GlobalKey countKey = new GlobalKey();
15 |
16 | final store = new Store(counterReducer, middleware: [new CountMiddleware(countKey)] ,initialState: 0);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 |
21 | return new StoreProvider(
22 | store: store,
23 | child: new Scaffold(
24 | key: countKey,
25 | appBar: new AppBar(
26 | title: new Text('Simple Redux'),
27 | ),
28 | body: new Center(
29 | child: new Column(
30 | mainAxisSize: MainAxisSize.min,
31 | children: [
32 | new TestWidgetA(),
33 | new TestWidgetB(),
34 | new TestWidgetC(),
35 | ],
36 | ),
37 | ),
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/redux_w_test_a.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_redux/flutter_redux.dart';
3 | import 'package:flutter_study/widget/demo_simple_redux/count_redux.dart';
4 |
5 | class TestWidgetA extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return new StoreConnector(
9 | converter: (store) {
10 | return () => store.dispatch(Actions.Increment);
11 | },
12 | builder: (context, callback) {
13 | return new Padding(
14 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
15 | child: new RaisedButton(
16 | textColor: Colors.black,
17 | child: new Text('+'),
18 | onPressed: callback),
19 | );
20 | },
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/redux_w_test_b.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_redux/flutter_redux.dart';
3 |
4 | class TestWidgetB extends StatelessWidget {
5 | @override
6 | Widget build(BuildContext context) {
7 | return new Padding(
8 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
9 | child: new StoreConnector(
10 | builder: (context, count) {
11 | return new Padding(
12 | padding:
13 | const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
14 | child: new Padding(
15 | padding:
16 | const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
17 | child: new Text(
18 | '当前count:$count',
19 | style: new TextStyle(fontSize: 20.0),
20 | ),
21 | ),
22 | );
23 | },
24 | converter: (store) => store.state.toString()),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/widget/demo_simple_redux/redux_w_test_c.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_redux/flutter_redux.dart';
3 | import 'package:flutter_study/widget/demo_simple_redux/count_redux.dart';
4 |
5 | class TestWidgetC extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return new Padding(
9 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
10 | child:
11 | new StoreConnector(builder: (context, callback) {
12 | return new Padding(
13 | padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
14 | child: new RaisedButton(
15 | textColor: Colors.black,
16 | child: new Text('-'),
17 | onPressed: callback),
18 | );
19 | }, converter: (store) {
20 | return () => store.dispatch(Actions.Decrement);
21 | }),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/widget/demo_stream/streams_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_study/common/widget/progreess_dialog.dart';
5 | import 'package:flutter_study/model/base_model.dart';
6 | import 'package:flutter_study/model/search_model.dart';
7 |
8 | class StreamPage extends StatefulWidget {
9 | @override
10 | State createState() {
11 | return new _StreamPageState();
12 | }
13 | }
14 |
15 | class _StreamPageState extends State {
16 | List _list = [];
17 |
18 | StreamController> _streamController;
19 |
20 | SearchApi _api = new SearchApi();
21 |
22 | _initStreamController() {
23 | _streamController = StreamController.broadcast();
24 | _streamController.stream.listen((list) {
25 | _list.addAll(list);
26 | setState(() {});
27 | });
28 | }
29 |
30 | _loadData() async {
31 | _api.getSearchResult('all').asStream().map((value) => (!value
32 | .error && null != value.results && value.results.length > 0) ? value
33 | .results : null).pipe(_streamController);
34 | }
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | _initStreamController();
40 | _loadData();
41 | }
42 |
43 | @override
44 | void dispose() {
45 | super.dispose();
46 | _streamController?.close();
47 | _streamController = null;
48 | }
49 |
50 | Widget _build(BuildContext context) {
51 | if (_list.isEmpty) {
52 | return getProgressDialog();
53 | } else {
54 | return ListView.builder(
55 | itemCount: _list.length,
56 | itemBuilder: (context, index) => _buildItem(index));
57 | }
58 | }
59 |
60 | Widget _buildItem(int index) {
61 | SearchModel model = _list[index];
62 | return new Text('$index. ${model.desc}');
63 | }
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 | return new Scaffold(
68 | appBar: new AppBar(
69 | title: new Text("StreamController"),
70 | centerTitle: true,
71 | ),
72 | body: new Center(
73 | child: _build(context),
74 | ),
75 | );
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/widget/drawer_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class DrawerWeiget extends StatefulWidget {
4 | @override
5 | State createState() {
6 | return new _DrawerWeigetState();
7 | }
8 | }
9 |
10 | class _DrawerWeigetState extends State {
11 | @override
12 | Widget build(BuildContext context) {
13 | // TODO: implement build
14 | return new ListView(
15 | padding: const EdgeInsets.only(),
16 | children: [
17 | new UserAccountsDrawerHeader(
18 | accountName: new Text('XXXXX'),
19 | accountEmail: new Text('XXXXXXXXXXX'),
20 | currentAccountPicture: new CircleAvatar(
21 | backgroundImage: new NetworkImage(
22 | 'http://n.sinaimg.cn/translate/20170726/Zjd3-fyiiahz2863063.jpg'),
23 | ),
24 | ),
25 | new ListTile(
26 | title: new Text('lifecycle 学习'),
27 | trailing: new Icon(Icons.arrow_right),
28 | onTap: () {
29 | Navigator.of(context).pop();
30 | Navigator.pushNamed(context, '/LifecyclePage');
31 | }),
32 | new Divider(),
33 | new ListTile(
34 | title: new Text('Route 学习'),
35 | trailing: new Icon(Icons.arrow_right),
36 | onTap: () {
37 | Navigator.of(context).pop();
38 | Navigator.pushNamed(context, '/RoutePage');
39 | }),
40 | new Divider(),
41 | new ListTile(
42 | title: new Text('数据存储 学习'),
43 | trailing: new Icon(Icons.arrow_right),
44 | onTap: () {
45 | Navigator.of(context).pop();
46 | Navigator.pushNamed(context, '/DataPage');
47 | }),
48 | new Divider(),
49 | new ListTile(
50 | title: new Text('Gesture 学习'),
51 | trailing: new Icon(Icons.arrow_right),
52 | onTap: () {
53 | Navigator.of(context).pop();
54 | Navigator.pushNamed(context, '/GesturePage');
55 | }),
56 | new Divider(),
57 | new ListTile(
58 | title: new Text('加载图片 学习'),
59 | trailing: new Icon(Icons.arrow_right),
60 | onTap: () {
61 | Navigator.of(context).pop();
62 | Navigator.pushNamed(context, '/LoadImgPage');
63 | }),
64 | new Divider(),
65 | new ListTile(
66 | title: new Text('网络请求 学习'),
67 | trailing: new Icon(Icons.arrow_right),
68 | onTap: () {
69 | Navigator.of(context).pop();
70 | Navigator.pushNamed(context, '/NetworkPage');
71 | }),
72 | new Divider(),
73 | new ListTile(
74 | title: new Text('基础Widget 学习'),
75 | trailing: new Icon(Icons.arrow_right),
76 | onTap: () {
77 | Navigator.of(context).pop();
78 | Navigator.pushNamed(context, '/BaseWidgetPage');
79 | }),
80 | new Divider(),
81 | new ListTile(
82 | title: new Text('进阶 学习'),
83 | trailing: new Icon(Icons.arrow_right),
84 | onTap: () {
85 | Navigator.of(context).pop();
86 | Navigator.pushNamed(context, '/AdvancedPage');
87 | }),
88 | new Divider(),
89 | new ListTile(
90 | title: new Text('Architecture 学习'),
91 | trailing: new Icon(Icons.arrow_right),
92 | onTap: () {
93 | Navigator.of(context).pop();
94 | Navigator.pushNamed(context, '/ArchitecturePage');
95 | }),
96 | new Divider(),
97 | ],
98 | );
99 | }
100 | }
101 |
102 | class DrawerPage extends StatelessWidget {
103 | @override
104 | Widget build(BuildContext context) {
105 | return new Scaffold(
106 | body:new DrawerWeiget(),
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/widget/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 | import 'package:flutter_study/widget/demo_localizations/localizations_study.dart';
6 | import 'package:flutter_study/widget/drawer_page.dart';
7 | import 'package:flutter_study/widget/tab_android_page.dart';
8 | import 'package:flutter_study/widget/tab_girl_page.dart';
9 | import 'package:flutter_study/widget/tab_ios_page.dart';
10 | class HomePage extends StatefulWidget {
11 | @override
12 | _HomePageState createState() => new _HomePageState();
13 | }
14 |
15 | class _HomePageState extends State
16 | with SingleTickerProviderStateMixin {
17 |
18 | final _key = new GlobalKey();
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | }
24 |
25 | @override
26 | void dispose() {
27 | super.dispose();
28 | }
29 |
30 | var _body;
31 |
32 | var _curIndex = 0;
33 |
34 | _initPage() {
35 | _body = new IndexedStack(
36 | children: [
37 | new TabGirlPage(),
38 | new TabAndroidPage(),
39 | new TabiOSPage(),
40 | ],
41 | index: _curIndex,
42 | );
43 | }
44 |
45 | _showDialog() {
46 | showDialog(
47 | context: context,
48 | child: new AlertDialog(content: new Text('退出app'), actions: [
49 | new FlatButton(
50 | onPressed: () {
51 | Navigator.pop(context);
52 | SystemNavigator.pop();
53 | },
54 | child: new Text('确定'))
55 | ]),
56 | );
57 | }
58 |
59 |
60 | Future _requestPop() {
61 | _showDialog();
62 | return new Future.value(false);
63 | }
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 | _initPage();
68 | return new WillPopScope(child: new Scaffold(
69 | key: _key,
70 | appBar: new AppBar(
71 | title: new Text(StudyLocalizations.of(context)
72 | .appTitle),
73 | centerTitle: true,
74 | ), //头部的标题AppBar
75 | drawer: new Drawer(
76 | child: new DrawerPage(),
77 | ),
78 | bottomNavigationBar: new BottomNavigationBar(
79 | items: [
80 | new BottomNavigationBarItem(
81 | icon: new Icon(Icons.home), title: new Text("妹子")),
82 | new BottomNavigationBarItem(
83 | icon: new Icon(Icons.phone_android), title: new Text("Android")),
84 | new BottomNavigationBarItem(
85 | icon: new Icon(Icons.phone_iphone), title: new Text("iOS")),
86 | ],
87 | currentIndex: _curIndex,
88 | type: BottomNavigationBarType.fixed,
89 | onTap: (index) {
90 | setState(() {
91 | _curIndex = index;
92 | });
93 | },
94 | ),
95 | body: _body,
96 | ), onWillPop: _requestPop);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/widget/tab_android_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_study/common/widget/progreess_dialog.dart';
5 | import 'package:flutter_study/model/ai_model.dart';
6 | import 'package:flutter_study/mvp/presenter/ai_presenter.dart';
7 | import 'package:flutter_study/mvp/presenter/ai_presenter_impl.dart';
8 | import 'package:flutter_study/util/routes_util.dart';
9 |
10 |
11 |
12 | class AndroidAppPage extends StatefulWidget {
13 | AndroidAppPage({Key key}) : super(key: key);
14 |
15 | @override
16 | _AndroidAppPageState createState() {
17 | _AndroidAppPageState view = new _AndroidAppPageState();
18 | AIPresenter presenter = new AIPresenterImpl(view);
19 | presenter.init();
20 | return view;
21 | }
22 | }
23 |
24 | class _AndroidAppPageState extends State implements AIView {
25 |
26 | final GlobalKey _refreshIndicatorKey =
27 | new GlobalKey();
28 |
29 | ScrollController _scrollController;
30 |
31 | List datas = [];
32 |
33 | AIPresenter _alPresenter;
34 |
35 | int curPageNum = 1;
36 |
37 | bool isSlideUp = false;
38 |
39 | @override
40 | void initState() {
41 | super.initState();
42 | _scrollController = new ScrollController()..addListener(_scrollListener);
43 | _refreshData();
44 | print("android");
45 | }
46 |
47 |
48 | @override
49 | void dispose() {
50 | _scrollController.removeListener(_scrollListener);
51 | super.dispose();
52 | }
53 |
54 |
55 |
56 | void _scrollListener() {
57 |
58 | if (_scrollController.position.pixels ==
59 | _scrollController.position.maxScrollExtent) {
60 | _loadData();
61 | }
62 | }
63 |
64 |
65 | Future _refreshData() {
66 | isSlideUp = false;
67 |
68 | final Completer completer = new Completer();
69 |
70 | curPageNum = 1;
71 |
72 | _alPresenter.loadAIData("Android", curPageNum, 10);
73 |
74 | setState(() {});
75 |
76 | completer.complete(null);
77 |
78 | return completer.future;
79 | }
80 |
81 | Future _loadData() {
82 | isSlideUp = true;
83 |
84 | final Completer completer = new Completer();
85 |
86 | curPageNum = curPageNum + 1;
87 |
88 | _alPresenter.loadAIData("Android", curPageNum, 10);
89 |
90 | setState(() {});
91 |
92 | completer.complete(null);
93 |
94 | return completer.future;
95 | }
96 |
97 | @override
98 | Widget build(BuildContext context) {
99 | var content;
100 |
101 | if (datas.isEmpty) {
102 | content = getProgressDialog();
103 | } else {
104 | content = new ListView.builder(
105 | physics:AlwaysScrollableScrollPhysics(),
106 | controller: _scrollController,
107 | itemCount: datas.length,
108 | itemBuilder: buildItem,
109 | );
110 | }
111 |
112 | var _refreshIndicator = new RefreshIndicator(
113 | key: _refreshIndicatorKey,
114 | onRefresh: _refreshData,
115 | child: content,
116 | );
117 |
118 | return _refreshIndicator;
119 | }
120 |
121 | Widget buildItem(BuildContext context, int index) {
122 | final AIModel item = datas[index];
123 | return new ListTile(
124 | onTap: (){
125 | RouteUtil.route2Web(context, item.desc, item.url);
126 | },
127 | title: new Text(item.desc), //子item的标题
128 | trailing: new Icon(
129 | Icons.arrow_right,
130 | ), //显示右侧的箭头,不显示则传null
131 | );
132 | }
133 |
134 | @override
135 | void onloadFLFail() {
136 | // TODO: implement onloadFLFail
137 | }
138 |
139 | @override
140 | void onloadFLSuc(List list) {
141 | if (!mounted) return; //异步处理,防止报错
142 | setState(() {
143 | if (isSlideUp) {
144 | datas.addAll(list);
145 | } else {
146 | datas = list;
147 | }
148 | });
149 | }
150 |
151 | @override
152 | setPresenter(AIPresenter presenter) {
153 | // TODO: implement setPresenter
154 | _alPresenter = presenter;
155 | }
156 | }
157 |
158 | class TabAndroidPage extends StatelessWidget {
159 | @override
160 | Widget build(BuildContext context) {
161 | // TODO: implement build
162 | return new Scaffold(
163 | body: new AndroidAppPage(),
164 | );
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/lib/widget/tab_girl_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_study/common/widget/progreess_dialog.dart';
5 | import 'package:flutter_study/model/fl_model.dart';
6 | import 'package:flutter_study/mvp/presenter/fl_presenter.dart';
7 | import 'package:flutter_study/mvp/presenter/fl_presenter_impl.dart';
8 | import 'package:flutter_study/widget/demo_gesture/multi_touch_page.dart';
9 |
10 | final GlobalKey _refreshIndicatorKey =
11 | new GlobalKey();
12 |
13 | class GirlsAppPage extends StatefulWidget {
14 | GirlsAppPage({Key key}) : super(key: key);
15 |
16 | @override
17 | _GirlsAppPageState createState() {
18 | _GirlsAppPageState view = new _GirlsAppPageState();
19 | FLPresenter presenter = new FLPresenterImpl(view);
20 | presenter.init();
21 | return view;
22 | }
23 | }
24 |
25 | class _GirlsAppPageState extends State implements FLView {
26 |
27 | final GlobalKey _refreshIndicatorKey =
28 | new GlobalKey();
29 |
30 | ScrollController _scrollController;
31 |
32 | List datas = [];
33 |
34 | FLPresenter _flPresenter;
35 |
36 | int curPageNum = 1;
37 |
38 | bool isSlideUp = false;
39 |
40 | void _scrollListener() {
41 | if (_scrollController.position.pixels ==
42 | _scrollController.position.maxScrollExtent) {
43 | _loadData();
44 | }
45 | }
46 |
47 | @override
48 | void initState() {
49 | super.initState();
50 | _refreshData();
51 | _scrollController = new ScrollController()..addListener(_scrollListener);
52 | print("girl");
53 | }
54 |
55 | @override
56 | void dispose() {
57 | super.dispose();
58 | _scrollController.removeListener(_scrollListener);
59 | }
60 |
61 | Future _refreshData() {
62 | isSlideUp = false;
63 |
64 | final Completer completer = new Completer();
65 |
66 | curPageNum = 1;
67 |
68 | _flPresenter.loadFLData(curPageNum, 10);
69 |
70 | setState(() {});
71 |
72 | completer.complete(null);
73 |
74 | return completer.future;
75 | }
76 |
77 | Future _loadData() {
78 | isSlideUp = true;
79 |
80 | final Completer completer = new Completer();
81 |
82 | curPageNum = curPageNum + 1;
83 |
84 | _flPresenter.loadFLData(curPageNum, 10);
85 |
86 | setState(() {});
87 |
88 | completer.complete(null);
89 |
90 | return completer.future;
91 | }
92 |
93 | @override
94 | Widget build(BuildContext context) {
95 | var content;
96 |
97 | if (datas.isEmpty) {
98 | content = getProgressDialog();
99 | } else {
100 | content = new ListView.builder(
101 | //设置physics属性总是可滚动
102 | physics: AlwaysScrollableScrollPhysics(),
103 | controller: _scrollController,
104 | itemCount: datas.length,
105 | itemBuilder: buildCard,
106 | );
107 | }
108 |
109 | var _refreshIndicator = new RefreshIndicator(
110 | key: _refreshIndicatorKey,
111 | onRefresh: _refreshData,
112 | child: content,
113 | );
114 |
115 | return _refreshIndicator;
116 | }
117 |
118 | void _goPhotoView(String url) {
119 | Navigator.of(context).push(new PageRouteBuilder(
120 | opaque: false,
121 | pageBuilder: (BuildContext context, _, __) {
122 | return new MultiTouchPage(url);
123 | },
124 | transitionsBuilder: (_, Animation animation, __, Widget child) {
125 | return new FadeTransition(
126 | opacity: animation,
127 | child: new RotationTransition(
128 | turns: new Tween(begin: 0.5, end: 1.0).animate(animation),
129 | child: child,
130 | ),
131 | );
132 | }));
133 | }
134 |
135 |
136 | Widget buildCard(BuildContext context, int index) {
137 | final String item = datas[index].url;
138 | return new GestureDetector(
139 | onTap: (){
140 | _goPhotoView(item);
141 | },
142 | child: new Card(
143 | child: new Image.network(item),
144 | ),
145 | );
146 | }
147 |
148 | @override
149 | void onloadFLFail() {
150 | // TODO: implement onloadFLFail
151 | }
152 |
153 | @override
154 | void onloadFLSuc(List list) {
155 | if (!mounted) return; //异步处理,防止报错
156 | setState(() {
157 | if (isSlideUp) {
158 | datas.addAll(list);
159 | } else {
160 | datas = list;
161 | }
162 | });
163 | }
164 |
165 | @override
166 | setPresenter(FLPresenter presenter) {
167 | // TODO: implement setPresenter
168 | _flPresenter = presenter;
169 | }
170 | }
171 |
172 | class TabGirlPage extends StatelessWidget {
173 | @override
174 | Widget build(BuildContext context) {
175 | // TODO: implement build
176 | return new Scaffold(
177 | body: new GirlsAppPage(),
178 | );
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/lib/widget/tab_ios_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_study/common/widget/progreess_dialog.dart';
5 | import 'package:flutter_study/model/ai_model.dart';
6 | import 'package:flutter_study/mvp/presenter/ai_presenter.dart';
7 | import 'package:flutter_study/mvp/presenter/ai_presenter_impl.dart';
8 | import 'package:flutter_study/util/routes_util.dart';
9 |
10 | class IOSAppPage extends StatefulWidget {
11 |
12 | @override
13 | State createState() {
14 | _IOSAppPageState view = new _IOSAppPageState();
15 | AIPresenter presenter = new AIPresenterImpl(view);
16 | presenter.init();
17 | return view;
18 | }
19 |
20 | }
21 |
22 | class _IOSAppPageState extends State implements AIView {
23 |
24 | final GlobalKey _refreshIndicatorKey =
25 | new GlobalKey();
26 |
27 | ScrollController _scrollController;
28 |
29 | List datas = [];
30 |
31 | AIPresenter _alPresenter;
32 |
33 | int curPageNum = 1;
34 |
35 | bool isSlideUp = false;
36 |
37 | @override
38 | void initState() {
39 | super.initState();
40 | _scrollController = new ScrollController()
41 | ..addListener(_scrollListener);
42 | _refreshData();
43 | print("iOS");
44 | }
45 |
46 |
47 | @override
48 | void dispose() {
49 | _scrollController.removeListener(_scrollListener);
50 | super.dispose();
51 | }
52 |
53 |
54 | void _scrollListener() {
55 | if (_scrollController.position.pixels ==
56 | _scrollController.position.maxScrollExtent) {
57 | _loadData();
58 | }
59 | }
60 |
61 |
62 | Future _refreshData() {
63 | isSlideUp = false;
64 |
65 | final Completer completer = new Completer();
66 |
67 | curPageNum = 1;
68 |
69 | _alPresenter.loadAIData("iOS", curPageNum, 10);
70 |
71 | setState(() {});
72 |
73 | completer.complete(null);
74 |
75 | return completer.future;
76 | }
77 |
78 | Future _loadData() {
79 | isSlideUp = true;
80 |
81 | final Completer completer = new Completer();
82 |
83 | curPageNum = curPageNum + 1;
84 |
85 | _alPresenter.loadAIData("Android", curPageNum, 10);
86 |
87 | setState(() {});
88 |
89 | completer.complete(null);
90 |
91 | return completer.future;
92 | }
93 |
94 | @override
95 | Widget build(BuildContext context) {
96 | var content;
97 |
98 | if (datas.isEmpty) {
99 | content = getProgressDialog();
100 | } else {
101 | content = new ListView.builder(
102 | physics: AlwaysScrollableScrollPhysics(),
103 | controller: _scrollController,
104 | itemCount: datas.length,
105 | itemBuilder: buildItem,
106 | );
107 | }
108 |
109 | var _refreshIndicator = new RefreshIndicator(
110 | key: _refreshIndicatorKey,
111 | onRefresh: _refreshData,
112 | child: content,
113 | );
114 |
115 | return _refreshIndicator;
116 | }
117 |
118 | Widget buildItem(BuildContext context, int index) {
119 | final AIModel item = datas[index];
120 | return new ListTile(
121 | onTap: (){
122 | RouteUtil.route2Web(context, item.desc, item.url);
123 | },
124 | title: new Text(item.desc), //子item的标题
125 | trailing: new Icon(
126 | Icons.arrow_right,
127 | ), //显示右侧的箭头,不显示则传null
128 | );
129 | }
130 |
131 | @override
132 | void onloadFLFail() {
133 | // TODO: implement onloadFLFail
134 | }
135 |
136 | @override
137 | void onloadFLSuc(List list) {
138 | if (!mounted) return; //异步处理,防止报错
139 | setState(() {
140 | if (isSlideUp) {
141 | datas.addAll(list);
142 | } else {
143 | datas = list;
144 | }
145 | });
146 | }
147 |
148 | @override
149 | setPresenter(AIPresenter presenter) {
150 | // TODO: implement setPresenter
151 | _alPresenter = presenter;
152 | }
153 | }
154 |
155 |
156 | class TabiOSPage extends StatelessWidget {
157 |
158 |
159 | @override
160 | Widget build(BuildContext context) {
161 | // TODO: implement build
162 | return new Scaffold(
163 | body: new IOSAppPage(),
164 | );
165 | }
166 | }
167 |
168 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_study
2 | description: A new Flutter application.
3 |
4 | dependencies:
5 | flutter:
6 | sdk: flutter
7 |
8 | # The following adds the Cupertino Icons font to your application.
9 | # Use with the CupertinoIcons class for iOS style icons.
10 | cupertino_icons: ^0.1.2
11 | shared_preferences: ^0.4.2
12 | path_provider: ^0.4.1
13 | sqflite: ^0.12.0
14 | cached_network_image: ^0.5.0
15 | transparent_image: ^0.1.0
16 | http: ^0.12.0
17 | dio: ^1.0.4
18 | flutter_webview_plugin: ^0.2.1
19 | flutter_redux: 0.5.2
20 | rxdart: 0.18.1
21 | # firebase_admob: ^0.5.5
22 | # fluttertoast: ^2.0.3
23 | flutter_localizations:
24 | sdk: flutter
25 |
26 | dev_dependencies:
27 | flutter_test:
28 |
29 | sdk: flutter
30 |
31 |
32 |
33 | # For information on the generic Dart part of this file, see the
34 | # following page: https://www.dartlang.org/tools/pub/pubspec
35 |
36 | # The following section is specific to Flutter.
37 | flutter:
38 |
39 | # The following line ensures that the Material Icons font is
40 | # included with your application, so that you can use the icons in
41 | # the material Icons class.
42 | uses-material-design: true
43 |
44 | # To add assets to your application, add an assets section, like this:
45 | assets:
46 | - images/ic_assignment_ind_36pt.png
47 | - images/lifecycle.png
48 |
49 | # - images/a_dot_ham.jpeg
50 |
51 | # An image asset can refer to one or more resolution-specific "variants", see
52 | # https://flutter.io/assets-and-images/#resolution-aware.
53 |
54 | # For details regarding adding assets from package dependencies, see
55 | # https://flutter.io/assets-and-images/#from-packages
56 |
57 | # To add custom fonts to your application, add a fonts section here,
58 | # in this "flutter" section. Each entry in this list should have a
59 | # "family" key with the font family name, and a "fonts" key with a
60 | # list giving the asset and other descriptors for the font. For
61 | # example:
62 | # fonts:
63 | # - family: Schyler
64 | # fonts:
65 | # - asset: fonts/Schyler-Regular.ttf
66 | # - asset: fonts/Schyler-Italic.ttf
67 | # style: italic
68 | # - family: Trajan Pro
69 | # fonts:
70 | # - asset: fonts/TrajanPro.ttf
71 | # - asset: fonts/TrajanPro_Bold.ttf
72 | # weight: 700
73 | #
74 | # For details regarding fonts from package dependencies,
75 | # see https://flutter.io/custom-fonts/#from-packages
76 |
--------------------------------------------------------------------------------
/screenshot/1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/1.jpeg
--------------------------------------------------------------------------------
/screenshot/10.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/10.jpeg
--------------------------------------------------------------------------------
/screenshot/11.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/11.jpeg
--------------------------------------------------------------------------------
/screenshot/12.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/12.jpeg
--------------------------------------------------------------------------------
/screenshot/13.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/13.jpeg
--------------------------------------------------------------------------------
/screenshot/14.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/14.jpeg
--------------------------------------------------------------------------------
/screenshot/15.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/15.jpeg
--------------------------------------------------------------------------------
/screenshot/16.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/16.jpeg
--------------------------------------------------------------------------------
/screenshot/17.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/17.jpeg
--------------------------------------------------------------------------------
/screenshot/18.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/18.jpeg
--------------------------------------------------------------------------------
/screenshot/19.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/19.jpeg
--------------------------------------------------------------------------------
/screenshot/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/20.png
--------------------------------------------------------------------------------
/screenshot/3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/3.jpeg
--------------------------------------------------------------------------------
/screenshot/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/4.png
--------------------------------------------------------------------------------
/screenshot/5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/5.jpeg
--------------------------------------------------------------------------------
/screenshot/6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/6.jpeg
--------------------------------------------------------------------------------
/screenshot/8.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/8.jpeg
--------------------------------------------------------------------------------
/screenshot/9.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhujian1989/flutter_study/03d5ae9d8ae68582db3ee293ee676a94d4edbd9c/screenshot/9.jpeg
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties
5 | // are correct.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 | import 'package:flutter_study/widget/home_page.dart';
10 |
11 | void main() {
12 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
13 | // Build our app and trigger a frame.
14 | await tester.pumpWidget(new HomePage());
15 |
16 | // Verify that our counter starts at 0.
17 | expect(find.text('0'), findsOneWidget);
18 | expect(find.text('1'), findsNothing);
19 |
20 | // Tap the '+' icon and trigger a frame.
21 | await tester.tap(find.byIcon(Icons.add));
22 | await tester.pump();
23 |
24 | // Verify that our counter has incremented.
25 | expect(find.text('0'), findsNothing);
26 | expect(find.text('1'), findsOneWidget);
27 | });
28 | }
29 |
--------------------------------------------------------------------------------