├── .gitignore
├── Archive.zip
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── lgyw
│ │ │ └── flutterapp
│ │ │ └── MainActivity.java
│ │ └── res
│ │ ├── drawable
│ │ └── launch_background.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── demonstrationgif
├── 20180814_142135.gif
├── 20180814_142220.gif
├── 20180821_094948.gif
├── 20180912_100745.gif
├── 20181023_90359.gif
├── 20181127_165032.gif
├── 20181130_092350.gif
├── 20181207_155551.gif
├── 20181229_155650.gif
└── screenshot_20190127113535.png
├── images
├── chaonan1.jpeg
├── chaonan2.jpg
├── chaonan3.jpeg
├── chaonan4.jpeg
├── close.png
├── icon_arrow.png
├── icon_cry.png
├── refresh.png
└── tianmao.jpg
├── 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
│ │ └── WorkspaceSettings.xcsettings
└── 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
├── Home.dart
├── bin
│ ├── adsorptiondatabin.dart
│ ├── adsorptionlistbin.dart
│ ├── appinfobin.dart
│ ├── bubblebin.dart
│ ├── dragablegridviewbin.dart
│ └── gridviewitembin.dart
├── components
│ ├── adsorptionview
│ │ ├── adsorptionview.dart
│ │ ├── equalHeightState.dart
│ │ └── notEqualHeightState.dart
│ ├── dragablegridview.dart
│ ├── drawablestarttext.dart
│ ├── loginanimation.dart
│ ├── marquee.dart
│ ├── pulltorefresh.dart
│ ├── radarchart.dart
│ └── waveprogressbar.dart
├── main.dart
└── ui
│ ├── firstpage
│ ├── adsorptionviewdemo.dart
│ ├── animations.dart
│ ├── dragablegridviewdemo.dart
│ ├── firstPage.dart
│ ├── marqueedemo.dart
│ └── pulltorefreshdemo.dart
│ ├── secondpage
│ ├── beziercurvedemo.dart
│ ├── blendmode.dart
│ ├── bubbles.dart
│ ├── dashboard.dart
│ ├── drawablestarttext.dart
│ ├── loginanimdemo.dart
│ ├── radarchartdemo.dart
│ ├── secondPage.dart
│ └── timepicker.dart
│ └── thirdpage
│ ├── cutScreen.dart
│ ├── examples
│ ├── CameraTest.dart
│ ├── Examples.dart
│ └── ImagePicker.dart
│ ├── home_page.dart
│ ├── shakeView.dart
│ ├── testFile.dart
│ └── thirdPage.dart
├── pictures
└── Dragable gridview.png
├── pubspec.lock
├── pubspec.yaml
└── 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
11 | .metadata
12 | *.iml
--------------------------------------------------------------------------------
/Archive.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/Archive.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | `由于GIF太多(大),演示的图片可能会卡,请移步至demonstrationgif文件夹下可查看单个GIF图片`
2 |
3 | ## PullToRefresh [](https://pub.dartlang.org/packages/pulltorefresh_flutter)
4 | #### Usage
5 | Add this to your package's pubspec.yaml file:
6 |
7 | dependencies:
8 | pulltorefresh_flutter: "^0.1.9"
9 |
10 | If you want to use the default refresh image of this project (the rotated image), please download https://raw.githubusercontent.com/baoolong/PullToRefresh_Flutter/master/images/refresh.png to your images folder, and Pubspec.yaml is declared as follows.
11 |
12 | If you want to use other images, put the image in the Images folder, declare it in the Pubspec.yaml file, and add the property refreshIconPath in the PullAndPush class.
13 |
14 | assets:
15 | - images/refresh.png
16 |
17 | Add it to your dart file:
18 |
19 | import 'package:pulltorefresh_flutter/pulltorefresh_flutter.dart';
20 | #### Example
21 | [https://github.com/baoolong/PullToRefresh_Flutter](https://github.com/baoolong/PullToRefresh_Flutter)
22 |
23 | 本功能只实现基本的上下拉刷新,可在这个基础上进行改进、优化、封装,如果只是使用,可在build方法中修改ListView控件和List数组的泛型,已经兼容IOS,已经支持对下拉和上拉的分别控制
24 |
25 |
26 |
27 | ## 仿京东广告滑动切换 ##
28 | 模仿的京东潮男模块的广告滑动切换,本人做的比较粗糙,大家可以在此基础上改进,比如滞后滑动,底层图片缩小等,由于没有进行屏幕适配,所以可能不同的手机会显示很丑,这是由于我在设计图片之间的Magin是用屏幕宽度减去两边距屏幕的宽度,再除以3计算的,大家可以根据需要去设定图片之间的Magin,最好固定值
29 |
30 |
31 |
32 | ## Marquee(跑马灯) [](https://pub.dartlang.org/packages/marquee_flutter)
33 |
34 | 一个用ListView做的跑马灯,可以垂直方向滚动,也可以水平方向滚动
35 |
36 | A Marquee widght with ListView,Can scroll vertically or horizontally
37 |
38 | #### Usage
39 | Add this to your package's pubspec.yaml file:
40 |
41 | dependencies:
42 | marquee_flutter: ^0.1.3
43 |
44 | Add it to your dart file:
45 |
46 | import 'package:marquee_flutter/marquee_flutter.dart';
47 |
48 | #### Example
49 | [https://github.com/baoolong/MarqueeWidget](https://github.com/baoolong/MarqueeWidget)
50 |
51 |
52 | 采用ListView绘制,将ListView设置为不可手动滑动,然后启动Timer来回拖动,造成跑马灯的错觉
53 |
54 | ## DragableGridView [](https://pub.dartlang.org/packages/dragablegridview_flutter)
55 | 采用GridView +OverflowBox +Container的transform属性来完成,基本稳定,现在加入了删除功能和动画,后续持续改进,代码会越来越精简,逻辑会更清晰,学习的朋友可以拿去自己研究改进,添加新功能,下面是示例图
56 | ### Usage
57 |
58 | Add this to your package's pubspec.yaml file:
59 |
60 | dependencies:
61 | dragablegridview_flutter: ^0.2.2
62 |
63 | Add it to your dart file:
64 |
65 | import 'package:dragablegridview_flutter/dragablegridview_flutter.dart';
66 |
67 | And GridView dataBin must extends DragAbleGridViewBin ,Add it to your dataBin file
68 |
69 | import 'package:dragablegridview_flutter/dragablegridviewbin.dart';
70 |
71 | ### Example
72 | [https://github.com/baoolong/DragableGridview](https://github.com/baoolong/DragableGridview)
73 |
74 | ----------
75 |
76 |
77 |
78 |
79 | ## AdsorptionView [](https://pub.dartlang.org/packages/adsorptionview_flutter)
80 | ListView吸顶控件,本控件只适用于ListView的Item高度固定的布局(AdsorptionViewState),如果高度不固定会有偏差。已经更新了非固定高度的吸顶布局(AdsorptionViewNotEqualHeightState),有一点点小问题,请自行解决,里面有如何获取ListView第一个可见Item的方法,可供参考
81 | ### Usage
82 | Add this to your package's pubspec.yaml file:
83 |
84 | dependencies:
85 | adsorptionview_flutter: ^0.1.3
86 |
87 | Add it to your dart file:
88 |
89 | import 'package:adsorptionview_flutter/adsorptionview_flutter.dart';
90 |
91 | And ListView dataBin must extends AdsorptionData ,Add it to your dataBin file
92 |
93 | import 'package:adsorptionview_flutter/adsorptiondatabin.dart';
94 |
95 | ### Example
96 | [https://github.com/baoolong/Adsorptionview](https://github.com/baoolong/Adsorptionview)
97 |
98 |
99 |
--------------------------------------------------------------------------------
/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/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 28
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.lgyw.flutterapp"
27 | minSdkVersion 21
28 | targetSdkVersion 28
29 | versionCode 1
30 | versionName "1.0"
31 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
32 | }
33 |
34 | buildTypes {
35 | release {
36 | // TODO: Add your own signing config for the release build.
37 | // Signing with the debug keys for now, so `flutter run --release` works.
38 | signingConfig signingConfigs.debug
39 | }
40 | }
41 | }
42 |
43 | flutter {
44 | source '../..'
45 | }
46 |
47 | dependencies {
48 | testImplementation 'junit:junit:4.12'
49 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
51 | }
52 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/lgyw/flutterapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lgyw.flutterapp;
2 |
3 | import android.content.Context;
4 | import android.hardware.Sensor;
5 | import android.hardware.SensorEvent;
6 | import android.hardware.SensorEventListener;
7 | import android.hardware.SensorManager;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 |
11 | import io.flutter.app.FlutterActivity;
12 | import io.flutter.plugin.common.MethodCall;
13 | import io.flutter.plugin.common.MethodChannel;
14 | import io.flutter.plugins.GeneratedPluginRegistrant;
15 | import io.flutter.plugin.common.MethodChannel.Result;
16 |
17 | public class MainActivity extends FlutterActivity {
18 |
19 | private static final String CHANNEL = "com.flutter.lgyw/sensor";
20 | private SensorManager sm;
21 | private double pressure=0.0;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | GeneratedPluginRegistrant.registerWith(this);
27 |
28 | sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
29 |
30 | new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
31 | new MethodChannel.MethodCallHandler() {
32 | @Override
33 | public void onMethodCall(MethodCall call, Result result) {
34 | if (call.method.equals("registerSensor")) {
35 | // 为压力传感器注册监听器
36 | boolean isSuccess=sm.registerListener(sensorEventListener, sm.getDefaultSensor(Sensor.TYPE_PRESSURE), SensorManager.SENSOR_DELAY_NORMAL);
37 | if(isSuccess){
38 | result.success("Success");
39 | }else{
40 | result.success("Faile");
41 | }
42 | }else if(call.method.equals("unRegisterSensor")){
43 | sm.unregisterListener(sensorEventListener);
44 | result.success("");
45 | }else if(call.method.equals("getPressure")){
46 | result.success(pressure);
47 | }
48 | }
49 | });
50 | }
51 |
52 | private SensorEventListener sensorEventListener=new SensorEventListener() {
53 | @Override
54 | public void onSensorChanged(SensorEvent sensorEvent) {
55 | if(sensorEvent.sensor.getType() == Sensor.TYPE_PRESSURE){
56 | pressure = sensorEvent.values[0];
57 | Log.i("MainActivity","sensorEvent.values[0] = " +sensorEvent.values[0]);
58 | }
59 | }
60 |
61 | @Override
62 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
63 |
64 | }
65 | };
66 | }
67 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.3.2'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=http\://services.gradle.org/distributions/gradle-4.10.1-all.zip
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/demonstrationgif/20180814_142135.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20180814_142135.gif
--------------------------------------------------------------------------------
/demonstrationgif/20180814_142220.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20180814_142220.gif
--------------------------------------------------------------------------------
/demonstrationgif/20180821_094948.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20180821_094948.gif
--------------------------------------------------------------------------------
/demonstrationgif/20180912_100745.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20180912_100745.gif
--------------------------------------------------------------------------------
/demonstrationgif/20181023_90359.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20181023_90359.gif
--------------------------------------------------------------------------------
/demonstrationgif/20181127_165032.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20181127_165032.gif
--------------------------------------------------------------------------------
/demonstrationgif/20181130_092350.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20181130_092350.gif
--------------------------------------------------------------------------------
/demonstrationgif/20181207_155551.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20181207_155551.gif
--------------------------------------------------------------------------------
/demonstrationgif/20181229_155650.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/20181229_155650.gif
--------------------------------------------------------------------------------
/demonstrationgif/screenshot_20190127113535.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/demonstrationgif/screenshot_20190127113535.png
--------------------------------------------------------------------------------
/images/chaonan1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/chaonan1.jpeg
--------------------------------------------------------------------------------
/images/chaonan2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/chaonan2.jpg
--------------------------------------------------------------------------------
/images/chaonan3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/chaonan3.jpeg
--------------------------------------------------------------------------------
/images/chaonan4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/chaonan4.jpeg
--------------------------------------------------------------------------------
/images/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/close.png
--------------------------------------------------------------------------------
/images/icon_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/icon_arrow.png
--------------------------------------------------------------------------------
/images/icon_cry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/icon_cry.png
--------------------------------------------------------------------------------
/images/refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/refresh.png
--------------------------------------------------------------------------------
/images/tianmao.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/images/tianmao.jpg
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/app.flx
37 | /Flutter/app.zip
38 | /Flutter/flutter_assets/
39 | /Flutter/App.framework
40 | /Flutter/Flutter.framework
41 | /Flutter/Generated.xcconfig
42 | /ServiceDefinitions.json
43 |
44 | Pods/
45 | .symlinks/
46 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | post_install do |installer|
64 | installer.pods_project.targets.each do |target|
65 | target.build_configurations.each do |config|
66 | config.build_settings['ENABLE_BITCODE'] = 'NO'
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - camera (0.0.1):
3 | - Flutter
4 | - Flutter (1.0.0)
5 | - image_picker (0.0.1):
6 | - Flutter
7 | - path_provider (0.0.1):
8 | - Flutter
9 | - video_player (0.0.1):
10 | - Flutter
11 |
12 | DEPENDENCIES:
13 | - camera (from `.symlinks/plugins/camera/ios`)
14 | - Flutter (from `.symlinks/flutter/ios`)
15 | - image_picker (from `.symlinks/plugins/image_picker/ios`)
16 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
17 | - video_player (from `.symlinks/plugins/video_player/ios`)
18 |
19 | EXTERNAL SOURCES:
20 | camera:
21 | :path: ".symlinks/plugins/camera/ios"
22 | Flutter:
23 | :path: ".symlinks/flutter/ios"
24 | image_picker:
25 | :path: ".symlinks/plugins/image_picker/ios"
26 | path_provider:
27 | :path: ".symlinks/plugins/path_provider/ios"
28 | video_player:
29 | :path: ".symlinks/plugins/video_player/ios"
30 |
31 | SPEC CHECKSUMS:
32 | camera: d56ad165545ae5a0ffb892376033760a969c68c8
33 | Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
34 | image_picker: 16e5fec1fbc87fd3b297c53e4048521eaf17cd06
35 | path_provider: f96fff6166a8867510d2c25fdcc346327cc4b259
36 | video_player: 3964090a33353060ed7f58aa6427c7b4b208ec21
37 |
38 | PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09
39 |
40 | COCOAPODS: 1.6.1
41 |
--------------------------------------------------------------------------------
/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/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildSystemType
6 | Original
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/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 | flutterapp
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/Home.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/rendering.dart';
4 | import 'package:flutterapp/ui/firstpage/firstPage.dart';
5 | import 'package:flutterapp/ui/secondpage/secondPage.dart';
6 | import 'package:flutterapp/ui/thirdpage/thirdPage.dart';
7 | import 'dart:ui' as ui show Image;
8 |
9 | class MyHomePage extends StatefulWidget{
10 | @override
11 | State createState() {
12 | return new _MyHomePageState();
13 | }
14 | }
15 |
16 |
17 | class _MyHomePageState extends State with SingleTickerProviderStateMixin{
18 |
19 | PageController controller;
20 | var currentPage=0;
21 | GlobalKey _globalKey=new GlobalKey();
22 |
23 | @override
24 | void initState() {
25 | super.initState();
26 | controller=new PageController(initialPage: this.currentPage);
27 | }
28 |
29 | @override
30 | void dispose() {
31 | controller.dispose();
32 | super.dispose();
33 | }
34 |
35 |
36 | Future _widgetToImage(final GlobalKey _globalKey) async {
37 | try {
38 | RenderRepaintBoundary boundary = _globalKey.currentContext
39 | .findRenderObject();
40 | ui.Image image = await boundary.toImage(pixelRatio: 1.0);
41 | var recorder = new PictureRecorder();
42 | Canvas canvas = Canvas(recorder);
43 | canvas.drawImage(image, new Offset(0.0, 0.0), new Paint());
44 | Picture picture = recorder.endRecording();
45 | return picture;
46 | }catch(e){
47 | print(e);
48 | }
49 | return null;
50 | }
51 |
52 |
53 | @override
54 | Widget build(BuildContext context) {
55 | return new RepaintBoundary(
56 | key: _globalKey,
57 | child: new Scaffold(
58 | body: new PageView(
59 | children: [
60 | new FirstPage(),
61 | new SecondPage(),
62 | new ThirdPage()
63 | ],
64 | controller: controller,
65 | onPageChanged: (int position){
66 | _widgetToImage(_globalKey);
67 | setState(() {
68 | this.currentPage = position;
69 | });
70 | },
71 | ),
72 | bottomNavigationBar:
73 | new BottomNavigationBar(items: [
74 | new BottomNavigationBarItem(
75 | icon: new Icon(Icons.home),
76 | title: new Title(
77 | title:"列表",
78 | color: Colors.white,
79 | child: new Text("列表",style: new TextStyle(fontSize: 13.0)))
80 | ),
81 | new BottomNavigationBarItem(
82 | icon: new Icon(Icons.message),
83 | title: new Title(
84 | title:"通知",
85 | color: Colors.white,
86 | child: new Text("通知",style: new TextStyle(fontSize: 13.0)))
87 | ),
88 | new BottomNavigationBarItem(
89 | icon: new Icon(Icons.cloud),
90 | title: new Title(
91 | title:"我的",
92 | color: Colors.white,
93 | child: new Text("我的",style: new TextStyle(fontSize: 13.0)))
94 | )
95 | ],
96 | iconSize: 28.0,
97 | onTap: (int position){
98 | setState(() {
99 | controller.animateToPage(
100 | position, duration: const Duration(milliseconds: 300),
101 | curve: Curves.ease);
102 | });
103 | },
104 | currentIndex: currentPage,
105 | fixedColor: Colors.blue,
106 | )
107 | ),
108 | );
109 | }
110 | }
--------------------------------------------------------------------------------
/lib/bin/adsorptiondatabin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AdsorptionData{
4 | bool isHeader=false;
5 | GlobalKey adsorptionKey=new GlobalKey();
6 | double headerPosition = -99.0;
7 | }
--------------------------------------------------------------------------------
/lib/bin/adsorptionlistbin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutterapp/bin/adsorptiondatabin.dart';
2 |
3 | class AdsorptionListBin extends AdsorptionData{
4 | AdsorptionListBin( this.headerName);
5 |
6 | String headerName;
7 |
8 | @override
9 | String toString() {
10 | return 'AdsorptionListBin{headerName: $headerName}';
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/lib/bin/appinfobin.dart:
--------------------------------------------------------------------------------
1 |
2 | class AppInfoBin{
3 | AppInfoBin(this.title,this.times,this.content,this.isTapDown);
4 | String title;
5 | String times;
6 | String content;
7 | bool isTapDown;
8 | }
--------------------------------------------------------------------------------
/lib/bin/bubblebin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class BubbleBin {
4 | double radius;
5 | double speed;
6 | double disappearHeight;
7 | Color color;
8 | int transparency;
9 | double xPosition;
10 | double yPosition;
11 |
12 | BubbleBin({
13 | @required this.radius,
14 | @required this.speed,
15 | @required this.disappearHeight,
16 | @required this.color,
17 | @required this.transparency,
18 | @required this.xPosition,
19 | @required this.yPosition
20 | });
21 |
22 | @override
23 | String toString() {
24 | return 'BubbleBin{radius: $radius, speed: $speed, disappearHeight: $disappearHeight, color: $color, transparency: $transparency, xPosition: $xPosition, yPosition: $yPosition}';
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/lib/bin/dragablegridviewbin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class DragAbleGridViewBin{
4 | double dragPointX=0.0;
5 | double dragPointY=0.0;
6 | double lastTimePositionX=0.0;
7 | double lastTimePositionY=0.0;
8 | GlobalKey containerKey=new GlobalKey();
9 | GlobalKey containerKeyChild=new GlobalKey();
10 | bool isLongPress=false;
11 | bool dragAble=false;
12 | ///是否隐藏,默认不隐藏
13 | bool offstage=false;
14 | }
--------------------------------------------------------------------------------
/lib/bin/gridviewitembin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutterapp/bin/dragablegridviewbin.dart';
2 | //import 'package:dragablegridview_flutter/dragablegridviewbin.dart';
3 |
4 | class ItemBin extends DragAbleGridViewBin{
5 |
6 | ItemBin( this.data);
7 |
8 | String data;
9 |
10 | @override
11 | String toString() {
12 | return 'ItemBin{data: $data, dragPointX: $dragPointX, dragPointY: $dragPointY, lastTimePositionX: $lastTimePositionX, lastTimePositionY: $lastTimePositionY, containerKey: $containerKey, containerKeyChild: $containerKeyChild, isLongPress: $isLongPress, dragAble: $dragAble}';
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/lib/components/adsorptionview/adsorptionview.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/bin/adsorptiondatabin.dart';
3 | import 'package:flutterapp/components/adsorptionview/equalHeightState.dart';
4 | import 'package:flutterapp/components/adsorptionview/notEqualHeightState.dart';
5 |
6 | typedef Widget GetHearWidget (M bin);
7 | typedef Widget GetGeneralItem (M bin);
8 |
9 | class AdsorptionView extends StatefulWidget{
10 |
11 | final List adsorptionDatas;
12 | final GetHearWidget headChild;
13 | final GetGeneralItem generalItemChild;
14 | final double itemHeight;
15 | final double itemWidth;
16 | final double cacheExtent;
17 | //final bool isEqualHeightItem;
18 |
19 | AdsorptionView({
20 | @required this.adsorptionDatas,
21 | @required this.headChild,
22 | @required this.generalItemChild,
23 | this.itemHeight:50.0,
24 | this.itemWidth:double.infinity,
25 | this.cacheExtent:30.0,
26 | //@required this.isEqualHeightItem,
27 | }): assert(
28 | adsorptionDatas!=null,
29 | generalItemChild!=null&&
30 | headChild!=null,
31 | );
32 |
33 | @override
34 | State createState() {
35 | // if(isEqualHeightItem) {
36 | return new AdsorptionViewState();
37 | // }else{
38 | // return new AdsorptionViewNotEqualHeightState();
39 | // }
40 | }
41 | }
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/lib/components/adsorptionview/equalHeightState.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 | import 'package:flutterapp/bin/adsorptiondatabin.dart';
4 | import 'package:flutterapp/components/adsorptionview/adsorptionview.dart';
5 |
6 | ///此控件适用于固定高度的ListView
7 | class AdsorptionViewState extends State>{
8 |
9 | ScrollController scrollController=new ScrollController();
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return new Stack(
14 | children: [
15 | new AdsorptionListView(
16 | scrollController: scrollController,
17 | adsorptionDatas: widget.adsorptionDatas,
18 | generalItemChild: widget.generalItemChild,
19 | headChild: widget.headChild,
20 | itemHeight: widget.itemHeight,
21 | itemWidth: widget.itemWidth,
22 | cacheExtent: widget.cacheExtent,
23 | ),
24 | new GestureDetector(
25 | onTap: (){
26 | double pixels= scrollController.position.pixels;
27 | int a=pixels~/widget.itemHeight;
28 | for(int i=a;i>=0;i--){
29 | if(widget.adsorptionDatas[i].isHeader) {
30 | scrollController.animateTo(i*widget.itemHeight, duration: new Duration(milliseconds: 200), curve: Curves.linear);
31 | break;
32 | }
33 | }
34 | },
35 | child: new HeaderView(
36 | scrollController: scrollController,
37 | headChild: widget.headChild,
38 | adsorptionDatas: widget.adsorptionDatas,
39 | itemWidth: widget.itemWidth,
40 | itemHeight: widget.itemHeight,
41 | ),
42 | ),
43 | ],
44 | );
45 | }
46 | }
47 |
48 |
49 | class AdsorptionListView extends StatefulWidget{
50 | final ScrollController scrollController;
51 | final double itemHeight;
52 | final double itemWidth;
53 | final double cacheExtent;
54 | final List adsorptionDatas;
55 | final GetHearWidget headChild;
56 | final GetGeneralItem generalItemChild;
57 |
58 | AdsorptionListView({
59 | @required this.adsorptionDatas,
60 | @required this.headChild,
61 | @required this.generalItemChild,
62 | this.itemHeight:50.0,
63 | this.itemWidth:double.infinity,
64 | this.cacheExtent:30.0,
65 | @required this.scrollController,
66 | }): assert(
67 | adsorptionDatas!=null,
68 | generalItemChild!=null&&
69 | headChild!=null,
70 | );
71 |
72 | @override
73 | State createState() {
74 | return AdsorptionListViewState();
75 | }
76 | }
77 |
78 | class AdsorptionListViewState extends State>{
79 |
80 | ScrollPhysics scrollPhysics=new ClampingScrollPhysics();
81 |
82 | @override
83 | Widget build(BuildContext context) {
84 | return new ListView.builder(
85 | physics: scrollPhysics,
86 | cacheExtent: widget.cacheExtent,
87 | controller: widget.scrollController,
88 | itemCount: widget.adsorptionDatas.length,
89 | itemBuilder: (context, index) {
90 | if(widget.adsorptionDatas[index].isHeader){
91 | return new Container(
92 | width: widget.itemWidth,
93 | height: widget.itemHeight,
94 | child: widget.headChild(widget.adsorptionDatas[index]),
95 | );
96 | }else{
97 | return new Container(
98 | width: widget.itemWidth,
99 | height: widget.itemHeight,
100 | child: widget.generalItemChild(widget.adsorptionDatas[index]),
101 | );
102 | }
103 | },
104 | );
105 | }
106 | }
107 |
108 |
109 | class HeaderView extends StatefulWidget{
110 |
111 | final ScrollController scrollController;
112 | final double itemHeight;
113 | final double itemWidth;
114 | final GetHearWidget headChild;
115 | final List adsorptionDatas;
116 |
117 | HeaderView({
118 | @required this.scrollController,
119 | this.itemHeight:50.0,
120 | this.itemWidth:double.infinity,
121 | @required this.headChild,
122 | @required this.adsorptionDatas,
123 | });
124 |
125 | @override
126 | State createState() {
127 | return new HeaderViewState();
128 | }
129 | }
130 |
131 | class HeaderViewState extends State>{
132 | double headerOffset=0.0;
133 | T headerStr;
134 | double beforeScroll=0.0;
135 |
136 | @override
137 | void initState() {
138 | headerStr=widget.adsorptionDatas.first;
139 |
140 | widget.scrollController.addListener((){
141 | //计算滑动了多少距离了
142 | double pixels=widget.scrollController.position.pixels;
143 |
144 | //根据滑动的距离 计算当前可见的第一个Item的Position
145 | int a=pixels~/widget.itemHeight;
146 | //计算滑动出屏幕多少距离
147 | double b=pixels%widget.itemHeight;
148 | double currentScrollPosition=widget.scrollController.position.extentBefore;
149 | //如果下一个item是Header 则偏移 如果不是 则偏移量=0
150 | if(widget.adsorptionDatas[a+1].isHeader){
151 | setState(() {
152 | // 改变布局
153 | if(currentScrollPosition-beforeScroll<0){
154 | //检测到再向上划就越出当前组 提前改变header的内容并偏移
155 | for(int i=a;i>=0;i--){
156 | if(widget.adsorptionDatas[i].isHeader){
157 | headerStr=widget.adsorptionDatas[i];
158 | break;
159 | }
160 | }
161 | }
162 | beforeScroll=currentScrollPosition;
163 | headerOffset=-b;
164 | });
165 | }else{
166 | //始终使header处于完整显示状态
167 | for(int i=a;i>=0;i--){
168 | if(widget.adsorptionDatas[i].isHeader) {
169 | if(headerStr != widget.adsorptionDatas[i]) {
170 | setState(() {
171 | headerStr = widget.adsorptionDatas[i];
172 | });
173 | }
174 | break;
175 | }
176 | }
177 | if(headerOffset!=0){
178 | setState(() {
179 | headerOffset=0.0;
180 | });
181 | }
182 | }
183 | });
184 | super.initState();
185 | }
186 |
187 | @override
188 | Widget build(BuildContext context) {
189 | return new Container(
190 | transform: Matrix4.translationValues(0.0, headerOffset, 0.0),
191 | width: widget.itemWidth,
192 | height: widget.itemHeight,
193 | child: widget.headChild(headerStr),
194 | );
195 | }
196 | }
--------------------------------------------------------------------------------
/lib/components/drawablestarttext.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class DrawableStartText extends StatefulWidget{
4 |
5 | final TextStyle textStyle;
6 | final String text;
7 | final String assetImage;
8 | final int maxLines;
9 | ///尽可能写出图片后大概有多少字母,这样能快速计算第一行显示多少个字母(例如有20个字母 可以设置该值为12左右),默认为0
10 | //final int lettersCountOfAfterImage;
11 |
12 | DrawableStartText({
13 | this.textStyle,
14 | @required this.text,
15 | @required this.assetImage,
16 | this.maxLines,
17 | //this.lettersCountOfAfterImage:0,
18 | });
19 |
20 | @override
21 | State createState() {
22 | return new DrawableStartTextState();
23 | }
24 | }
25 |
26 |
27 |
28 | class DrawableStartTextState extends State{
29 |
30 | double _textHeight;
31 | GlobalKey rowKey=GlobalKey();
32 | GlobalKey imageKey=GlobalKey();
33 | String _topText="";
34 | String _bottomText="";
35 | Image _image;
36 |
37 | @override
38 | void initState() {
39 | super.initState();
40 | //计算文字的高度,根据文字的高度设定图片的高度,然后让图片自适应
41 | TextPainter painter=new TextPainter();
42 | if(widget.textStyle!=null) {
43 | painter.text = TextSpan(style: widget.textStyle, text: widget.text);
44 | }else{
45 | painter.text = TextSpan(text: widget.text);
46 | }
47 | painter.maxLines=1;
48 | painter.textDirection=TextDirection.ltr;
49 | painter.layout();
50 | _textHeight=painter.size.height;
51 |
52 | //在第一帧后计算下第一行能显示多少个字母,然后将字母分成两段显示
53 | WidgetsBinding.instance.addPostFrameCallback((callback){
54 | _image.image.resolve(new ImageConfiguration())
55 | .addListener((imageInfo,synchronousCall){
56 | //计算图片的宽高
57 | double imgHeight = imageInfo.image.height . toDouble();
58 | double imgWidth = imageInfo.image.width . toDouble();
59 | //由于图片缩放了。所以根据缩放大小计算出宽图,这里没有用key去取值,是因为取出的值是空的
60 | double scale=_textHeight/imgHeight;
61 | double _imageWidth=imgWidth*scale;
62 |
63 | //再用父控件的宽度减去图片的宽度就是文字显示的宽度
64 | double parentWidth = rowKey.currentContext.findRenderObject().paintBounds.size.width;
65 | double textWidth = parentWidth - _imageWidth;
66 |
67 | int index=0;
68 | //计算出在哪个字母时超出了显示范围
69 | for(;indextextWidth){
77 | break;
78 | }
79 | }
80 |
81 | //将超出的哪个位置减掉,剩下的字母就不会超出范围了
82 | int validIndex=index-1;
83 | //根据计算的位置,分别截取前半部分 和后半部分显示
84 | setState(() {
85 | _topText= widget.text.substring(0,validIndex);
86 | _bottomText = widget.text.substring(validIndex);
87 | });
88 | });
89 |
90 | });
91 | }
92 |
93 | @override
94 | Widget build(BuildContext context) {
95 | final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
96 | return new Column(
97 | crossAxisAlignment: CrossAxisAlignment.start,
98 | children: [
99 | new Row(
100 | key: rowKey,
101 | children: [
102 | _image=new Image.asset(
103 | widget.assetImage,
104 | key:imageKey,
105 | height:_textHeight,
106 | fit : BoxFit.fitHeight,
107 | ),
108 | new Text(
109 | _topText,
110 | style: widget.textStyle,
111 | maxLines: 1,
112 | ),
113 | ],
114 | ),
115 | new Text(
116 | _bottomText,
117 | style: widget.textStyle,
118 | textAlign: TextAlign.left,
119 | maxLines: widget.maxLines ==null ? defaultTextStyle.maxLines : widget.maxLines-1,
120 | overflow: widget.maxLines ==null ? defaultTextStyle.overflow : TextOverflow.ellipsis,
121 | ),
122 | ],
123 | );
124 | }
125 | }
--------------------------------------------------------------------------------
/lib/components/marquee.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 |
6 | class MarqueeWidget extends StatefulWidget{
7 |
8 | final String text;
9 | final TextStyle textStyle;
10 | ///滚动方向,水平或者垂直
11 | final Axis scrollAxis;
12 | ///空白部分占控件的百分比
13 | final double ratioOfBlankToScreen;
14 |
15 | MarqueeWidget({
16 | @required this.text,
17 | this.textStyle,
18 | this.scrollAxis:Axis.horizontal,
19 | this.ratioOfBlankToScreen:0.25,
20 | }) :assert(text!=null,);
21 |
22 | @override
23 | State createState() {
24 | return new MarqueeWidgetState();
25 | }
26 | }
27 |
28 | class MarqueeWidgetState extends State with SingleTickerProviderStateMixin{
29 |
30 | ScrollController scroController;
31 | double blankWidth;
32 | double blankHeight;
33 | double position=0.0;
34 | Timer timer;
35 | final double _moveDistance=3.0;
36 | final int _timerRest=100;
37 | GlobalKey _key=GlobalKey();
38 |
39 |
40 | @override
41 | void initState() {
42 | super.initState();
43 | scroController=new ScrollController();
44 | WidgetsBinding.instance.addPostFrameCallback((callback){
45 | startTimer();
46 | });
47 | }
48 |
49 | void startTimer(){
50 | double widgetWidth = _key.currentContext.findRenderObject().paintBounds.size.width;
51 | double widgetHeight = _key.currentContext.findRenderObject().paintBounds.size.height;
52 |
53 | timer=Timer.periodic(new Duration(milliseconds: _timerRest), (timer){
54 | double maxScrollExtent=scroController.position.maxScrollExtent;
55 | double pixels=scroController.position.pixels;
56 | //当animateTo的距离大于最大滑动距离时,则要返回第一个child的特定位置,让末尾正好处于最右侧,然后继续滚动,造成跑马灯的假象
57 | if(pixels+_moveDistance>=maxScrollExtent){
58 | if(widget.scrollAxis==Axis.horizontal){
59 | //TODO maxScrollExtent是可滑动的最大距离,不可滑动的距离并不计算在内(即ListView的控件宽度),maxScrollExtent + widgetWidth才是children的真正高度
60 | //(maxScrollExtent+widgetWidth-blankWidth)/2 可计算出一个TextView控件的长度,然后再减去widgetWidth。计算出第一个child偏移到最右侧所需要的偏移量
61 | //当animateTo滑动到末尾,但是距末尾还有一段距离,jumpTo的时候要将这段距离考虑进去 pixels-maxScrollExtent
62 | //原始计算公式 (maxScrollExtent+widgetWidth-blankWidth)/2 -widgetWidth + pixels- maxScrollExtent,下面的计算公式是经过简化的
63 | position=(maxScrollExtent-blankWidth-widgetWidth)/2+pixels-maxScrollExtent;
64 | }else{
65 | position=(maxScrollExtent-blankHeight-widgetHeight)/2+pixels-maxScrollExtent;
66 | }
67 | scroController.jumpTo(position);
68 | }
69 | position+=_moveDistance;
70 | scroController.animateTo(position,duration: new Duration(milliseconds: _timerRest),curve: Curves.linear);
71 | });
72 | }
73 |
74 |
75 | @override
76 | void didChangeDependencies() {
77 | super.didChangeDependencies();
78 | double screenWidth=MediaQuery.of(context).size.width;
79 | double screenHeight=MediaQuery.of(context).size.height;
80 | blankWidth=screenWidth*widget.ratioOfBlankToScreen;
81 | blankHeight=screenHeight*widget.ratioOfBlankToScreen;
82 | }
83 |
84 | Widget getBothEndsChild(){
85 | if(widget.scrollAxis ==Axis.vertical){
86 | String newString=widget.text.split("").join("\n");
87 | return new Center(
88 | child: new Text(newString,style: widget.textStyle,textAlign: TextAlign.center,),
89 | );
90 | }
91 | return new Center(
92 | child:new Text(widget.text,style: widget.textStyle,)
93 | );
94 | }
95 |
96 | Widget getCenterChild(){
97 | if(widget.scrollAxis ==Axis.horizontal){
98 | return new Container(width: blankWidth);
99 | }else{
100 | return new Container(height: blankHeight);
101 | }
102 | }
103 |
104 |
105 |
106 | @override
107 | void dispose() {
108 | super.dispose();
109 | timer.cancel();
110 | }
111 |
112 | @override
113 | Widget build(BuildContext context) {
114 | return new ListView(
115 | key: _key,
116 | scrollDirection: widget.scrollAxis,
117 | controller: scroController,
118 | physics: new NeverScrollableScrollPhysics(),
119 | children: [
120 | getBothEndsChild(),
121 | getCenterChild(),
122 | getBothEndsChild(),
123 | ],
124 | );
125 | }
126 | }
--------------------------------------------------------------------------------
/lib/components/radarchart.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'dart:math';
3 | import 'package:flutter/material.dart';
4 |
5 | class RadarChart extends StatefulWidget{
6 |
7 | final double radarChartRadius=200.0;
8 | final Map maps={"Java":20,"Flutter":20,"Object-C":20,"C#":20,"Kotlin":20};
9 |
10 | @override
11 | State createState() {
12 | return RadarChartState() ;
13 | }
14 |
15 | }
16 |
17 | class RadarChartState extends State{
18 |
19 | PictureRecorder _recorder;
20 | Picture picture;
21 | double maxWidth=0.0;
22 | double maxHeight=0.0;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return new Container(
27 | child: new CustomPaint(
28 | size: new Size(maxWidth,maxHeight),
29 | painter: new RadarChartPainter(
30 | radarChartRadius:widget.radarChartRadius,
31 | picture: picture,
32 | ),
33 | ),
34 | );
35 | }
36 |
37 |
38 | @override
39 | void initState() {
40 | super.initState();
41 | _recorder=new PictureRecorder();
42 | drawRadarChartBackground();
43 | }
44 |
45 |
46 | ///画雷达图的底图
47 | void drawRadarChartBackground(){
48 | Canvas canvas=Canvas(_recorder);
49 | //计算每边占多少角度
50 | double angle=pi*2/widget.maps.length;
51 | Paint linePaint=Paint();
52 | //文字和雷达图的间距
53 | double spaceBetweenChartAndText=5.0;
54 |
55 | //计算雷达图中最长的文字占用的宽度,在切大小的时候必须考虑到文字占用的大小
56 | TextPainter painterSmall=new TextPainter();
57 | painterSmall.textDirection=TextDirection.ltr;
58 | double maxTextWidth=0.0;
59 | widget.maps.keys.forEach((key){
60 | painterSmall.text=new TextSpan(text: key,style: new TextStyle(fontSize: 15.0,color: Colors.black));
61 | painterSmall.layout();
62 | if(painterSmall.size.width>maxTextWidth){
63 | maxTextWidth=painterSmall.size.width;
64 | }
65 | });
66 | //在半径的基础上加上最大文字宽度,由于是两边有文字,所以*2 ,加10是因为文字和图之间有空隙
67 | maxWidth=widget.radarChartRadius+maxTextWidth*2+spaceBetweenChartAndText*2;
68 | maxHeight=widget.radarChartRadius+painterSmall.size.height*2+spaceBetweenChartAndText*2;
69 | canvas.clipRect(new Rect.fromLTRB(0.0, 0.0, maxWidth, maxHeight));
70 |
71 |
72 | canvas.translate(maxWidth/2, maxHeight/2);
73 | //旋转单边一半所需要的角度
74 | double halfAngle=angle/2;
75 | //绘制横线的半径
76 | double linesRadius;
77 | //横线与横线之间的间隙
78 | double linesSpace=cos(halfAngle)*widget.radarChartRadius/10;
79 |
80 | //绘制网格图
81 | canvas.save();
82 | //canvas.rotate(-pi/2-halfAngle);
83 | //为什么角度是反的? Why is the angle reversed?
84 | canvas.rotate(pi/2+halfAngle);
85 | for(int i=0;i=(1.875*pi) || accumulateAngle=pi/8 && accumulateAngle=pi*0.375 && accumulateAngle=pi*0.625 && accumulateAngle=pi*0.875 && accumulateAngle=pi*1.125 && accumulateAngle=pi*1.375 && accumulateAngle createState() {
37 | return new WaveProgressBarState();
38 | }
39 | }
40 |
41 |
42 | class WaveProgressBarState extends State with SingleTickerProviderStateMixin{
43 | double _moveForwardDark=0.0;
44 | double _moveForwardLight=0.0;
45 | double _waterHeight;
46 | double _percentage;
47 | Animation animation;
48 | AnimationController animationController;
49 | VoidCallback _voidCallback;
50 | Random _random=new Random();
51 | Picture _lightWavePic;
52 | Picture _darkWavePic;
53 |
54 | @override
55 | void dispose() {
56 | animationController.stop();
57 | animationController.dispose();
58 | super.dispose();
59 | }
60 |
61 | @override
62 | void initState() {
63 | super.initState();
64 | _percentage=widget.percentage;
65 | _waterHeight=(1-_percentage) * widget.size.height;
66 | widget.progressController.bezierCurveState=this;
67 | WavePictureGenerator generator=WavePictureGenerator(widget.size,widget.waveDistance,widget.waveHeight,widget.waterColor);
68 | _lightWavePic=generator.drawLightWave();
69 | _darkWavePic=generator.drawDarkWave();
70 | animationController = new AnimationController(duration: const Duration(milliseconds: 3000), vsync: this);
71 |
72 | WidgetsBinding widgetsBinding=WidgetsBinding.instance;
73 | widgetsBinding.addPostFrameCallback((callback){
74 | widgetsBinding.addPersistentFrameCallback((callback) {
75 | if(mounted){
76 | setState(() {
77 | _moveForwardDark= _moveForwardDark - widget.flowSpeed- _random.nextDouble()-1;
78 | if(_moveForwardDark<= - widget.waveDistance*4){
79 | _moveForwardDark=_moveForwardDark+widget.waveDistance*4;
80 | }
81 |
82 | _moveForwardLight = _moveForwardLight- widget.flowSpeed- _random.nextDouble();
83 | if(_moveForwardLight <= - widget.waveDistance*4){
84 | _moveForwardLight = _moveForwardLight+widget.waveDistance*4;
85 | }
86 | });
87 | widgetsBinding.scheduleFrame();
88 | }
89 | });
90 | });
91 | }
92 |
93 |
94 |
95 | @override
96 | Widget build(BuildContext context) {
97 | return new CustomPaint(
98 | size: widget.size,
99 | painter: new BezierCurvePainter(
100 | moveForward:_moveForwardDark,
101 | textStyle:widget.textStyle ,
102 | circleStrokeWidth: widget.circleStrokeWidth,
103 | strokeCircleColor: widget.strokeCircleColor,
104 | percentage: _percentage ,
105 | moveForwardLight: _moveForwardLight,
106 | lightWavePic: _lightWavePic,
107 | darkWavePic: _darkWavePic,
108 | waterHeight: _waterHeight,
109 | ),
110 | );
111 | }
112 |
113 | void changeWaterHeight(double h){
114 | initAnimation(_percentage ,h);
115 | animationController.forward();
116 | }
117 |
118 |
119 | void initAnimation(double old ,double newPercentage){
120 | animation = new Tween(begin: old, end: newPercentage).animate(animationController);
121 |
122 | animation.addListener(_voidCallback=() {
123 | setState(() {
124 | double value = animation.value;
125 | _percentage=value;
126 | double newHeight=(1-_percentage) * widget.size.height;
127 | _waterHeight=newHeight;
128 | });
129 | });
130 |
131 | animation.addStatusListener((animationStatus){
132 | if(animationStatus==AnimationStatus.completed){
133 | animation.removeListener(_voidCallback);
134 | animationController.reset();
135 | }else if(animationStatus==AnimationStatus.forward){
136 |
137 | }
138 | });
139 | }
140 | }
141 |
142 |
143 | class WavePictureGenerator{
144 | PictureRecorder _recorder;
145 | final Size size;
146 | final double _waveDistance;
147 | final double _waveHeight;
148 | final Color _waterColor;
149 | int _maxCount;
150 | double waterHeight;
151 | double _targetWidth;
152 | double _targetHeight;
153 |
154 | WavePictureGenerator(this.size,this._waveDistance,this._waveHeight,this._waterColor){
155 | double oneDistance=_waveDistance*4;
156 | int count=(size.width/oneDistance).ceil()+1;
157 | _targetWidth=count*oneDistance;
158 | _maxCount=count*4+1;
159 | waterHeight=size.height/2;
160 | _targetHeight=size.height+waterHeight;
161 | }
162 |
163 | Picture drawDarkWave(){
164 | return drawWaves(true);
165 | }
166 |
167 | Picture drawLightWave(){
168 | return drawWaves(false);
169 | }
170 |
171 | Picture drawWaves(bool isDarkWave){
172 | _recorder=PictureRecorder();
173 | Canvas canvas=Canvas(_recorder);
174 | canvas.clipRect(new Rect.fromLTWH(0.0, 0.0, _targetWidth, _targetHeight));
175 | Paint paint =Paint();
176 | if(isDarkWave){
177 | paint.color = _waterColor;
178 | }else{
179 | paint.color = _waterColor.withAlpha(0x88);
180 | }
181 | paint.style=PaintingStyle.fill;
182 | canvas.drawPath(createBezierPath(isDarkWave), paint);
183 | return _recorder.endRecording();
184 | }
185 |
186 |
187 | Path createBezierPath(bool isDarkWave){
188 |
189 | Path path=Path();
190 | path.moveTo(0, waterHeight);
191 |
192 | double lastPoint=0.0;
193 | int m=0;
194 | double waves;
195 | for(int i=0;i<_maxCount-2;i=i+2){
196 | if(m%2==0){
197 | waves=waterHeight+_waveHeight;
198 | }else{
199 | waves=waterHeight-_waveHeight;
200 | }
201 | path.cubicTo(lastPoint, waterHeight, lastPoint+_waveDistance, waves, lastPoint+_waveDistance*2, waterHeight);
202 | lastPoint=lastPoint+_waveDistance*2;
203 | m++;
204 | }
205 | if(isDarkWave){
206 | path.lineTo(lastPoint,_targetHeight);
207 | path.lineTo(0,_targetHeight);
208 | }else{
209 | double waveHeightMax=waterHeight+_waveHeight+10.0;
210 | path.lineTo(lastPoint, waveHeightMax);
211 | path.lineTo(0,waveHeightMax);
212 | }
213 | path.close();
214 | return path;
215 | }
216 | }
217 |
218 |
219 | class BezierCurvePainter extends CustomPainter{
220 |
221 | final double moveForward;
222 | final Color strokeCircleColor;
223 | final TextStyle textStyle;
224 | final double circleStrokeWidth;
225 | final double percentage;
226 | final double moveForwardLight;
227 | final Picture darkWavePic;
228 | final Picture lightWavePic;
229 | final double waterHeight;
230 | final Paint _paints =Paint();
231 |
232 | BezierCurvePainter({
233 | @required this.moveForward,
234 | @required this.strokeCircleColor,
235 | @required this.textStyle,
236 | @required this.circleStrokeWidth,
237 | @required this.percentage,
238 | @required this.moveForwardLight,
239 | @required this.darkWavePic,
240 | @required this.lightWavePic,
241 | @required this.waterHeight,
242 | });
243 |
244 | @override
245 | void paint(Canvas canvas, Size size) {
246 | Paint layerPaint=new Paint();
247 |
248 | double halfSizeHeight = size.height/2;
249 | double halfSizeWidth = size.width/2;
250 | double radius=min(size.width, size.height)/2-circleStrokeWidth/2;
251 |
252 | //由于在绘制图片的时候在波浪上面有50%高度的空白部分,所以在这里必须减掉
253 | double targetHeight=waterHeight-halfSizeHeight;
254 |
255 | canvas.saveLayer(new Rect.fromLTRB(0.0, 0.0, size.width, size.height), layerPaint);
256 | //绘制淡颜色的海浪
257 | canvas.save();
258 | canvas.translate(moveForwardLight, targetHeight);
259 | canvas.drawPicture(lightWavePic);
260 |
261 | //绘制深颜色的海浪
262 | double moveDistance=moveForward-moveForwardLight;
263 | canvas.translate(moveDistance, 0.0);
264 | canvas.drawPicture(darkWavePic);
265 | canvas.restore();
266 |
267 | layerPaint.blendMode=BlendMode.dstIn ;
268 | canvas.saveLayer(new Rect.fromLTRB(0.0, 0.0, size.width, size.height), layerPaint);
269 |
270 | canvas.drawCircle(new Offset(halfSizeWidth, halfSizeHeight), radius-circleStrokeWidth, _paints);
271 | canvas.restore();
272 | canvas.restore();
273 |
274 |
275 | _paints.style=PaintingStyle.stroke;
276 | _paints.color=strokeCircleColor;
277 | _paints.strokeWidth=circleStrokeWidth;
278 | canvas.drawCircle(new Offset(halfSizeWidth, halfSizeHeight), radius, _paints);
279 |
280 | TextPainter textPainter = new TextPainter();
281 | textPainter.textDirection = TextDirection.ltr;
282 | textPainter.text = new TextSpan(text: (percentage*100).toInt().toString()+"%",
283 | style: textStyle,);
284 | textPainter.layout();
285 | double textStarPositionX = halfSizeWidth-textPainter.size.width/2;
286 | double textStarPositionY = halfSizeHeight-textPainter.size.height/2;
287 | textPainter.paint(canvas, new Offset(textStarPositionX, textStarPositionY));
288 | }
289 |
290 | @override
291 | bool shouldRepaint(CustomPainter oldDelegate) {
292 | return true;
293 | }
294 | }
295 |
296 | class WaterController {
297 | WaveProgressBarState bezierCurveState;
298 |
299 | void changeProgressRate(double h){
300 | if(bezierCurveState!=null) {
301 | bezierCurveState.changeWaterHeight(h);
302 | }
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:camera/camera.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutterapp/Home.dart';
4 |
5 |
6 | List cameras;
7 |
8 | Future main() async {
9 |
10 | // Fetch the available cameras before initializing the app.
11 | try {
12 | cameras = await availableCameras();
13 | } on CameraException catch (e) {
14 | logError(e.code, e.description);
15 | }
16 | runApp(
17 | new MaterialApp(
18 | title: 'Startup Name Generator',
19 | showPerformanceOverlay: false,
20 | theme: new ThemeData(
21 | primaryColor: Colors.white,
22 | ),
23 | home: new MyHomePage(),
24 | )
25 | );
26 | }
27 |
28 |
29 | void logError(String code, String message) =>
30 | print('Error: $code\nError Message: $message');
--------------------------------------------------------------------------------
/lib/ui/firstpage/adsorptionviewdemo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 | import 'package:flutterapp/bin/adsorptionlistbin.dart';
4 | import 'package:flutterapp/components/adsorptionview/adsorptionview.dart';
5 |
6 | class AdsorptionViewDemo extends StatefulWidget{
7 | @override
8 | State createState() {
9 | List adsorptionDatas=new List();
10 | AdsorptionListBin adsorptionData;
11 |
12 | adsorptionData=new AdsorptionListBin("A");
13 | adsorptionData.isHeader=true;
14 | adsorptionDatas.add(adsorptionData);
15 |
16 | adsorptionData=new AdsorptionListBin("阿杜");
17 | adsorptionDatas.add(adsorptionData);
18 |
19 | adsorptionData=new AdsorptionListBin("阿宝");
20 | adsorptionDatas.add(adsorptionData);
21 |
22 | adsorptionData=new AdsorptionListBin("艾夫杰尼");
23 | adsorptionDatas.add(adsorptionData);
24 |
25 | adsorptionData=new AdsorptionListBin("阿牛");
26 | adsorptionDatas.add(adsorptionData);
27 |
28 | adsorptionData=new AdsorptionListBin("安苏羽");
29 | adsorptionDatas.add(adsorptionData);
30 |
31 | adsorptionData=new AdsorptionListBin("阿勒长青");
32 | adsorptionDatas.add(adsorptionData);
33 |
34 |
35 | adsorptionData=new AdsorptionListBin("B");
36 | adsorptionData.isHeader=true;
37 | adsorptionDatas.add(adsorptionData);
38 |
39 | adsorptionData=new AdsorptionListBin("白小白");
40 | adsorptionDatas.add(adsorptionData);
41 |
42 | adsorptionData=new AdsorptionListBin("白羽毛");
43 | adsorptionDatas.add(adsorptionData);
44 |
45 | adsorptionData=new AdsorptionListBin("Bridge");
46 | adsorptionDatas.add(adsorptionData);
47 |
48 | adsorptionData=new AdsorptionListBin("斑马");
49 | adsorptionDatas.add(adsorptionData);
50 |
51 | adsorptionData=new AdsorptionListBin("白一阳");
52 | adsorptionDatas.add(adsorptionData);
53 |
54 | adsorptionData=new AdsorptionListBin("白举纲");
55 | adsorptionDatas.add(adsorptionData);
56 |
57 | adsorptionData=new AdsorptionListBin("暴林");
58 | adsorptionDatas.add(adsorptionData);
59 |
60 |
61 | adsorptionData=new AdsorptionListBin("C");
62 | adsorptionData.isHeader=true;
63 | adsorptionDatas.add(adsorptionData);
64 |
65 | adsorptionData=new AdsorptionListBin("陈奕迅");
66 | adsorptionDatas.add(adsorptionData);
67 |
68 | adsorptionData=new AdsorptionListBin("陈小春");
69 | adsorptionDatas.add(adsorptionData);
70 |
71 | adsorptionData=new AdsorptionListBin("成龙");
72 | adsorptionDatas.add(adsorptionData);
73 |
74 | adsorptionData=new AdsorptionListBin("陈百强");
75 | adsorptionDatas.add(adsorptionData);
76 |
77 | adsorptionData=new AdsorptionListBin("迟志强");
78 | adsorptionDatas.add(adsorptionData);
79 |
80 | adsorptionData=new AdsorptionListBin("崔健");
81 | adsorptionDatas.add(adsorptionData);
82 |
83 | adsorptionData=new AdsorptionListBin("陈晓东");
84 | adsorptionDatas.add(adsorptionData);
85 |
86 | adsorptionData=new AdsorptionListBin("陈学冬");
87 | adsorptionDatas.add(adsorptionData);
88 |
89 | adsorptionData=new AdsorptionListBin("蔡国庆");
90 | adsorptionDatas.add(adsorptionData);
91 |
92 | adsorptionData=new AdsorptionListBin("陈冠希");
93 | adsorptionDatas.add(adsorptionData);
94 |
95 | adsorptionData=new AdsorptionListBin("陈琳");
96 | adsorptionDatas.add(adsorptionData);
97 | return new AdsorptionViewState(adsorptionDatas);
98 | }
99 | }
100 |
101 | ///此控件适用于固定高度的ListView
102 | class AdsorptionViewState extends State{
103 |
104 | AdsorptionViewState(this.adsorptionDatas);
105 |
106 | List adsorptionDatas;
107 | double itemHeight=50.0;
108 |
109 |
110 | @override
111 | Widget build(BuildContext context) {
112 | return new Scaffold(
113 | appBar: new AppBar(
114 | title: new Text("吸附布局"),
115 | ),
116 | body:new AdsorptionView(
117 | adsorptionDatas: adsorptionDatas,
118 | generalItemChild: (AdsorptionListBin bin) {
119 | print("build Item Child ${bin.headerName}");
120 | return new Container(
121 | height: 60,
122 | alignment: Alignment.centerLeft,
123 | margin: EdgeInsets.fromLTRB(15.0, 0.0, 0.0, 0.0),
124 | child: new Text(
125 | bin.headerName,
126 | style: new TextStyle(fontSize: 18.0, color: Colors.grey),
127 | ),
128 | );
129 | },
130 | headChild: (AdsorptionListBin bin) {
131 | print("build head Child");
132 | return new Container(
133 | height: 50,
134 | color: Colors.grey,
135 | alignment: Alignment.centerLeft,
136 | padding: EdgeInsets.fromLTRB(15.0, 0.0, 0.0, 0.0),
137 | child: new Text(
138 | bin.headerName,
139 | style: new TextStyle( fontSize: 20.0,color: Colors.black),
140 | ),
141 | );
142 | },
143 | ),
144 | );
145 | }
146 | }
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/lib/ui/firstpage/animations.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/animation.dart';
5 |
6 | import 'package:flutter/rendering.dart';
7 |
8 | class AnimationWidget extends StatefulWidget{
9 | @override
10 | State createState() {
11 | return new AnimationState();
12 | }
13 |
14 | }
15 |
16 | class AnimationState extends State with SingleTickerProviderStateMixin{
17 |
18 | final double imageWidth=90.0;
19 | final double imageHeight=160.0;
20 | Animation animation;
21 | AnimationController controller;
22 | double preXPosition;
23 | double screenWidth;
24 | double magins;
25 | double scales=0.0;
26 | List imagesPaths;
27 | bool directionLeft=true;
28 |
29 | @override
30 | void initState() {
31 | controller = new AnimationController(duration: const Duration(milliseconds: 430), vsync: this);
32 | animation = new Tween(begin: 0.0, end: 1.0).animate(controller)
33 | ..addListener(() {
34 | setState(() {
35 | // the state that has changed here is the animation object’s value
36 | if(directionLeft){
37 | scales=animation.value;
38 | }else{
39 | scales=1.0-animation.value;
40 | }
41 | print("**********");
42 | });
43 | });
44 | animation.addStatusListener((animationStatus){
45 | if(animationStatus==AnimationStatus.completed){
46 | setState(() {
47 | controller.reset();
48 | if(directionLeft){
49 | String a=imagesPaths[3];
50 | imagesPaths.removeLast();
51 | imagesPaths.insert(0, a);
52 | }
53 | scales=0.0;
54 | });
55 |
56 | }else if(animationStatus==AnimationStatus.forward){
57 | setState(() {
58 | if(!directionLeft){
59 | String a=imagesPaths[0];
60 | imagesPaths.removeAt(0);
61 | imagesPaths.add(a);
62 | }
63 | });
64 | }
65 | });
66 |
67 | super.initState();
68 |
69 | imagesPaths=new List();
70 | imagesPaths.add("images/chaonan3.jpeg");
71 | imagesPaths.add("images/chaonan4.jpeg");
72 | imagesPaths.add("images/chaonan2.jpg");
73 | imagesPaths.add("images/chaonan1.jpeg");
74 | }
75 |
76 | @override
77 | void didChangeDependencies() {
78 | super.didChangeDependencies();
79 | screenWidth=MediaQuery.of(context).size.width;
80 | magins=(screenWidth-60-imageWidth*2.5)/2.0;
81 | print("magins is $magins");
82 | }
83 |
84 |
85 |
86 | /* 第一排的magn不用动 宽高不用动
87 | * 中间的View宽高放大 magin加大
88 | * 最后一排 也就是最前面的界面宽高不用动,magin快速变大
89 | */
90 | Row creatRow(double imgHeight,double imgWidth,double maginSize,String imgPath){
91 | return new Row(
92 | mainAxisAlignment: MainAxisAlignment.end,
93 | children: [
94 | new Center(
95 | child: new Container(
96 | width: screenWidth,
97 | alignment: Alignment.centerRight,
98 | child: new OverflowBox(
99 | maxWidth: double.infinity,
100 | maxHeight: double.infinity,
101 | alignment: Alignment.centerRight,
102 | child: new Container(
103 | height: imgHeight,
104 | width: imgWidth,
105 | margin: new EdgeInsets.fromLTRB(0.0, 0.0, maginSize, 0.0),
106 | child: new Image.asset(imgPath),
107 | ),
108 | ),
109 | ),
110 | ),
111 | ],
112 | );
113 | }
114 |
115 |
116 |
117 | dispose() {
118 | controller.dispose();
119 | super.dispose();
120 | }
121 |
122 | @override
123 | Widget build(BuildContext context) {
124 | return new Scaffold(
125 | appBar: new AppBar(
126 | title: new Text("AnimationWidget"),
127 | ),
128 | body: new Center(
129 | child: new GestureDetector(
130 | onHorizontalDragDown: (getureDragDownCallback){
131 | print("onHorizontalDragDown");
132 | },
133 | onHorizontalDragStart: (getureDragStartCallback){
134 | preXPosition=getureDragStartCallback.globalPosition.dx;
135 | },
136 | onHorizontalDragUpdate: (getureDragUpdateCallback){
137 | if((preXPosition-getureDragUpdateCallback.globalPosition.dx)>50&&preXPosition!=0.0){
138 | print("动画启动");
139 | preXPosition=0.0;
140 | directionLeft=true;
141 | controller.forward();
142 | }else if((preXPosition-getureDragUpdateCallback.globalPosition.dx)<-50&&preXPosition!=0.0){
143 | print("动画启动");
144 | preXPosition=0.0;
145 | directionLeft=false;
146 | controller.forward();
147 | }
148 | },
149 | onHorizontalDragEnd: (getureDragEndCallback){
150 | preXPosition=0.0;
151 | },
152 | child: new Stack(
153 | children: [
154 | creatRow(imageHeight*1.9, imageWidth*1.9, 30.0, imagesPaths[0]),
155 | creatRow(imageHeight*(1.9+0.3*scales), imageWidth*(1.9+0.3*scales), 30.0+scales*magins, imagesPaths[1]),
156 | creatRow(imageHeight*(2.2+0.3*scales), imageWidth*(2.2+0.3*scales),magins+30+scales*magins,imagesPaths[2]),
157 | creatRow(imageHeight*2.5,imageWidth*2.5,magins*2+30+scales*(imageWidth*2.5+40),imagesPaths[3]),
158 | ],
159 | ),
160 | )
161 | ),
162 | );
163 | }
164 | }
--------------------------------------------------------------------------------
/lib/ui/firstpage/dragablegridviewdemo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/bin/gridviewitembin.dart';
3 | import 'package:flutterapp/components/dragablegridview.dart';
4 | //import 'package:dragablegridview_flutter/dragablegridview_flutter.dart';
5 |
6 |
7 | class DragAbleGridViewDemo extends StatefulWidget{
8 | @override
9 | State createState() {
10 | return new DragAbleGridViewDemoState();
11 | }
12 |
13 | }
14 |
15 | class DragAbleGridViewDemoState extends State{
16 |
17 | List itemBins=new List();
18 | String actionTxtEdit="编辑";
19 | String actionTxtComplete="完成";
20 | String actionTxt;
21 | var editSwitchController=EditSwitchController();
22 | final List heroes=["鲁班","虞姬","甄姬","黄盖","张飞","关羽","刘备","曹操","赵云","孙策","庄周","廉颇","后裔","妲己","荆轲",];
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | actionTxt=actionTxtEdit;
28 | heroes.forEach((heroName) {
29 | itemBins.add(new ItemBin(heroName));
30 | }
31 | );
32 | }
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 | return new Scaffold(
37 | appBar: new AppBar(
38 | title: new Text("可拖拽GridView"),
39 | actions: [
40 | new Center(
41 | child: new GestureDetector(
42 | child: new Container(
43 | child: new Text(actionTxt,style: TextStyle(fontSize: 19.0),),
44 | margin: EdgeInsets.only(right: 12),
45 | ),
46 | onTap: (){
47 | changeActionState();
48 | editSwitchController.editStateChanged();
49 | },
50 | )
51 | )
52 | ],
53 | ),
54 | body: new DragAbleGridView(
55 | mainAxisSpacing:10.0,
56 | crossAxisSpacing:10.0,
57 | childAspectRatio:1.8,
58 | crossAxisCount: 4,
59 | itemBins:itemBins,
60 | editSwitchController:editSwitchController,
61 | /******************************new parameter*********************************/
62 | isOpenDragAble: true,
63 | animationDuration: 300, //milliseconds
64 | longPressDuration: 800, //milliseconds
65 | /******************************new parameter*********************************/
66 | deleteIcon: new Image.asset("images/close.png",width: 15.0 ,height: 15.0 ),
67 | child: (int position){
68 | return new Container(
69 | padding: EdgeInsets.fromLTRB(8.0, 5.0, 8.0, 5.0),
70 | decoration: new BoxDecoration(
71 | borderRadius: BorderRadius.all(new Radius.circular(3.0)),
72 | border: new Border.all(color: Colors.blue),
73 | ),
74 | //因为本布局和删除图标同处于一个Stack内,设置marginTop和marginRight能让图标处于合适的位置
75 | //Because this layout and the delete_Icon are in the same Stack, setting marginTop and marginRight will make the icon in the proper position.
76 | margin: EdgeInsets.only(top: 6.0,right: 6.0),
77 | child: new Text(
78 | itemBins[position].data,
79 | style: new TextStyle(fontSize: 16.0,color: Colors.blue),),
80 | );
81 | },
82 | editChangeListener: (){
83 | changeActionState();
84 | },
85 | ),
86 | );
87 | }
88 |
89 | void changeActionState(){
90 | if(actionTxt==actionTxtEdit){
91 | setState(() {
92 | actionTxt=actionTxtComplete;
93 | });
94 | }else{
95 | setState(() {
96 | actionTxt=actionTxtEdit;
97 | });
98 | }
99 | }
100 | }
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/lib/ui/firstpage/firstPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/ui/firstpage/adsorptionviewdemo.dart';
3 | import 'package:flutterapp/ui/firstpage/dragablegridviewdemo.dart';
4 | import 'package:flutterapp/ui/secondpage/loginanimdemo.dart';
5 | import 'package:flutterapp/ui/firstpage/pulltorefreshdemo.dart';
6 | import 'package:flutterapp/bin/appinfobin.dart';
7 | import 'package:flutterapp/ui/firstpage/animations.dart';
8 | import 'package:flutterapp/ui/firstpage/marqueedemo.dart';
9 | import 'package:flutterapp/ui/secondpage/timepicker.dart';
10 |
11 | class FirstPage extends StatefulWidget{
12 |
13 | @override
14 | State createState() {
15 | return new FirdtPageState();
16 | }
17 |
18 | }
19 |
20 | class FirdtPageState extends State{
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return new Scaffold(
25 | appBar: new AppBar(
26 | title: new Text("CustomWidght",style: new TextStyle(fontSize: 18.0),),
27 | actions: [
28 | new IconButton(
29 | icon: new Icon(Icons.search),
30 | onPressed: null,
31 | iconSize: 29.0,
32 | disabledColor: Colors.white,)
33 | ]
34 | ,),
35 | body: new Container(
36 | // ignore: conflicting_dart_import
37 | child: new ListViewWidgets(),
38 | )
39 | );
40 | }
41 | }
42 |
43 |
44 | class ListViewWidgets extends StatefulWidget{
45 |
46 | var constantList = [
47 | new AppInfoBin("Animations", "2018-07-09 17:30", "模仿京东品质潮男页面的动画效果",false),
48 | new AppInfoBin("MarqueeWidget", "2018-07-12 15:32", "跑马灯效果",false),
49 | new AppInfoBin("PullAndPush", "2018-07-27 09:45", "上下拉刷新",false),
50 | new AppInfoBin("DragAbleGridView", "2018-08-15 15:30", "可拖拽的GridView",false),
51 | new AppInfoBin("AdsorptionView", "2018-09-06 16:30", "可以吸附顶部的布局",false),
52 | ];
53 |
54 | @override
55 | State createState() {
56 | return new ListState();
57 | }
58 |
59 | }
60 |
61 | class ListState extends State{
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | return new ListView.builder(
66 | itemCount: widget.constantList.length,
67 | scrollDirection: Axis.vertical,
68 | itemBuilder: (BuildContext context,int index){
69 | return new GestureDetector(
70 | onTapDown: (TapDownDetails details){
71 | setState(() {
72 | widget.constantList[index].isTapDown=true;
73 | });
74 | },
75 | onTapCancel: (){
76 | setState(() {
77 | widget.constantList[index].isTapDown=false;
78 | });
79 | },
80 | onTapUp:(TapUpDetails details){
81 | setState(() {
82 | widget.constantList[index].isTapDown=false;
83 | });
84 | if(index==0){
85 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
86 | return new AnimationWidget();
87 | }));
88 | }else if(index==1){
89 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
90 | return new MarqueeWidgetDemo();
91 | }));
92 | }else if(index==2){
93 | Navigator.of(context).push(new PageRouteBuilder(
94 | pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
95 | return new PullAndPushTest();
96 | },
97 | transitionsBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) {
98 | return SlideTransition(
99 | position: new Tween(
100 | begin: const Offset(-1.0, 0.0),
101 | end: Offset.zero,
102 | ).animate(animation),
103 | child: child,
104 | );
105 | },
106 | ));
107 | }else if(index==3){
108 | Navigator.of(context).push(new PageRouteBuilder(
109 | pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
110 | return new DragAbleGridViewDemo();
111 | },
112 | transitionsBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) {
113 | return ScaleTransition(
114 | scale: new Tween(
115 | begin: 0.3,
116 | end: 1.0,
117 | ).animate(animation),
118 | child: child,
119 | );
120 | },
121 | ));
122 | }else if(index==4){
123 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
124 | return new AdsorptionViewDemo();
125 | }));
126 | }
127 | },
128 | child:new Card(
129 | color: widget.constantList[index].isTapDown?Color(0xFFF4CB28):null,
130 | child: new Container(
131 | padding: new EdgeInsets.all(10.0),
132 | child: new ListTile(
133 | subtitle: new Container(
134 | child: new Column(
135 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
136 | children: [
137 | new Row(
138 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
139 | children: [
140 | new Text(widget.constantList[index].title,style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 16.0,color: Colors.black),)
141 | ],
142 | ),
143 | new Row(
144 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
145 | children: [
146 | new Row(
147 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
148 | crossAxisAlignment: CrossAxisAlignment.center,
149 | children: [
150 | new Text("时间",style: new TextStyle(fontSize: 13.0)),
151 | new Text(widget.constantList[index].times,style: new TextStyle(fontSize: 13.0)),
152 | ],
153 | )
154 | ],
155 | ),
156 | new Row(
157 | children: [
158 | new Expanded(
159 | child:new Container(
160 | padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
161 | child: new Text(widget.constantList[index].content,maxLines: 1,overflow: TextOverflow.ellipsis,),
162 | ),
163 | )
164 | ],
165 | )
166 | ],
167 | ),
168 | ),
169 | trailing: new Icon(Icons.keyboard_arrow_right,color: Colors.grey,),
170 | ),
171 | ),
172 | )
173 | );
174 | },);
175 | }
176 |
177 | }
--------------------------------------------------------------------------------
/lib/ui/firstpage/marqueedemo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/components/marquee.dart';
3 | //import 'package:marquee_flutter/marquee_flutter.dart';
4 |
5 |
6 | class MarqueeWidgetDemo extends StatelessWidget{
7 | @override
8 | Widget build(BuildContext context) {
9 | return new Scaffold(
10 | appBar: new AppBar(
11 | title: new Text("跑马灯"),
12 | ),
13 | body:new Container(
14 | color: Colors.blueGrey,
15 | height: 30,
16 | child: new MarqueeWidget(
17 | text: "ListView即滚动列表控件,能将子控件组成可滚动的列表。当你需要排列的子控件超出容器大小",
18 | textStyle: new TextStyle(fontSize: 16.0),
19 | scrollAxis: Axis.horizontal,
20 | ),
21 | )
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/ui/firstpage/pulltorefreshdemo.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'dart:io';
3 | import 'dart:ui';
4 |
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter/rendering.dart';
7 | import 'package:flutterapp/components/pulltorefresh.dart';
8 | //import 'package:pulltorefresh_flutter/pulltorefresh_flutter.dart';
9 |
10 |
11 | class PullAndPushTest extends StatefulWidget{
12 |
13 | @override
14 | State createState() {
15 | return new PullAndPushTestState();
16 | }
17 | }
18 |
19 | ///PullAndPush可以使用默认的样式,在此样式的基础上可以使用default**系列的属性改变显示效果,也可以自定义RefreshBox的样式(footerRefreshBox or headerRefreshBox),也就是说可以定义其中一个,另一个用默认的,也可以全部自定义
20 | ///isPullEnable;isPushEnable属性可以控制RefreshBox 是否可用,无论是自定义的还是默认的
21 | ///PullAndPush can use the default style,Based on this style, you can use the properties of the default** series to change the display,
22 | ///You can also customize the style of the RefreshBox (footerRefreshBox or headerRefreshBox), which means you can define one of them, and the other can be customized by default or all.
23 | class PullAndPushTestState extends State with TickerProviderStateMixin{
24 | List addStrs=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
25 | List strs=["1","2","3","4","5","6","7","8","9","0"];
26 | ScrollController controller=new ScrollController();
27 | //For compatibility with ios ,must use RefreshAlwaysScrollPhysics ;为了兼容ios 必须使用RefreshAlwaysScrollPhysics
28 | ScrollPhysics scrollPhysics=new RefreshAlwaysScrollPhysics();
29 | //使用系统的请求
30 | var httpClient = new HttpClient();
31 | var url = "https://github.com/";
32 | var _result="";
33 | String customRefreshBoxIconPath="images/icon_arrow.png";
34 | AnimationController customBoxWaitAnimation;
35 | int rotationAngle=0;
36 | String customHeaderTipText="快尼玛给老子松手!";
37 | String defaultRefreshBoxTipText="快尼玛给老子松手!";
38 | ///button等其他方式,通过方法调用触发下拉刷新
39 | TriggerPullController triggerPullController=new TriggerPullController();
40 |
41 |
42 | @override
43 | void initState() {
44 | super.initState();
45 | //这个是刷新时控件旋转的动画,用来使刷新的Icon动起来
46 | customBoxWaitAnimation=new AnimationController(duration: const Duration(milliseconds: 1000*100), vsync: this);
47 | //第一次layout后会被调用
48 | WidgetsBinding.instance.addPostFrameCallback((context){
49 | print("addPostFrameCallback is invoke");
50 | //triggerPullController.triggerPull();
51 | });
52 | }
53 |
54 |
55 | @override
56 | Widget build(BuildContext context) {
57 | return new Scaffold(
58 | appBar: new AppBar(
59 | title: new Text("上下拉刷新"),
60 | ),
61 | body: new PullAndPush(
62 | //如果你headerRefreshBox和footerRefreshBox全都自定义了,则default**系列的属性均无效,假如有一个RefreshBox是用默认的(在该RefreshBox Enable的情况下)则default**系列的属性均有效
63 | //If your headerRefreshBox and footerRefreshBox are all customizable,then the default** attributes of the series are invalid,
64 | // If there is a RefreshBox is the default(In the case of the RefreshBox Enable)then the default** attributes of the series are valid
65 | defaultRefreshBoxTipText: defaultRefreshBoxTipText,
66 | headerRefreshBox: _getCustomHeaderBox(),
67 | triggerPullController:triggerPullController,
68 |
69 | //你也可以自定义底部的刷新栏;you can customize the bottom refresh box
70 | animationStateChangedCallback:(AnimationStates animationStates,RefreshBoxDirectionStatus refreshBoxDirectionStatus){
71 | _handleStateCallback( animationStates, refreshBoxDirectionStatus);
72 | },
73 | listView: new ListView.builder(
74 | //ListView的Item
75 | itemCount: strs.length,//+2,
76 | controller: controller,
77 | physics: scrollPhysics,
78 | itemBuilder: (BuildContext context,int index){
79 | return new Container(
80 | height: 35.0,
81 | child: new Center(
82 | child: new Text(strs[index],style: new TextStyle(fontSize: 18.0),),
83 | ),
84 | );
85 | }
86 | ),
87 | loadData: (isPullDown) async{
88 | await _loadData(isPullDown);
89 | },
90 | scrollPhysicsChanged: (ScrollPhysics physics) {
91 | //这个不用改,照抄即可;This does not need to change,only copy it
92 | setState(() {
93 | scrollPhysics=physics;
94 | });
95 | },
96 | )
97 | );
98 | }
99 |
100 |
101 |
102 | Widget _getCustomHeaderBox(){
103 | return new Container(
104 | color: Colors.grey,
105 | child: new Row(
106 | mainAxisAlignment: MainAxisAlignment.center,
107 | children: [
108 | new Align(
109 | alignment: Alignment.centerLeft,
110 | child: new RotatedBox(
111 | quarterTurns: rotationAngle,
112 | child: new RotationTransition( //布局中加载时动画的weight
113 | child: new Image.asset(
114 | customRefreshBoxIconPath,
115 | height: 45.0,
116 | width: 45.0,
117 | fit:BoxFit.cover,
118 | ),
119 | turns: new Tween(
120 | begin: 100.0,
121 | end: 0.0
122 | )
123 | .animate(customBoxWaitAnimation)
124 | ..addStatusListener((animationStatus) {
125 | if (animationStatus == AnimationStatus.completed) {
126 | customBoxWaitAnimation.repeat();
127 | }
128 | }
129 | ),
130 | ),
131 | ),
132 | ),
133 |
134 | new Align(
135 | alignment: Alignment.centerRight,
136 | child:new ClipRect(
137 | child:new Text(customHeaderTipText,style: new TextStyle(fontSize: 18.0,color: Color(0xffe6e6e6)),),
138 | ),
139 | ),
140 | ],
141 | )
142 | );
143 | }
144 |
145 | void _handleStateCallback(AnimationStates animationStates,RefreshBoxDirectionStatus refreshBoxDirectionStatus){
146 | switch (animationStates){
147 | //RefreshBox高度达到50,上下拉刷新可用;RefreshBox height reached 50,the function of load data is available
148 | case AnimationStates.DragAndRefreshEnabled:
149 | setState(() {
150 | //3.141592653589793是弧度,角度为180度,旋转180度;3.141592653589793 is radians,angle is 180⁰,Rotate 180⁰
151 | rotationAngle=2;
152 | });
153 | break;
154 |
155 | //开始加载数据时;When loading data starts
156 | case AnimationStates.StartLoadData:
157 | setState(() {
158 | customRefreshBoxIconPath="images/refresh.png";
159 | customHeaderTipText="正尼玛在拼命加载.....";
160 | });
161 | customBoxWaitAnimation.forward();
162 | break;
163 |
164 | //加载完数据时;RefreshBox会留在屏幕2秒,并不马上消失,这里可以提示用户加载成功或者失败
165 | // After loading the data,RefreshBox will stay on the screen for 2 seconds, not disappearing immediately,Here you can prompt the user to load successfully or fail.
166 | case AnimationStates.LoadDataEnd:
167 | customBoxWaitAnimation.reset();
168 | setState(() {
169 | rotationAngle = 0;
170 | if(refreshBoxDirectionStatus==RefreshBoxDirectionStatus.PULL) {
171 | customRefreshBoxIconPath = "images/icon_cry.png";
172 | customHeaderTipText = "加载失败!请重试";
173 | }else if(refreshBoxDirectionStatus==RefreshBoxDirectionStatus.PUSH){
174 | defaultRefreshBoxTipText="可提示用户加载成功Or失败";
175 | }
176 | });
177 | break;
178 |
179 | //RefreshBox已经消失,并且闲置;RefreshBox has disappeared and is idle
180 | case AnimationStates.RefreshBoxIdle:
181 | setState(() {
182 | rotationAngle=0;
183 | defaultRefreshBoxTipText=customHeaderTipText="快尼玛给老子松手!";
184 | customRefreshBoxIconPath="images/icon_arrow.png";
185 | });
186 | break;
187 | }
188 | }
189 |
190 | Future _loadData(bool isPullDown) async{
191 | try {
192 | var request = await httpClient.getUrl(Uri.parse(url));
193 | var response = await request.close();
194 | if (response.statusCode == HttpStatus.ok) {
195 | _result = await response.transform(utf8.decoder).join();
196 | setState(() {
197 | //拿到数据后,对数据进行梳理
198 | if(isPullDown){
199 | strs.clear();
200 | strs.addAll(addStrs);
201 | }else{
202 | strs.addAll(addStrs);
203 | }
204 | });
205 | } else {
206 | _result = 'error code : ${response.statusCode}';
207 | }
208 | } catch (exception) {
209 | _result = '网络异常';
210 | }
211 | print(_result);
212 | }
213 | }
214 |
215 |
216 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/lib/ui/secondpage/beziercurvedemo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/components/waveprogressbar.dart';
3 |
4 | class BezierCurveDemo extends StatefulWidget{
5 | @override
6 | State createState() {
7 |
8 | return BezierCurveDemoState();
9 | }
10 |
11 | }
12 |
13 | class BezierCurveDemoState extends State{
14 |
15 | final TextEditingController _controller = new TextEditingController();
16 | //默认初始值为0.0
17 | double waterHeight=0.0;
18 | WaterController waterController=WaterController();
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | WidgetsBinding widgetsBinding=WidgetsBinding.instance;
24 | widgetsBinding.addPostFrameCallback((callback){
25 | //这里写你想要显示的百分比
26 | waterController.changeProgressRate(0.82);
27 | });
28 | }
29 |
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 |
34 | return new Scaffold(
35 | resizeToAvoidBottomPadding: false,
36 | appBar: new AppBar(
37 | title: new Text("贝塞尔曲线测试"),
38 | ),
39 | body: new Column(
40 | children: [
41 | new Row(
42 | children: [
43 | new Text("高度调整: ",
44 | style: new TextStyle(fontSize: 20.0),
45 | ),
46 | new Container(
47 | width: 150.0,
48 | child: new TextField(
49 | controller: _controller,
50 | decoration: new InputDecoration(
51 | hintText: "请输入高度",
52 | )
53 | ),
54 | ),
55 | new RaisedButton(onPressed: (){
56 | print("waterHeight is ${_controller.toString()}");
57 | FocusScope.of(context).requestFocus(FocusNode());
58 | waterController.changeProgressRate(double.parse(_controller.text));
59 | },
60 | child: new Text("确定"),
61 | ),
62 | ],
63 | ),
64 | new Container(
65 | margin: EdgeInsets.only(top: 80.0),
66 | child: new Center(
67 | child: new WaveProgressBar(
68 | flowSpeed: 2.0,
69 | waveDistance:45.0,
70 | waterColor: Color(0xFF68BEFC),
71 | //strokeCircleColor: Color(0x50e16009),
72 | progressController: waterController,
73 | percentage: waterHeight,
74 | size: new Size (300,300),
75 | textStyle: new TextStyle(
76 | color:Color(0x15000000),
77 | fontSize: 60.0,
78 | fontWeight: FontWeight.bold),
79 | ),
80 | ),
81 | ),
82 | ],
83 | ),
84 | );
85 | }
86 |
87 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/blendmode.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:ui' as ui;
3 |
4 | class BlendModes extends StatefulWidget{
5 | @override
6 | State createState() {
7 | return new BlendModeState();
8 | }
9 |
10 | }
11 |
12 | class BlendModeState extends State{
13 |
14 | final double sizes=200.0;
15 | BlendMode blendMode=BlendMode.dstOver;
16 | String title="BlendMode.dstOver";
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return new Scaffold(
21 | appBar: new AppBar(
22 | title: new Text(title),
23 | actions: [
24 | new PopupMenuButton(
25 | onSelected: (value){
26 | setState(() {
27 | blendMode=value;
28 | title=value.toString();
29 | });
30 | },
31 | itemBuilder: (BuildContext context) => getItems(),
32 | ),
33 | ],
34 | ),
35 | body: new Center(
36 | child: new CustomPaint(
37 | size: new Size(sizes, sizes),
38 | painter: new BlendModePainter(blendMode),
39 | ),
40 | ),
41 | );
42 | }
43 |
44 |
45 | List> getItems(){
46 | return >[
47 | const PopupMenuItem(
48 | value: BlendMode.difference,
49 | child: Text('BlendMode.difference'),
50 | ),
51 | const PopupMenuItem(
52 | value: BlendMode.dst,
53 | child: Text('BlendMode.dst'),
54 | ),
55 | const PopupMenuItem(
56 | value: BlendMode.dstATop,
57 | child: Text('BlendMode.dstATop'),
58 | ),
59 | const PopupMenuItem(
60 | value: BlendMode.dstIn,
61 | child: Text('BlendMode.dstIn'),
62 | ),
63 | const PopupMenuItem(
64 | value: BlendMode.dstOut,
65 | child: Text('BlendMode.dstOut'),
66 | ),
67 | const PopupMenuItem(
68 | value: BlendMode.dstOver,
69 | child: Text('BlendMode.dstOver'),
70 | ),
71 | const PopupMenuItem(
72 | value: BlendMode.src,
73 | child: Text('BlendMode.src'),
74 | ),
75 | const PopupMenuItem(
76 | value: BlendMode.srcATop,
77 | child: Text('BlendMode.srcATop'),
78 | ),
79 | const PopupMenuItem(
80 | value: BlendMode.srcIn,
81 | child: Text('BlendMode.srcIn'),
82 | ),
83 | const PopupMenuItem(
84 | value: BlendMode.srcOut,
85 | child: Text('BlendMode.srcOut'),
86 | ),
87 | const PopupMenuItem(
88 | value: BlendMode.srcOver,
89 | child: Text('BlendMode.srcOver'),
90 | ),
91 | const PopupMenuItem(
92 | value: BlendMode.exclusion,
93 | child: Text('BlendMode.exclusion'),
94 | ),
95 | const PopupMenuItem(
96 | value: BlendMode.hardLight,
97 | child: Text('BlendMode.hardLight'),
98 | ),
99 | const PopupMenuItem(
100 | value: BlendMode.hue,
101 | child: Text('BlendMode.hue'),
102 | ),
103 | const PopupMenuItem(
104 | value: BlendMode.lighten,
105 | child: Text('BlendMode.lighten'),
106 | ),
107 | const PopupMenuItem(
108 | value: BlendMode.luminosity,
109 | child: Text('BlendMode.luminosity'),
110 | ),
111 | const PopupMenuItem(
112 | value: BlendMode.modulate,
113 | child: Text('BlendMode.modulate'),
114 | ),
115 | const PopupMenuItem(
116 | value: BlendMode.multiply,
117 | child: Text('BlendMode.multiply'),
118 | ),
119 | const PopupMenuItem(
120 | value: BlendMode.overlay,
121 | child: Text('BlendMode.overlay'),
122 | ),
123 | const PopupMenuItem(
124 | value: BlendMode.plus,
125 | child: Text('BlendMode.plus'),
126 | ),
127 | const PopupMenuItem(
128 | value: BlendMode.saturation,
129 | child: Text('BlendMode.saturation'),
130 | ),
131 | const PopupMenuItem(
132 | value: BlendMode.screen,
133 | child: Text('BlendMode.screen'),
134 | ),
135 | const PopupMenuItem(
136 | value: BlendMode.softLight,
137 | child: Text('BlendMode.softLight'),
138 | ),const PopupMenuItem(
139 | value: BlendMode.clear,
140 | child: Text('BlendMode.clear'),
141 | ),
142 | const PopupMenuItem(
143 | value: BlendMode.color,
144 | child: Text('BlendMode.color'),
145 | ),
146 | const PopupMenuItem(
147 | value: BlendMode.colorBurn,
148 | child: Text('BlendMode.colorBurn'),
149 | ),
150 | const PopupMenuItem(
151 | value: BlendMode.colorDodge,
152 | child: Text('BlendMode.colorDodge'),
153 | ),
154 | const PopupMenuItem(
155 | value: BlendMode.darken,
156 | child: Text('BlendMode.darken'),
157 | ),
158 |
159 | // const PopupMenuItem(
160 | // value: BlendMode.values,
161 | // child: Text('BlendMode.values'),
162 | // ),
163 | const PopupMenuItem(
164 | value: BlendMode.xor,
165 | child: Text('BlendMode.xor'),
166 | ),
167 | ];
168 | }
169 | }
170 |
171 | class BlendModePainter extends CustomPainter{
172 |
173 | final BlendMode blendMode;
174 |
175 | BlendModePainter(this.blendMode);
176 |
177 | @override
178 | void paint(Canvas canvas, Size size) {
179 | Paint paint=new Paint();
180 | Paint layerPaint=new Paint();
181 |
182 |
183 | canvas.saveLayer(new Rect.fromLTRB(0.0, 0.0, 200.0, 200.0), layerPaint);
184 | //paint.color=Color(0xff2196f3);
185 | paint.shader= ui.Gradient.linear(new Offset(0.0, 0.0), new Offset(150.0, 150.0), [Colors.red,Colors.green,Colors.blue],[0.0,0.5,1.0]);
186 | canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, 150.0, 150.0), paint);
187 | paint.shader=null;
188 |
189 |
190 | layerPaint.blendMode=blendMode ;
191 |
192 | canvas.saveLayer(new Rect.fromLTRB(0.0, 0.0, 200.0, 200.0), layerPaint);
193 | canvas.save();
194 | canvas.translate(125.0, 125.0);
195 | paint.color=Colors.yellow;
196 | canvas.drawCircle(new Offset(0.0, 0.0), 75.0, paint);
197 | canvas.restore();
198 | canvas.restore();
199 | canvas.restore();
200 | }
201 |
202 | @override
203 | bool shouldRepaint(CustomPainter oldDelegate) {
204 | return true;
205 | }
206 |
207 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/bubbles.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutterapp/bin/bubblebin.dart';
5 |
6 | class Bubbles extends StatefulWidget{
7 | @override
8 | State createState() {
9 | return new BubblesState();
10 | }
11 |
12 | }
13 |
14 | class BubblesState extends State{
15 |
16 | List _bubbles=new List();
17 | Random _random=new Random();
18 | double xBlankSpace=0.2;
19 | double _maxSpeed=6.0;
20 | double _fixedHeight;
21 | double _disappearHeight;
22 | double maxRadius=25.0;
23 | double screenWidth;
24 | double screenHeight;
25 | WidgetsBinding widgetsBinding;
26 | final List _colors=[Colors.green,Color(0XFF66BB6A),Color(0XFF4CAF50),Color(0XFF43A047),Color(0XFF388E3C),Color(0XFF2E7D32),
27 | Color(0XFF1B5E20),Color(0XFF00C853),Color(0XFF00E676),Color(0XFF64DD17),Color(0XFF76FF03)];
28 |
29 | @override
30 | void initState() {
31 | super.initState();
32 | //print("initState be invoke");
33 | widgetsBinding=WidgetsBinding.instance;
34 | widgetsBinding.addPostFrameCallback((callback){
35 | widgetsBinding.addPersistentFrameCallback((callback){
36 | print("addPersistentFrameCallback be invoke");
37 | if(mounted){
38 | setState(() {
39 | //TODO 先将数据改变,再添加新数据
40 | BubbleBin bubbleBin;
41 | for (int i=0;i<_bubbles.length;i++){
42 | bubbleBin=_bubbles[i];
43 | if(bubbleBin.yPositionxBlankSpace&&xPositionRandom<1.0-xBlankSpace
65 | && yPositionRandom>0.2
66 | && radiusRandom>0.2
67 | && speedRandom>0.2
68 | && _bubbles.length<10){
69 | _disappearHeight=screenHeight-(_fixedHeight+_fixedHeight*_getPercentageOfDisappearHeight(yPositionRandom));
70 | BubbleBin bin=new BubbleBin(
71 | radius:maxRadius*radiusRandom,
72 | color: _colors[intRandom],
73 | yPosition: screenHeight,
74 | disappearHeight: _disappearHeight,
75 | transparency: 0XFF,
76 | xPosition: screenWidth*xPositionRandom,
77 | speed: _maxSpeed*speedRandom);
78 | _bubbles.add(bin);
79 | }
80 | });
81 | widgetsBinding.scheduleFrame();
82 | }
83 |
84 | });
85 | });
86 | }
87 |
88 | @override
89 | void didChangeDependencies() {
90 | super.didChangeDependencies();
91 | Size size=MediaQuery.of(context).size;
92 | screenWidth=size.width;
93 | screenHeight=size.height;
94 | _fixedHeight=screenHeight/2.0;
95 | }
96 |
97 | double _getPercentageOfDisappearHeight(double doubleRandom){
98 | double percentageOfDisappearHeight;
99 | if(doubleRandom>0.3){
100 | percentageOfDisappearHeight=_getPercentageOfDisappearHeight(doubleRandom/2);
101 | }else{
102 | percentageOfDisappearHeight=doubleRandom;
103 | }
104 | return percentageOfDisappearHeight;
105 | }
106 |
107 |
108 |
109 | @override
110 | Widget build(BuildContext context) {
111 | return new Scaffold(
112 | appBar: new AppBar(
113 | title: new Text("泡泡"),
114 | ),
115 | body: new Container(
116 | child: new CustomPaint(
117 | size: new Size(screenWidth,screenHeight),
118 | painter: new BubblesPainter(_bubbles),
119 | ),
120 | ),
121 | );
122 | }
123 | }
124 |
125 | class BubblesPainter extends CustomPainter{
126 |
127 | final List _bubbles;
128 |
129 | BubblesPainter(this._bubbles);
130 |
131 | @override
132 | void paint(Canvas canvas, Size size) {
133 | Paint paint=new Paint();
134 | paint.style=PaintingStyle.fill;
135 | BubbleBin bin;
136 | Offset offset;
137 | Color color;
138 | for (int i=0;i<_bubbles.length;i++){
139 | bin=_bubbles[i];
140 | color=bin.color;
141 | paint.color=color.withAlpha(bin.transparency);
142 | offset=new Offset(bin.xPosition, bin.yPosition);
143 | canvas.drawCircle(offset , bin.radius, paint);
144 | }
145 | }
146 |
147 | @override
148 | bool shouldRepaint(CustomPainter oldDelegate) {
149 | return true;
150 | }
151 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/dashboard.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 |
6 |
7 | class DashBoard extends StatefulWidget{
8 | @override
9 | State createState() {
10 | return new DashBoardState();
11 | }
12 | }
13 |
14 |
15 | class DashBoardState extends State{
16 |
17 | final platform = const MethodChannel('com.flutter.lgyw/sensor');
18 | bool _isGetPressure=false;
19 | int pressures=0;final double wholeCirclesRadian=6.283185307179586;
20 | ///虽然一个圆被分割为160份,但是只显示120份
21 | final int tableCount=160;
22 | Size dashBoardSize;
23 | double tableSpace;
24 | Picture _pictureBackGround;
25 | Picture _pictureIndicator;
26 |
27 | @override
28 | void initState() {
29 | super.initState();
30 | dashBoardSize=new Size(300.0,300.0);
31 | tableSpace=wholeCirclesRadian/tableCount;
32 | _pictureBackGround=DashBoardTablePainter(tableSpace,dashBoardSize).getBackGround();
33 | _pictureIndicator=IndicatorPainter(dashBoardSize).drawIndicator();
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | return new Scaffold(
39 | appBar: new AppBar(
40 | title: new Text("汽车仪表盘"),
41 | ),
42 | body: new Center(
43 | child:GestureDetector(
44 | onPanDown:(DragDownDetails dragDownDetails){
45 | _isGetPressure=true;
46 | boostSpeed();
47 | },
48 | onPanCancel: (){
49 | handleEndEvent();
50 | },
51 | onPanEnd: (DragEndDetails dragEndDetails){
52 | handleEndEvent();
53 | },
54 | child:new CustomPaint(
55 | size: dashBoardSize,
56 | painter: new DashBoardIndicatorPainter(pressures,tableSpace,_pictureBackGround,_pictureIndicator),
57 | ),
58 | ),
59 | ),
60 | );
61 | }
62 |
63 | void boostSpeed() async {
64 | while (_isGetPressure){
65 | if(pressures<120){
66 | setState(() {
67 | pressures++;
68 | });
69 | }
70 | await Future.delayed(new Duration(milliseconds: 30));
71 | }
72 | }
73 |
74 |
75 | void handleEndEvent(){
76 | _isGetPressure=false;
77 | bringDownSpeed();
78 | }
79 |
80 |
81 | void bringDownSpeed() async {
82 | while (!_isGetPressure){
83 | setState(() {
84 | pressures--;
85 | });
86 |
87 | if(pressures<=0){
88 | break;
89 | }
90 | await Future.delayed(new Duration(milliseconds: 30));
91 | }
92 | }
93 | }
94 |
95 |
96 | class DashBoardIndicatorPainter extends CustomPainter{
97 |
98 | final int speeds;
99 | double tableSpace;
100 | final Picture pictureBackGround;
101 | final Picture pictureIndicator;
102 |
103 | DashBoardIndicatorPainter(this.speeds,this.tableSpace,this.pictureBackGround,this.pictureIndicator);
104 |
105 | @override
106 | void paint(Canvas canvas, Size size) {
107 | canvas.drawPicture(pictureBackGround);
108 | drawIndicator( canvas, size);
109 | String text;
110 | if(speeds<100){
111 | text=(speeds*2).toString()+"KM/H";
112 | }else{
113 | int s=speeds-100;
114 | text=(100*2+s*3).toString()+"KM/H";
115 | }
116 | drawSpeendOnDashBoard(text,canvas, size);
117 | }
118 |
119 | @override
120 | bool shouldRepaint(CustomPainter oldDelegate) {
121 | return true;
122 | }
123 |
124 | ///画实时得速度值到面板上
125 | void drawSpeendOnDashBoard(String text,Canvas canvas,Size size){
126 | double halfHeight=size.height/2;
127 | double halfWidth=size.width/2;
128 | canvas.save();
129 | canvas.translate(halfWidth, halfHeight);
130 |
131 | TextPainter textPainter = new TextPainter();
132 | textPainter.textDirection = TextDirection.ltr;
133 | textPainter.text = new TextSpan(text: text, style: new TextStyle(color:Colors.deepOrangeAccent,fontSize: 25.0,fontStyle: FontStyle.italic,fontWeight: FontWeight.bold));
134 | textPainter.layout();
135 | double textStarPositionX = -textPainter.size.width / 2;
136 | double textStarPositionY = 73;
137 | textPainter.paint(canvas, new Offset(textStarPositionX, textStarPositionY));
138 |
139 | canvas.restore();
140 | }
141 |
142 |
143 |
144 | ///画速度指针
145 | void drawIndicator(Canvas canvas, Size size){
146 | double halfHeight=size.height/2;
147 | double halfWidth=size.width/2;
148 |
149 | canvas.save();
150 | canvas.translate(halfWidth, halfHeight);
151 | canvas.rotate((-60+speeds)*tableSpace);
152 | canvas.translate(-halfWidth, -halfHeight);
153 |
154 | canvas.drawPicture(pictureIndicator);
155 |
156 | canvas.restore();
157 | }
158 | }
159 |
160 |
161 | class IndicatorPainter {
162 |
163 | final PictureRecorder _recorder = PictureRecorder();
164 | final Size size;
165 |
166 | IndicatorPainter(this.size);
167 |
168 | ///画速度指针
169 | Picture drawIndicator(){
170 | Canvas canvas=Canvas(_recorder);
171 | canvas.clipRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height));
172 |
173 | double halfHeight=size.height/2;
174 | double halfWidth=size.width/2;
175 | Path path=new Path();
176 | path.moveTo(-2.5, 20);
177 | path.lineTo(2.5, 20);
178 | path.lineTo(6.0, -30);
179 | path.lineTo(0.5, -halfHeight+8);
180 | path.lineTo(-0.5, -halfHeight+8);
181 | path.lineTo(-6.0, -30);
182 | path.close();
183 | canvas.save();
184 |
185 | canvas.translate(halfWidth, halfHeight);
186 |
187 | Paint paint=new Paint();
188 | paint.color=Colors.red;
189 | paint.style=PaintingStyle.fill;
190 |
191 | canvas.drawPath(path, paint);
192 |
193 | paint.color=Colors.black;
194 | canvas.drawCircle(new Offset(0.0,0.0), 6, paint);
195 |
196 | canvas.restore();
197 | return _recorder.endRecording();
198 | }
199 | }
200 |
201 |
202 |
203 |
204 | class DashBoardTablePainter {
205 |
206 | final double tableSpace;
207 | var speedTexts=["0","20","40","60","80","100","120","140","160","180","200","230","260"];
208 | final Size size;
209 | final PictureRecorder _recorder = PictureRecorder();
210 |
211 | DashBoardTablePainter(this.tableSpace,this.size);
212 |
213 | Picture getBackGround() {
214 | Canvas canvas=Canvas(_recorder);
215 | canvas.clipRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height));
216 | drawTable( canvas, size);
217 | return _recorder.endRecording();
218 | }
219 |
220 |
221 | ///画仪表盘的表格
222 | void drawTable(Canvas canvas, Size size){
223 | canvas.save();
224 | double halfWidth=size.width/2;
225 | double halfHeight=size.height/2;
226 | canvas.translate(halfWidth, halfHeight);
227 |
228 | Paint paintMain=new Paint();
229 | paintMain.color=Colors.blue;
230 | paintMain.strokeWidth=2.5;
231 | paintMain.style=PaintingStyle.fill;
232 |
233 |
234 | Paint paintOther=new Paint();
235 | paintOther.color=Colors.blue;
236 | paintOther.strokeWidth=1;
237 | paintOther.style=PaintingStyle.fill;
238 |
239 | drawLongLine(canvas,paintMain,halfHeight,speedTexts[6]);
240 |
241 | canvas.save();
242 | for(int i=61;i<=120;i++){
243 | canvas.rotate(tableSpace);
244 | if(i%10==0){
245 | int a=(i/10).ceil();
246 | changePaintColors(paintMain,i);
247 | drawLongLine(canvas,paintMain,halfHeight,speedTexts[a]);
248 | }else if(i%5==0){
249 | changePaintColors(paintMain,i);
250 | drawMiddleLine(canvas,paintMain,halfHeight);
251 | }else{
252 | changePaintColors(paintOther,i);
253 | drawSmallLine(canvas,paintOther,halfHeight);
254 | }
255 | }
256 | canvas.restore();
257 |
258 |
259 | canvas.save();
260 | for(int i=59;i>=0;i--){
261 | canvas.rotate(-tableSpace);
262 | if(i%10==0){
263 | int a=(i/10).ceil();
264 | changePaintColors(paintMain,i);
265 | drawLongLine(canvas,paintMain,halfHeight,speedTexts[a]);
266 | }else if(i%5==0){
267 | changePaintColors(paintMain,i);
268 | drawMiddleLine(canvas,paintMain,halfHeight);
269 | }else{
270 | changePaintColors(paintOther,i);
271 | drawSmallLine(canvas,paintOther,halfHeight);
272 | }
273 | }
274 | canvas.restore();
275 |
276 | canvas.restore();
277 | }
278 |
279 |
280 | void changePaintColors(Paint paint,int value){
281 | if(value<=20){
282 | paint.color=Colors.green;
283 | }else if(value<80){
284 | paint.color=Colors.blue;
285 | }else{
286 | paint.color=Colors.red;
287 | }
288 | }
289 |
290 | ///画仪表盘上的长线
291 | void drawLongLine(Canvas canvas,Paint paintMain,double halfHeight,String text){
292 | canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+15), paintMain);
293 |
294 | TextPainter textPainter = new TextPainter();
295 | textPainter.textDirection = TextDirection.ltr;
296 | textPainter.text = new TextSpan(text: text, style: new TextStyle(color:paintMain.color,fontSize: 15.5,));
297 | textPainter.layout();
298 | double textStarPositionX = -textPainter.size.width / 2;
299 | double textStarPositionY = -halfHeight+19;
300 | textPainter.paint(canvas, new Offset(textStarPositionX, textStarPositionY));
301 | }
302 |
303 |
304 | void drawMiddleLine(Canvas canvas,Paint paintMain,double halfHeight){
305 | canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+10), paintMain);
306 | }
307 |
308 |
309 | ///画短线
310 | void drawSmallLine(Canvas canvas,Paint paintOther,double halfHeight){
311 | canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+7), paintOther);
312 | }
313 |
314 | }
315 |
316 |
--------------------------------------------------------------------------------
/lib/ui/secondpage/drawablestarttext.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/components/drawablestarttext.dart';
3 |
4 | class DrawableStartTextDemo extends StatelessWidget{
5 | @override
6 | Widget build(BuildContext context) {
7 |
8 | return new Scaffold(
9 | appBar: new AppBar(
10 | title: new Text("DrawableStartText"),
11 | ),
12 | body: new Center(
13 | child: new Container(
14 | child: new DrawableStartText(
15 | assetImage: "images/tianmao.jpg",
16 | text: " 莫顿 全自动感应壁挂式酒精喷雾式手消毒器 手消毒机杀菌净手器",
17 | textStyle: new TextStyle(fontSize: 17.0),
18 | ),
19 | ),
20 | ),
21 | );
22 | }
23 | }
24 |
25 |
26 |
--------------------------------------------------------------------------------
/lib/ui/secondpage/loginanimdemo.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:convert';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | import 'package:flutterapp/components/loginanimation.dart';
7 |
8 | class LoginAnimationDemo extends StatefulWidget{
9 |
10 | final String loginTip="登陆";
11 | final double width=200.0,height=40.0;
12 |
13 | @override
14 | State createState() {
15 | return new LoginAnimationDemoState();
16 | }
17 |
18 | }
19 |
20 | class LoginAnimationDemoState extends State{
21 |
22 | //使用系统的请求
23 | var httpClient = new HttpClient();
24 | var url = "https://github.com/";
25 | var _result="";
26 | final LoginErrorMessageController loginErrorMessageController=LoginErrorMessageController();
27 |
28 | @override
29 | void initState() {
30 | super.initState();
31 | }
32 |
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 |
37 | return new Scaffold(
38 | appBar: new AppBar(
39 | title: new Text("登陆按钮动画"),
40 | ),
41 | body: new Center(
42 | child:new Container(
43 | child:new AnimatedLoginButton(
44 | loginErrorMessageController:loginErrorMessageController,
45 | onTap: () async {
46 | try {
47 | var request = await httpClient.getUrl(Uri.parse(url));
48 | var response = await request.close();
49 | if (response.statusCode == HttpStatus.ok) {
50 | _result = await response.transform(utf8.decoder).join();
51 |
52 | //拿到数据后,对数据进行梳理
53 | loginErrorMessageController.showErrorMessage("网络异常");
54 |
55 | } else {
56 | _result = 'ERROR CODE: ${response.statusCode}';
57 | loginErrorMessageController.showErrorMessage("网络异常 $_result");
58 | }
59 | } catch (exception) {
60 | _result = '网络异常';
61 | loginErrorMessageController.showErrorMessage("网络异常");
62 | }
63 | print(_result);
64 | },
65 | ),
66 | ),
67 | ),
68 | );
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/radarchartdemo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/components/radarchart.dart';
3 |
4 | class RadarChartDemo extends StatelessWidget{
5 | @override
6 | Widget build(BuildContext context) {
7 |
8 | return new Scaffold(
9 | appBar: new AppBar(
10 | title: new Text("雷达图"),
11 | ),
12 | body: new Center(
13 | child: new RadarChart(),
14 | ),
15 | );
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/secondPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/bin/appinfobin.dart';
3 | import 'package:flutterapp/ui/secondpage/beziercurvedemo.dart';
4 | import 'package:flutterapp/ui/secondpage/blendmode.dart';
5 | import 'package:flutterapp/ui/secondpage/bubbles.dart';
6 | import 'package:flutterapp/ui/secondpage/dashboard.dart';
7 | import 'package:flutterapp/ui/secondpage/drawablestarttext.dart';
8 | import 'package:flutterapp/ui/secondpage/loginanimdemo.dart';
9 | import 'package:flutterapp/ui/secondpage/radarchartdemo.dart';
10 | import 'package:flutterapp/ui/secondpage/timepicker.dart';
11 |
12 | class SecondPage extends StatefulWidget{
13 |
14 | @override
15 | State createState() {
16 | return new SecondPageState();
17 | }
18 |
19 | }
20 |
21 | class SecondPageState extends State{
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return new Scaffold(
26 | appBar: new AppBar(
27 | title: new Text("CustomWidght",style: new TextStyle(fontSize: 18.0),),
28 | actions: [
29 | new IconButton(
30 | icon: new Icon(Icons.search),
31 | onPressed: null,
32 | iconSize: 29.0,
33 | disabledColor: Colors.white,)
34 | ]
35 | ,),
36 | body: new Container(
37 | // ignore: conflicting_dart_import
38 | child: new ListViewWidgets(),
39 | )
40 | );
41 | }
42 | }
43 |
44 |
45 | class ListViewWidgets extends StatefulWidget{
46 |
47 | var constantList = [
48 | new AppInfoBin("IOSPicker", "2018-07-16 16:16", "自定义仿IOS时间选择器",false),
49 | new AppInfoBin("LoginAnimation", "2018-11-26 10:05", "登陆按钮的动画",false),
50 | new AppInfoBin("BlendMode", "2018-11-28 10:52", "BlendMode测试",false),
51 | new AppInfoBin("DashBoard", "2018-11-29 14:34", "汽车仪表盘模拟",false),
52 | new AppInfoBin("Bubbles", "2018-12-07 10:38", "泡泡往上冒的动画",false),
53 | new AppInfoBin("BezierCurve", "2018-12-26 16:00", "水波纹效果",false),
54 | new AppInfoBin("RadarChart", "2019-01-02 15:33", "雷达图(蜘蛛网图)",false),
55 | new AppInfoBin("DrawableStartText", "2019-01-10 09:27", "文字的开头添加标签",false),
56 | ];
57 |
58 | @override
59 | State createState() {
60 | return new ListState();
61 | }
62 |
63 | }
64 |
65 | class ListState extends State{
66 |
67 | @override
68 | Widget build(BuildContext context) {
69 | return new ListView.builder(
70 | itemCount: widget.constantList.length,
71 | itemBuilder: (BuildContext context,int index){
72 | return new GestureDetector(
73 | onTapDown: (TapDownDetails details){
74 | setState(() {
75 | widget.constantList[index].isTapDown=true;
76 | });
77 | },
78 | onTapCancel: (){
79 | setState(() {
80 | widget.constantList[index].isTapDown=false;
81 | });
82 | },
83 | onTapUp:(TapUpDetails details){
84 | setState(() {
85 | widget.constantList[index].isTapDown=false;
86 | });
87 | if(index==0){
88 | Navigator.of(context).push(new PageRouteBuilder(
89 | pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
90 | return new Timepicker();
91 | },
92 | transitionsBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) {
93 | return ScaleTransition(
94 | scale: new Tween(
95 | begin: 0.3,
96 | end: 1.0,
97 | ).animate(animation),
98 | child: child,
99 | );
100 | },
101 | ));
102 | }else if(index==1){
103 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
104 | return new LoginAnimationDemo();
105 | }));
106 | }else if(index==2){
107 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
108 | return new BlendModes();
109 | }));
110 | }else if(index==3){
111 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
112 | return new DashBoard();
113 | }));
114 | }else if(index==4){
115 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
116 | return new Bubbles();
117 | }));
118 | }else if(index==5){
119 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
120 | return new BezierCurveDemo();
121 | }));
122 | }else if(index==6){
123 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
124 | return new RadarChartDemo();
125 | }));
126 | }else if(index==7){
127 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
128 | return new DrawableStartTextDemo();
129 | }));
130 | }
131 | },
132 | child:new Card(
133 | color: widget.constantList[index].isTapDown?Color(0xFFF4CB28):null,
134 | child: new Container(
135 | padding: new EdgeInsets.all(10.0),
136 | child: new ListTile(
137 | subtitle: new Container(
138 | child: new Column(
139 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
140 | children: [
141 | new Row(
142 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
143 | children: [
144 | new Text(widget.constantList[index].title,style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 16.0,color: Colors.black),)
145 | ],
146 | ),
147 | new Row(
148 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
149 | children: [
150 | new Row(
151 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
152 | crossAxisAlignment: CrossAxisAlignment.center,
153 | children: [
154 | new Text("时间",style: new TextStyle(fontSize: 13.0)),
155 | new Text(widget.constantList[index].times,style: new TextStyle(fontSize: 13.0)),
156 | ],
157 | )
158 | ],
159 | ),
160 | new Row(
161 | children: [
162 | new Expanded(
163 | child:new Container(
164 | padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
165 | child: new Text(widget.constantList[index].content,maxLines: 1,overflow: TextOverflow.ellipsis,),
166 | ),
167 | )
168 | ],
169 | )
170 | ],
171 | ),
172 | ),
173 | trailing: new Icon(Icons.keyboard_arrow_right,color: Colors.grey,),
174 | ),
175 | ),
176 | )
177 | );
178 | },);
179 | }
180 |
181 | }
--------------------------------------------------------------------------------
/lib/ui/secondpage/timepicker.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/physics.dart';
5 |
6 | class Timepicker extends StatefulWidget{
7 | @override
8 | State createState() {
9 | return new TimepickerState();
10 | }
11 |
12 | }
13 |
14 | class TimepickerState extends State with SingleTickerProviderStateMixin{
15 |
16 | List hours;
17 | AnimationController controller;
18 | Animation animation;
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | controller = new AnimationController(duration: const Duration(milliseconds: 1800), vsync: this);
24 | hours=new List();
25 | for(int i=0;i<24;i++){
26 | hours.add(i.toString()+"小时");
27 | }
28 | }
29 |
30 |
31 | double start=0.0;
32 | double offset=0.0;
33 | TextPaintCanvas paintCanvas;
34 | FrictionSimulation frictionSimulation;
35 | AnimationStatusListener statusListener;
36 | VoidCallback voidCallback;
37 | int downTime;
38 |
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return new Scaffold(
43 | backgroundColor: Colors.white70,
44 | appBar: new AppBar(
45 | title: new Text("时间选择器"),
46 | ),
47 | body: new Builder(builder: (BuildContext contextx){
48 | return new Center(
49 | child:new Container(
50 | width: 80.0,
51 | height: 130.0,
52 | child: new GestureDetector(
53 | onVerticalDragDown: (getureDragDownCallback){
54 | if(!controller.isCompleted) {
55 | paintCanvas.changeFirstCount();
56 | animation.removeListener(voidCallback);
57 | animation.removeStatusListener(statusListener);
58 | controller.reset();
59 | }
60 | },
61 | onVerticalDragStart: (getureDragStartCallback){
62 | downTime=DateTime.now().millisecondsSinceEpoch;
63 | start=getureDragStartCallback.globalPosition.dy;
64 | },
65 | /******************************************************************************************************************/
66 | onVerticalDragEnd: (getureDragEndCallback){
67 | Velocity velo=getureDragEndCallback.velocity;
68 | if(velo.pixelsPerSecond.dy.isNaN){
69 | return;
70 | }
71 | double lastOffset=offset;
72 | double distance=(velo.pixelsPerSecond.dy).abs()/10;
73 | if(DateTime.now().millisecondsSinceEpoch-downTime<300&&lastOffset<15&&distance==0.0){
74 | return;
75 | }
76 | double controlOffset = paintCanvas.getOffset(distance + lastOffset.abs());
77 | if(controlOffset.isNaN){
78 | return;
79 | }
80 | if(distance==0.0){
81 | distance=paintCanvas.getItemHeight()-controlOffset;
82 | }
83 |
84 |
85 | double scrollOffset;
86 | if(velo.pixelsPerSecond.dy==0.0){
87 | frictionSimulation=new FrictionSimulation.through(0.0,distance+0.1,20.0,0.0);
88 | scrollOffset=frictionSimulation.timeAtX(distance);
89 | }else{
90 | frictionSimulation=new FrictionSimulation.through(0.0,distance,20.0,0.0);
91 | scrollOffset=frictionSimulation.timeAtX(distance-controlOffset);
92 | }
93 |
94 |
95 | animation = new Tween(begin: 0.0, end: scrollOffset).animate(controller);
96 | voidCallback=(){
97 | if(animation.value==0.0){
98 | return;
99 | }
100 | if(offset<0){
101 | offset=-(frictionSimulation.x(animation.value))+lastOffset;
102 | }else{
103 | offset=frictionSimulation.x(animation.value)+lastOffset;
104 | }
105 | if(offset.isNaN){
106 | return;
107 | }
108 | setState(() {
109 | paintCanvas.changeDatas(offset,hours);
110 | });
111 | };
112 | statusListener=(animationStatus){
113 | if(animationStatus==AnimationStatus.completed){
114 | //offset=0.0;
115 | paintCanvas.changeFirstCount();
116 | animation.removeListener(voidCallback);
117 | animation.removeStatusListener(statusListener);
118 | controller.reset();
119 | Scaffold.of(contextx).showSnackBar(new SnackBar(content: new Text(hours[3]),duration: new Duration(seconds: 1),));
120 | }else if(animationStatus==AnimationStatus.forward){
121 | //frictionSimulation.x(430.0);
122 | }
123 | };
124 | animation.addStatusListener(statusListener);
125 | animation.addListener(voidCallback);
126 | controller.forward();
127 | },
128 | /******************************************************************************************************************/
129 | onVerticalDragUpdate: (getureDragUpdateCallback){
130 | double point =getureDragUpdateCallback.globalPosition.dy;
131 | offset=start-point;
132 | if(offset.abs()<15){
133 | return;
134 | }
135 | setState(() {
136 | paintCanvas.changeDatas(offset,hours);
137 | });
138 | },
139 | onVerticalDragCancel: (){
140 |
141 | },
142 | child: new CustomPaint(
143 | painter: paintCanvas=new TextPaintCanvas(-offset,hours),
144 | )
145 | ),
146 | ),
147 | );
148 | }),
149 | );
150 | }
151 | }
152 |
153 | class TextPaintCanvas extends CustomPainter{
154 |
155 | TextPaintCanvas(this.offset,this.hours);
156 |
157 | double offset;
158 | static double maginsHeight=0.0;
159 | static double smallTextHright=0.0;
160 | static int firstCount=0;
161 | List hours;
162 | static double preOffset=0.0;
163 | static int modle=0;
164 |
165 |
166 | void changeFirstCount(){
167 | firstCount=0;
168 | preOffset=0.0;
169 | firstCount=0;
170 | modle=0;
171 | }
172 |
173 | double getOffset(double lastOffset){
174 | if(maginsHeight!=0.0) {
175 | return lastOffset % (smallTextHright + maginsHeight);
176 | }
177 | return 0.0;
178 | }
179 |
180 | double getItemHeight(){
181 | if(maginsHeight!=0.0) {
182 | return smallTextHright + maginsHeight;
183 | }
184 | return 0.0;
185 | }
186 |
187 | void changeDatas(double offsets,List hours){
188 | if(maginsHeight!=0.0) {
189 | int a = offsets ~/ (smallTextHright + maginsHeight);
190 | if (firstCount != a) {
191 | //向上滑
192 | if (preOffset-offsets<0) {
193 | //移除第一个,加到末尾
194 | if(getOffset(offsets)==0.0){
195 | return;
196 | }
197 | String first = hours.first;
198 | hours.removeAt(0);
199 | hours.add(first);
200 | firstCount ++;
201 | preOffset=offsets;
202 | //向下滑
203 | } else if (preOffset-offsets>0) {
204 | //除去最后一个。加到前面
205 | String last = hours.last;
206 | hours.removeLast();
207 | hours.insert(0, last);
208 | firstCount --;
209 | preOffset=offsets;
210 | }
211 | }else if(firstCount == a&&firstCount==0){
212 | if(offsets>0&&modle!=1){
213 | modle=1;
214 | String first = hours.first;
215 | hours.removeAt(0);
216 | hours.add(first);
217 | }else if(offsets<0&&modle!=-1){
218 | modle=-1;
219 | String last = hours.last;
220 | hours.removeLast();
221 | hours.insert(0, last);
222 | }
223 | }
224 | }
225 | }
226 |
227 | void parseOffset(){
228 | if(maginsHeight!=0.0) {
229 | offset = offset % (smallTextHright + maginsHeight);
230 | //print(offset);
231 | }
232 | }
233 |
234 |
235 | double getRadian(double itemOffset,double controlHeight,double maginsHeight,double smallTextHright){
236 | double radian;
237 | double radius=controlHeight/2+smallTextHright+maginsHeight;
238 | if(itemOffsetcontrolHeight/2){
243 | double offHeight=itemOffset-controlHeight/2+smallTextHright;
244 | radian=-asin(offHeight/radius);
245 | }else if(itemOffset==controlHeight/2){
246 | radian=0.0;
247 | }
248 | print(radian);
249 | return radian;
250 | }
251 |
252 | void drawText(Canvas canvas,TextPainter painterSmall,double itemOffset,String texts){
253 | canvas.save();
254 | canvas.translate(0.0, itemOffset);
255 | painterSmall.text=new TextSpan(text: texts,style: new TextStyle(fontSize: 18.0,color: Colors.black));
256 | painterSmall.layout();
257 | if(smallTextHright==0.0){
258 | smallTextHright=painterSmall.size.height;
259 | }
260 | double smallTextWidth=painterSmall.size.width;
261 | //计算间距
262 | if(maginsHeight==0.0){
263 | maginsHeight=(130.0-smallTextHright*5.0)/4;
264 | }
265 | try {
266 | canvas.transform(Matrix4.rotationX(getRadian(itemOffset, 130.0, maginsHeight, smallTextHright)).storage);
267 | }catch(e){
268 |
269 | }
270 | painterSmall.paint(canvas, new Offset((80-smallTextWidth)/2, 0.0));
271 | canvas.restore();
272 | }
273 |
274 |
275 |
276 | @override
277 | void paint(Canvas canvas, Size size) {
278 | parseOffset();
279 | canvas.clipRect(new Rect.fromLTRB(0.0, 0.0, 80.0, 130.0));
280 |
281 | TextPainter painterSmall=new TextPainter();
282 | painterSmall.textDirection=TextDirection.ltr;
283 | painterSmall.maxLines=1;
284 |
285 | //第一条Item,初始化不可见
286 | drawText(canvas,painterSmall,-maginsHeight-smallTextHright+offset,hours[0]);
287 | //第二条Item
288 | drawText(canvas,painterSmall,offset,hours[1]);
289 | //第三条Item
290 | drawText(canvas,painterSmall,maginsHeight+smallTextHright+offset,hours[2]);
291 | //最中间的Item
292 | drawText(canvas,painterSmall,maginsHeight*2+smallTextHright*2+offset,hours[3]);
293 | //第五条Item
294 | drawText(canvas,painterSmall,maginsHeight*3+smallTextHright*3+offset,hours[4]);
295 | //第六条Item
296 | drawText(canvas,painterSmall,maginsHeight*4+smallTextHright*4+offset,hours[5]);
297 | //第七条Item
298 | drawText(canvas,painterSmall,maginsHeight*5+smallTextHright*5+offset,hours[6]);
299 |
300 | Rect rect=Rect.fromLTRB(0.0, 0.0, 80.0, maginsHeight*2+smallTextHright*2);
301 | Paint paintRext=new Paint();
302 | paintRext.color=Color(0x90ffffff);
303 | canvas.drawRect(rect, paintRext);
304 |
305 | canvas.translate(0.0, maginsHeight*2+smallTextHright*3);
306 | rect=Rect.fromLTRB(0.0, 0.0, 80.0, maginsHeight*2+smallTextHright*2);
307 | canvas.drawRect(rect, paintRext);
308 | }
309 |
310 | @override
311 | bool shouldRepaint(CustomPainter oldDelegate) {
312 | return true;
313 | }
314 |
315 | }
316 |
317 |
--------------------------------------------------------------------------------
/lib/ui/thirdpage/cutScreen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:ui' as ui show Image;
3 |
4 | import 'package:flutter/rendering.dart';
5 |
6 | class CutScreen extends StatefulWidget{
7 |
8 | @override
9 | State createState() {
10 | return new CutScreenState();
11 | }
12 |
13 | }
14 |
15 | class CutScreenState extends State{
16 |
17 | ui.Image image;
18 | ImagePaint paintCanvas;
19 | GlobalKey _globalKey=new GlobalKey();
20 | double screenWidth,screenHeight;
21 |
22 |
23 | @override
24 | void didChangeDependencies() {
25 | super.didChangeDependencies();
26 | Size size=MediaQuery.of(context).size;
27 | screenWidth=size.width;
28 | screenHeight=size.height;
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return new RepaintBoundary(
34 | key: _globalKey,
35 | child: new Scaffold(
36 | appBar: new AppBar(title: new Text("界面3"),),
37 | body:new Column(
38 | children: [
39 | new RaisedButton(
40 | child:new Text("点击显示图片"),
41 | onPressed: () async {
42 | RenderRepaintBoundary boundary = _globalKey.currentContext
43 | .findRenderObject();
44 | image = await boundary.toImage(pixelRatio: 1.0);
45 | setState(() {
46 |
47 | });
48 | }
49 | ),
50 | new CustomPaint(
51 | size: new Size(screenWidth, screenHeight),
52 | painter: paintCanvas=new ImagePaint(image,screenWidth,screenHeight),
53 | ),
54 | ],
55 | ),
56 | ),
57 | );
58 | }
59 | }
60 |
61 | class ImagePaint extends CustomPainter{
62 |
63 | ImagePaint(this.image,this.screenWidth,this.screenHeight);
64 |
65 | ui.Image image;
66 | final double screenWidth,screenHeight;
67 |
68 | @override
69 | void paint(Canvas canvas, Size size) {
70 | if(image!=null){
71 | canvas.drawImage(image, new Offset(0.0, 0.0), new Paint());
72 | }else{
73 | Paint paint=new Paint();
74 | paint.color=Colors.amberAccent;
75 | canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, screenWidth, screenHeight), paint);
76 | }
77 | }
78 |
79 | @override
80 | bool shouldRepaint(CustomPainter oldDelegate) {
81 | return true;
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/lib/ui/thirdpage/examples/CameraTest.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 | import 'dart:io';
4 | import 'package:camera/camera.dart';
5 | import 'package:path_provider/path_provider.dart';
6 | import 'package:flutterapp/main.dart';
7 |
8 |
9 |
10 | class CameraExampleHome extends StatefulWidget {
11 |
12 | @override
13 | _CameraExampleHomeState createState() {
14 | return _CameraExampleHomeState();
15 | }
16 | }
17 |
18 | void logError(String code, String message) =>
19 | print('Error: $code\nError Message: $message');
20 |
21 | class _CameraExampleHomeState extends State {
22 | CameraController controller;
23 | String imagePath;
24 | String videoPath;
25 | VoidCallback videoPlayerListener;
26 |
27 | final GlobalKey _scaffoldKey = GlobalKey();
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | key: _scaffoldKey,
33 | appBar: AppBar(
34 | title: const Text('Camera example'),
35 | ),
36 | body: Column(
37 | children: [
38 | Expanded(
39 | child: Container(
40 | child: Padding(
41 | padding: const EdgeInsets.all(1.0),
42 | child: Center(
43 | child: _cameraPreviewWidget(),
44 | ),
45 | ),
46 | decoration: BoxDecoration(
47 | color: Colors.black,
48 | border: Border.all(
49 | color: controller != null && controller.value.isRecordingVideo
50 | ? Colors.redAccent
51 | : Colors.grey,
52 | width: 3.0,
53 | ),
54 | ),
55 | ),
56 | ),
57 | Padding(
58 | padding: const EdgeInsets.all(5.0),
59 | child: Row(
60 | mainAxisAlignment: MainAxisAlignment.start,
61 | children: [
62 | _captureControlRowWidget(),
63 | _thumbnailWidget(),
64 | ],
65 | ),
66 | ),
67 | ],
68 | ),
69 | );
70 | }
71 |
72 | /// 显示相机的预览(如果预览不可用,则显示消息)。
73 | /// Display the preview from the camera (or a message if the preview is not available).
74 | Widget _cameraPreviewWidget() {
75 | if (controller == null || !controller.value.isInitialized) {
76 | return const Text(
77 | 'Tap a camera',
78 | style: TextStyle(
79 | color: Colors.white,
80 | fontSize: 24.0,
81 | fontWeight: FontWeight.w900,
82 | ),
83 | );
84 | } else {
85 | return AspectRatio(
86 | aspectRatio: controller.value.aspectRatio,
87 | child: CameraPreview(controller),
88 | );
89 | }
90 | }
91 |
92 | /// 显示捕获的图像或视频的缩略图。
93 | /// Display the thumbnail of the captured image or video.
94 | Widget _thumbnailWidget() {
95 | return Expanded(
96 | child: Align(
97 | alignment: Alignment.centerRight,
98 | child: imagePath == null
99 | ? null : SizedBox(
100 | child: Image.file(File(imagePath)),
101 | width: 64.0,
102 | height: 64.0,
103 | ),
104 | ),
105 | );
106 | }
107 |
108 | /// 使用按钮显示控制栏以拍摄照片和录制视频。
109 | /// Display the control bar with buttons to take pictures and record videos.
110 | Widget _captureControlRowWidget() {
111 | return Row(
112 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
113 | mainAxisSize: MainAxisSize.max,
114 | children: [
115 | IconButton(
116 | icon: const Icon(Icons.camera_alt),
117 | color: Colors.blue,
118 | onPressed: controller != null &&
119 | controller.value.isInitialized &&
120 | !controller.value.isRecordingVideo
121 | ? onTakePictureButtonPressed
122 | : null,
123 | ),
124 |
125 | IconButton(
126 | //cameraDescription
127 | icon: cameraChangeIcon,
128 | onPressed: (){onNewCameraSelected();},
129 | ),
130 | ],
131 | );
132 | }
133 |
134 |
135 | Icon cameraChangeIcon = Icon(Icons.camera_rear);
136 | String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
137 |
138 |
139 | void showInSnackBar(String message) {
140 | _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message)));
141 | }
142 |
143 |
144 | void onNewCameraSelected() async {
145 | if(controller != null && controller.value.isRecordingVideo){
146 | return;
147 | }
148 | if(controller!=null){
149 | for (CameraDescription cameraDescription in cameras) {
150 | if(controller.description == cameraDescription){
151 | continue;
152 | }else{
153 | if(cameraDescription.lensDirection == CameraLensDirection.back||cameraDescription.lensDirection == CameraLensDirection.front){
154 | if (controller != null) {
155 | await controller.dispose();
156 | }
157 | controller = CameraController(cameraDescription, ResolutionPreset.high);
158 | break;
159 | }
160 | }
161 | }
162 | }else{
163 | for (CameraDescription cameraDescription in cameras) {
164 | if(cameraDescription.lensDirection == CameraLensDirection.back){
165 | controller = CameraController(cameraDescription, ResolutionPreset.high);
166 | break;
167 | }
168 | }
169 | }
170 | // If the controller is updated then update the UI.
171 | controller.addListener(() {
172 | if (mounted) setState(() {});
173 | if (controller.value.hasError) {
174 | showInSnackBar('Camera error ${controller.value.errorDescription}');
175 | }
176 | });
177 |
178 | try {
179 | await controller.initialize();
180 | } on CameraException catch (e) {
181 | _showCameraException(e);
182 | }
183 |
184 | if (mounted) {
185 | setState(() {
186 | cameraChangeIcon = controller.description.lensDirection
187 | == CameraLensDirection.back ? Icon(Icons.camera_rear) : Icon(Icons.camera_front);
188 | });
189 | }
190 | }
191 |
192 | void onTakePictureButtonPressed() {
193 | takePicture().then((String filePath) {
194 | if (mounted) {
195 | setState(() {
196 | imagePath = filePath;
197 | });
198 | if (filePath != null) showInSnackBar('Picture saved to $filePath');
199 | }
200 | });
201 | }
202 |
203 |
204 | Future takePicture() async {
205 | if (!controller.value.isInitialized) {
206 | showInSnackBar('Error: select a camera first.');
207 | return null;
208 | }
209 | final Directory extDir = await getApplicationDocumentsDirectory();
210 | final String dirPath = '${extDir.path}/Pictures/flutter_test';
211 | await Directory(dirPath).create(recursive: true);
212 | final String filePath = '$dirPath/${timestamp()}.jpg';
213 |
214 | if (controller.value.isTakingPicture) {
215 | // A capture is already pending, do nothing.
216 | return null;
217 | }
218 |
219 | try {
220 | await controller.takePicture(filePath);
221 | } on CameraException catch (e) {
222 | _showCameraException(e);
223 | return null;
224 | }
225 | return filePath;
226 | }
227 |
228 | void _showCameraException(CameraException e) {
229 | logError(e.code, e.description);
230 | showInSnackBar('Error: ${e.code}\n${e.description}');
231 | }
232 | }
233 |
234 |
--------------------------------------------------------------------------------
/lib/ui/thirdpage/examples/Examples.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutterapp/ui/thirdpage/examples/CameraTest.dart';
3 | import 'package:flutterapp/ui/thirdpage/examples/ImagePicker.dart';
4 |
5 | class Examples extends StatelessWidget{
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return new Scaffold(
10 | appBar: new AppBar(
11 | title: new Text("Examples"),
12 | ),
13 | body: new Container(
14 | margin: EdgeInsets.all(10),
15 | child: new Wrap(
16 | spacing: 10,
17 | children: [
18 | new GestureDetector(
19 | child: new Chip(label: new Text("Camera")),
20 | onTap: (){
21 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
22 | return new CameraExampleHome();
23 | }));
24 | },
25 | ),
26 |
27 | new GestureDetector(
28 | child: new Chip(label: new Text("ImagePicker")),
29 | onTap: (){
30 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
31 | return new ImagePickerApp();
32 | }));
33 | },
34 | ),
35 | ],
36 | ),
37 | ),
38 | );
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/lib/ui/thirdpage/examples/ImagePicker.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:image_picker/image_picker.dart';
6 | import 'package:video_player/video_player.dart';
7 |
8 | class ImagePickerApp extends StatefulWidget {
9 | ImagePickerApp({Key key, this.title}) : super(key: key);
10 |
11 | final String title;
12 |
13 | @override
14 | _MyHomePageState createState() => _MyHomePageState();
15 | }
16 |
17 | class _MyHomePageState extends State {
18 | Future _imageFile;
19 | bool isVideo = false;
20 | VideoPlayerController _controller;
21 | VoidCallback listener;
22 |
23 | void _onImageButtonPressed(ImageSource source) {
24 | setState(() {
25 | if (_controller != null) {
26 | _controller.setVolume(0.0);
27 | _controller.removeListener(listener);
28 | }
29 | if (isVideo) {
30 | ImagePicker.pickVideo(source: source).then((File file) {
31 | if (file != null && mounted) {
32 | setState(() {
33 | _controller = VideoPlayerController.file(file)
34 | ..addListener(listener)
35 | ..setVolume(1.0)
36 | ..initialize()
37 | ..setLooping(true)
38 | ..play();
39 | });
40 | }
41 | });
42 | } else {
43 | _imageFile = ImagePicker.pickImage(source: source);
44 | }
45 | });
46 | }
47 |
48 | @override
49 | void deactivate() {
50 | if (_controller != null) {
51 | _controller.setVolume(0.0);
52 | _controller.removeListener(listener);
53 | }
54 | super.deactivate();
55 | }
56 |
57 | @override
58 | void dispose() {
59 | if (_controller != null) {
60 | _controller.dispose();
61 | }
62 | super.dispose();
63 | }
64 |
65 | @override
66 | void initState() {
67 | super.initState();
68 | listener = () {
69 | setState(() {});
70 | };
71 | }
72 |
73 | Widget _previewVideo(VideoPlayerController controller) {
74 | if (controller == null) {
75 | return const Text(
76 | 'You have not yet picked a video',
77 | textAlign: TextAlign.center,
78 | );
79 | } else if (controller.value.initialized) {
80 | return Padding(
81 | padding: const EdgeInsets.all(10.0),
82 | child: AspectRatioVideo(controller),
83 | );
84 | } else {
85 | return const Text(
86 | 'Error Loading Video',
87 | textAlign: TextAlign.center,
88 | );
89 | }
90 | }
91 |
92 | Widget _previewImage() {
93 | return FutureBuilder(
94 | future: _imageFile,
95 | builder: (BuildContext context, AsyncSnapshot snapshot) {
96 | if (snapshot.connectionState == ConnectionState.done &&
97 | snapshot.data != null) {
98 | return Image.file(snapshot.data);
99 | } else if (snapshot.error != null) {
100 | return const Text(
101 | 'Error picking image.',
102 | textAlign: TextAlign.center,
103 | );
104 | } else {
105 | return const Text(
106 | 'You have not yet picked an image.',
107 | textAlign: TextAlign.center,
108 | );
109 | }
110 | });
111 | }
112 |
113 | @override
114 | Widget build(BuildContext context) {
115 | return Scaffold(
116 | appBar: AppBar(
117 | title: Text("ImagePicker"),
118 | ),
119 | body: Center(
120 | child: isVideo ? _previewVideo(_controller) : _previewImage(),
121 | ),
122 | floatingActionButton: Column(
123 | mainAxisAlignment: MainAxisAlignment.end,
124 | children: [
125 | FloatingActionButton(
126 | onPressed: () {
127 | isVideo = false;
128 | _onImageButtonPressed(ImageSource.gallery);
129 | },
130 | heroTag: 'image0',
131 | tooltip: 'Pick Image from gallery',
132 | child: const Icon(Icons.photo_library),
133 | ),
134 | Padding(
135 | padding: const EdgeInsets.only(top: 16.0),
136 | child: FloatingActionButton(
137 | onPressed: () {
138 | isVideo = false;
139 | _onImageButtonPressed(ImageSource.camera);
140 | },
141 | heroTag: 'image1',
142 | tooltip: 'Take a Photo',
143 | child: const Icon(Icons.camera_alt),
144 | ),
145 | ),
146 | Padding(
147 | padding: const EdgeInsets.only(top: 16.0),
148 | child: FloatingActionButton(
149 | backgroundColor: Colors.red,
150 | onPressed: () {
151 | isVideo = true;
152 | _onImageButtonPressed(ImageSource.gallery);
153 | },
154 | heroTag: 'video0',
155 | tooltip: 'Pick Video from gallery',
156 | child: const Icon(Icons.video_library),
157 | ),
158 | ),
159 | Padding(
160 | padding: const EdgeInsets.only(top: 16.0),
161 | child: FloatingActionButton(
162 | backgroundColor: Colors.red,
163 | onPressed: () {
164 | isVideo = true;
165 | _onImageButtonPressed(ImageSource.camera);
166 | },
167 | heroTag: 'video1',
168 | tooltip: 'Take a Video',
169 | child: const Icon(Icons.videocam),
170 | ),
171 | ),
172 | ],
173 | ),
174 | );
175 | }
176 | }
177 |
178 | class AspectRatioVideo extends StatefulWidget {
179 | AspectRatioVideo(this.controller);
180 |
181 | final VideoPlayerController controller;
182 |
183 | @override
184 | AspectRatioVideoState createState() => AspectRatioVideoState();
185 | }
186 |
187 | class AspectRatioVideoState extends State {
188 | VideoPlayerController get controller => widget.controller;
189 | bool initialized = false;
190 |
191 | VoidCallback listener;
192 |
193 | @override
194 | void initState() {
195 | super.initState();
196 | listener = () {
197 | if (!mounted) {
198 | return;
199 | }
200 | if (initialized != controller.value.initialized) {
201 | initialized = controller.value.initialized;
202 | setState(() {});
203 | }
204 | };
205 | controller.addListener(listener);
206 | }
207 |
208 | @override
209 | Widget build(BuildContext context) {
210 | if (initialized) {
211 | return Center(
212 | child: AspectRatio(
213 | aspectRatio: controller.value?.aspectRatio,
214 | child: VideoPlayer(controller),
215 | ),
216 | );
217 | } else {
218 | return Container();
219 | }
220 | }
221 | }
222 |
223 |
224 |
--------------------------------------------------------------------------------
/lib/ui/thirdpage/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | typedef OnPageChange(int index);
5 |
6 | class HomePage extends StatefulWidget {
7 | @override
8 | _HomePageState createState() => _HomePageState();
9 | }
10 |
11 |
12 | class _HomePageState extends State {
13 | var _currentIndex = 0;
14 | PageController _pageController;
15 | final List images = [
16 | 'images/chaonan1.jpeg',
17 | 'images/chaonan2.jpg',
18 | 'images/chaonan3.jpeg',
19 | ];
20 |
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | num screenWidth = MediaQuery.of(context).size.width;
25 | return Scaffold(
26 | appBar: AppBar(
27 | title: Text('mts主页'),
28 | iconTheme: IconThemeData(color: Colors.blueAccent),
29 | ),
30 | body: SizedBox(
31 | height: screenWidth * 0.8 / 4 * 3,
32 | child: PageView.builder(
33 | controller: _pageController,
34 | itemCount: images.length,
35 | onPageChanged: (index) {
36 | setState(() {
37 | _currentIndex = index;
38 | });
39 | },
40 | itemBuilder: (BuildContext context, int index) {
41 | return PageChild(
42 | index: index,
43 | imgPath: images[index],
44 | onPageChange: (int index){
45 | setState(() {
46 | _currentIndex = index;
47 | });
48 | },
49 | imgLength: images.length,
50 | pageController: _pageController,
51 | );
52 | }),
53 | ));
54 | }
55 |
56 | @override
57 | void initState() {
58 | super.initState();
59 | _pageController =
60 | PageController(initialPage: images.length % 2, viewportFraction: 0.8);
61 | }
62 | }
63 |
64 | class PageChild extends StatefulWidget{
65 |
66 | final int index;
67 | final String imgPath;
68 | final OnPageChange onPageChange;
69 | final PageController pageController;
70 | final int imgLength;
71 |
72 | PageChild({
73 | @required this.index,
74 | @required this.imgPath,
75 | @required this.onPageChange,
76 | @required this.pageController,
77 | @required this.imgLength,
78 | });
79 |
80 | @override
81 | State createState() {
82 | return PageChildState();
83 | }
84 | }
85 |
86 | class PageChildState extends State{
87 | @override
88 | Widget build(BuildContext context) {
89 | return InkWell(
90 | onTap: () {
91 | print(widget.index);
92 | widget.pageController.animateToPage(widget.index % widget.imgLength,
93 | duration: Duration(milliseconds: 500),
94 | curve: Curves.fastOutSlowIn);
95 | },
96 | child: Padding(
97 | padding: const EdgeInsets.all(10.0),
98 | child: ClipRRect(
99 | borderRadius: BorderRadius.circular(16.0),
100 | child: Image.asset(
101 | widget.imgPath,
102 | fit: BoxFit.cover,
103 | ),
104 | ),
105 | ),
106 | );
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/lib/ui/thirdpage/shakeView.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class ShakeView extends StatefulWidget{
6 | @override
7 | State createState() {
8 | return new ShakeViewState();
9 | }
10 | }
11 |
12 | class ShakeViewState extends State with SingleTickerProviderStateMixin{
13 |
14 | Animation animation;
15 | AnimationController animationController;
16 | double rotateAngle=0.0;
17 | Random _random=new Random();
18 | double doubleAngle ;
19 | var listInfo =[-0.05,0.03,0.04,-0.02,0.05,-0.04,0.02,0.05,-0.03,0.04,0.03,-0.06,0.02,-0.05,0.03,0.04,-0.02,0.05,-0.04,0.02,0.05,-0.03];
20 | var listAngles =[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0];
21 | int count = 0;
22 | bool isTiming = false;
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | animationController = new AnimationController(duration: const Duration(milliseconds: 300), vsync: this,animationBehavior: AnimationBehavior.preserve);
28 |
29 | animation = new Tween(begin: 0.0, end: 2.0).animate(animationController)
30 | ..addListener(() {
31 | double animationValue = animation.value;
32 | setState(() {
33 | for(int i =0 ;i< listInfo.length;i++){
34 | doubleAngle = listInfo[i] *2;
35 | if(animationValue<=0.5){
36 | listAngles[i] = animationValue * doubleAngle;
37 | }else if(animationValue<=1.0){
38 | listAngles[i] = (1-animationValue) * doubleAngle;
39 | }else if(animationValue<=1.5){
40 | listAngles[i] = -(animationValue-1.0) * doubleAngle;
41 | }else{
42 | listAngles[i] = -(2.0-animationValue) * doubleAngle;
43 | }
44 | }
45 | });
46 | if(animationValue==2.0){
47 | changeData();
48 | }
49 | });
50 | }
51 |
52 | void changeData()async{
53 | print("changeData");
54 | if(count%3 == 0){
55 | int d;
56 | double c;
57 | for(int i =0 ;i< listInfo.length;i++){
58 | d = _random.nextInt(10);
59 | if(d>5){
60 | c = listInfo[i] = listInfo[i]+0.01;
61 | }else{
62 | c = listInfo[i] = listInfo[i]-0.01;
63 | }
64 |
65 | if(c<0.02 && c >=0){
66 | listInfo[i] = 0.03;
67 | }else if(c>-0.02 && c <=0){
68 | listInfo[i] = -0.03;
69 | }else if(c<-0.07){
70 | listInfo[i] = -0.06;
71 | }else if(c>0.07){
72 | listInfo[i] = 0.06;
73 | }
74 | }
75 | }
76 | count++;
77 | }
78 |
79 |
80 |
81 |
82 | void startTiming() async{
83 | while(isTiming) {
84 | await Future.delayed(Duration(milliseconds: 300 * 3));
85 | if(isTiming){
86 | changeData();
87 | }
88 | }
89 | }
90 |
91 |
92 | void _onLongPress(){
93 | if(animationController.isAnimating){
94 | return;
95 | }
96 | isTiming=true;
97 | startTiming();
98 | animationController.repeat();
99 | }
100 |
101 | @override
102 | Widget build(BuildContext context) {
103 | return new Scaffold(
104 | appBar: new AppBar(
105 | title: new Text("ShakeView"),
106 | actions: [
107 | new GestureDetector(
108 | onTap: (){
109 | if(animationController.isAnimating){
110 | isTiming = false;
111 | animationController.stop();
112 | }
113 | setState(() {
114 | listAngles =[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0];
115 | });
116 | },
117 | child: new Container(
118 | padding: EdgeInsets.all(5),
119 | child: new Text("完成"),
120 | ),
121 | ),
122 | ],
123 | ),
124 | body: new Column(
125 | children: [
126 | getRows(0),
127 | getRows(4),
128 | getRows(8),
129 | getRows(12),
130 | getRows(16),
131 | getRowsLess(),
132 | ],
133 | ),
134 | );
135 | }
136 |
137 |
138 | Widget getRows(int miniPosition){
139 | return new Row(
140 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
141 | children: [
142 | getItem(miniPosition),
143 | getItem(miniPosition+1),
144 | getItem(miniPosition+2),
145 | getItem(miniPosition+3),
146 | ],
147 | );
148 | }
149 |
150 | Widget getRowsLess(){
151 | return new Row(
152 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
153 | children: [
154 | getItem(20),
155 | getItem(21),
156 | new Container(
157 | margin: EdgeInsets.all(10),
158 | height: 60,
159 | width: 60,
160 | ),
161 | new Container(
162 | margin: EdgeInsets.all(10),
163 | height: 60,
164 | width: 60,
165 | ),
166 | ],
167 | );
168 | }
169 |
170 |
171 | Widget getItem(int position){
172 | return new GestureDetector(
173 | onLongPress: (){
174 | _onLongPress();
175 | },
176 | child:Transform.rotate(
177 | origin: new Offset(0, 0),
178 | angle: listAngles[position],
179 | child: new Container(
180 | margin: EdgeInsets.all(10),
181 | height: 60,
182 | width: 60,
183 | decoration: BoxDecoration(
184 | color: Colors.black45,
185 | borderRadius: BorderRadius.all(Radius.circular(5)),
186 | ),
187 | ),
188 | ),
189 | );
190 | }
191 |
192 | @override
193 | void dispose() {
194 | isTiming = false;
195 | animationController.dispose();
196 | super.dispose();
197 | }
198 | }
--------------------------------------------------------------------------------
/lib/ui/thirdpage/testFile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class TestFile extends StatefulWidget{
4 | @override
5 | State createState() {
6 | return new TestFileState();
7 | }
8 | }
9 |
10 | class TestFileState extends State{
11 |
12 | var texts = ["123","234","345","456","789","101","102","103","104","end"];
13 | String txt = "START";
14 | bool isStart = true;
15 | int count = 0;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return new Scaffold(
20 | appBar: new AppBar(
21 | title: new Text("TestFile"),
22 | ),
23 | body: new Column(
24 | children: [
25 | new GestureDetector(
26 | child: new Text(txt),
27 | onTap: () async {
28 | while(isStart){
29 | setState(() {
30 | txt = texts[count];
31 | });
32 | count++;
33 | if(count>=texts.length){
34 | count=0;
35 | }
36 | await Future.delayed(new Duration(milliseconds: 1000));
37 | }
38 | },
39 | ),
40 | new MyStateLessWidget(),
41 | ],
42 | ),
43 | );
44 | }
45 |
46 | @override
47 | void dispose() {
48 | isStart=false;
49 | super.dispose();
50 | }
51 | }
52 |
53 |
54 | class MyStateLessWidget extends StatefulWidget{
55 | @override
56 | State createState() {
57 | return MyStateLessWidgetState();
58 | }
59 |
60 | }
61 |
62 |
63 | class MyStateLessWidgetState extends State{
64 | @override
65 | Widget build(BuildContext context) {
66 | print("MyStateLessWidget is invokell");
67 | return new Text("I am a StatelessWidget",style: new TextStyle(fontSize: 18,color: Colors.red),);
68 | }
69 | }
--------------------------------------------------------------------------------
/lib/ui/thirdpage/thirdPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:flutter/rendering.dart';
4 | import 'package:flutterapp/bin/appinfobin.dart';
5 | import 'package:flutterapp/ui/thirdpage/shakeView.dart';
6 | import 'package:flutterapp/ui/thirdpage/testFile.dart';
7 | import 'package:flutterapp/ui/thirdpage/examples/Examples.dart';
8 | import 'package:flutterapp/ui/thirdpage/cutScreen.dart';
9 | import 'package:flutterapp/ui/thirdpage/home_page.dart';
10 |
11 | class ThirdPage extends StatefulWidget{
12 |
13 | @override
14 | State createState() {
15 | return new ThirdPageState();
16 | }
17 |
18 | }
19 |
20 | class ThirdPageState extends State{
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return new Scaffold(
25 | appBar: new AppBar(
26 | title: new Text("CustomWidght",style: new TextStyle(fontSize: 18.0),),
27 | actions: [
28 | new IconButton(
29 | icon: new Icon(Icons.search),
30 | onPressed: null,
31 | iconSize: 29.0,
32 | disabledColor: Colors.white,)
33 | ]
34 | ,),
35 | body: new Container(
36 | // ignore: conflicting_dart_import
37 | child: new ListViewWidgets(),
38 | )
39 | );
40 | }
41 | }
42 |
43 |
44 | class ListViewWidgets extends StatefulWidget{
45 |
46 | final constantList = [
47 | new AppInfoBin("CutScreen", "2019-01-11 10:25", "屏幕截图",false),
48 | new AppInfoBin("Examples", "2019-04-17 11:16", "各种示例",false),
49 | new AppInfoBin("ShakeView", "2019-04-18 10:06", "可以摇晃的View",false),
50 | new AppInfoBin("TEST", "2019-04-20 15:17", "测试类",false),
51 | new AppInfoBin("Gallery", "2019-05-27 11:03", "画廊",false),
52 | ];
53 |
54 | @override
55 | State createState() {
56 | return new ListState();
57 | }
58 |
59 | }
60 |
61 | class ListState extends State{
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | return new ListView.builder(
66 | itemCount: widget.constantList.length,
67 | itemBuilder: (BuildContext context,int index){
68 | return new GestureDetector(
69 | onTapDown: (TapDownDetails details){
70 | setState(() {
71 | widget.constantList[index].isTapDown=true;
72 | });
73 | },
74 | onTapCancel: (){
75 | setState(() {
76 | widget.constantList[index].isTapDown=false;
77 | });
78 | },
79 | onTapUp:(TapUpDetails details){
80 | setState(() {
81 | widget.constantList[index].isTapDown=false;
82 | });
83 | if(index==0){
84 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
85 | return new CutScreen();
86 | }));
87 | }else if(index==1){
88 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
89 | return new Examples();
90 | }));
91 | }else if(index==2){
92 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
93 | return new ShakeView();
94 | }));
95 | }else if(index==3){
96 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
97 | return new TestFile();
98 | }));
99 | }else if(index==4){
100 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
101 | return new HomePage();
102 | }));
103 | }
104 | },
105 | child:new Card(
106 | color: widget.constantList[index].isTapDown?Color(0xFFF4CB28):null,
107 | child: new Container(
108 | padding: new EdgeInsets.all(10.0),
109 | child: new ListTile(
110 | subtitle: new Container(
111 | child: new Column(
112 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
113 | children: [
114 | new Row(
115 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
116 | children: [
117 | new Text(widget.constantList[index].title,style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 16.0,color: Colors.black),)
118 | ],
119 | ),
120 | new Row(
121 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
122 | children: [
123 | new Row(
124 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
125 | crossAxisAlignment: CrossAxisAlignment.center,
126 | children: [
127 | new Text("时间",style: new TextStyle(fontSize: 13.0)),
128 | new Text(widget.constantList[index].times,style: new TextStyle(fontSize: 13.0)),
129 | ],
130 | )
131 | ],
132 | ),
133 | new Row(
134 | children: [
135 | new Expanded(
136 | child:new Container(
137 | padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
138 | child: new Text(widget.constantList[index].content,maxLines: 1,overflow: TextOverflow.ellipsis,),
139 | ),
140 | )
141 | ],
142 | )
143 | ],
144 | ),
145 | ),
146 | trailing: new Icon(Icons.keyboard_arrow_right,color: Colors.grey,),
147 | ),
148 | ),
149 | )
150 | );
151 | },);
152 | }
153 | }
--------------------------------------------------------------------------------
/pictures/Dragable gridview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFlutter/PullToRefresh/fe11bedb786528987b14af7f82db61fb7985582a/pictures/Dragable gridview.png
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "2.1.0"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "1.0.4"
18 | camera:
19 | dependency: "direct main"
20 | description:
21 | name: camera
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "0.4.3+2"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.1.2"
32 | collection:
33 | dependency: transitive
34 | description:
35 | name: collection
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.14.11"
39 | cupertino_icons:
40 | dependency: "direct main"
41 | description:
42 | name: cupertino_icons
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "0.1.2"
46 | dragablegridview_flutter:
47 | dependency: "direct main"
48 | description:
49 | name: dragablegridview_flutter
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "0.0.4"
53 | english_words:
54 | dependency: "direct main"
55 | description:
56 | name: english_words
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "3.1.5"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_localizations:
66 | dependency: "direct main"
67 | description: flutter
68 | source: sdk
69 | version: "0.0.0"
70 | flutter_test:
71 | dependency: "direct dev"
72 | description: flutter
73 | source: sdk
74 | version: "0.0.0"
75 | image_picker:
76 | dependency: "direct main"
77 | description:
78 | name: image_picker
79 | url: "https://pub.flutter-io.cn"
80 | source: hosted
81 | version: "0.5.4+3"
82 | intl:
83 | dependency: transitive
84 | description:
85 | name: intl
86 | url: "https://pub.flutter-io.cn"
87 | source: hosted
88 | version: "0.15.8"
89 | marquee_flutter:
90 | dependency: "direct main"
91 | description:
92 | name: marquee_flutter
93 | url: "https://pub.flutter-io.cn"
94 | source: hosted
95 | version: "0.0.2"
96 | matcher:
97 | dependency: transitive
98 | description:
99 | name: matcher
100 | url: "https://pub.flutter-io.cn"
101 | source: hosted
102 | version: "0.12.5"
103 | meta:
104 | dependency: transitive
105 | description:
106 | name: meta
107 | url: "https://pub.flutter-io.cn"
108 | source: hosted
109 | version: "1.1.6"
110 | path:
111 | dependency: transitive
112 | description:
113 | name: path
114 | url: "https://pub.flutter-io.cn"
115 | source: hosted
116 | version: "1.6.2"
117 | path_provider:
118 | dependency: "direct main"
119 | description:
120 | name: path_provider
121 | url: "https://pub.flutter-io.cn"
122 | source: hosted
123 | version: "0.5.0+1"
124 | pedantic:
125 | dependency: transitive
126 | description:
127 | name: pedantic
128 | url: "https://pub.flutter-io.cn"
129 | source: hosted
130 | version: "1.5.0"
131 | pulltorefresh_flutter:
132 | dependency: "direct main"
133 | description:
134 | name: pulltorefresh_flutter
135 | url: "https://pub.flutter-io.cn"
136 | source: hosted
137 | version: "0.1.9"
138 | quiver:
139 | dependency: transitive
140 | description:
141 | name: quiver
142 | url: "https://pub.flutter-io.cn"
143 | source: hosted
144 | version: "2.0.2"
145 | sky_engine:
146 | dependency: transitive
147 | description: flutter
148 | source: sdk
149 | version: "0.0.99"
150 | source_span:
151 | dependency: transitive
152 | description:
153 | name: source_span
154 | url: "https://pub.flutter-io.cn"
155 | source: hosted
156 | version: "1.5.5"
157 | stack_trace:
158 | dependency: transitive
159 | description:
160 | name: stack_trace
161 | url: "https://pub.flutter-io.cn"
162 | source: hosted
163 | version: "1.9.3"
164 | stream_channel:
165 | dependency: transitive
166 | description:
167 | name: stream_channel
168 | url: "https://pub.flutter-io.cn"
169 | source: hosted
170 | version: "2.0.0"
171 | string_scanner:
172 | dependency: transitive
173 | description:
174 | name: string_scanner
175 | url: "https://pub.flutter-io.cn"
176 | source: hosted
177 | version: "1.0.4"
178 | term_glyph:
179 | dependency: transitive
180 | description:
181 | name: term_glyph
182 | url: "https://pub.flutter-io.cn"
183 | source: hosted
184 | version: "1.1.0"
185 | test_api:
186 | dependency: transitive
187 | description:
188 | name: test_api
189 | url: "https://pub.flutter-io.cn"
190 | source: hosted
191 | version: "0.2.4"
192 | transparent_image:
193 | dependency: "direct main"
194 | description:
195 | name: transparent_image
196 | url: "https://pub.flutter-io.cn"
197 | source: hosted
198 | version: "0.1.0"
199 | typed_data:
200 | dependency: transitive
201 | description:
202 | name: typed_data
203 | url: "https://pub.flutter-io.cn"
204 | source: hosted
205 | version: "1.1.6"
206 | vector_math:
207 | dependency: transitive
208 | description:
209 | name: vector_math
210 | url: "https://pub.flutter-io.cn"
211 | source: hosted
212 | version: "2.0.8"
213 | video_player:
214 | dependency: "direct main"
215 | description:
216 | name: video_player
217 | url: "https://pub.flutter-io.cn"
218 | source: hosted
219 | version: "0.5.4"
220 | sdks:
221 | dart: ">=2.2.0 <3.0.0"
222 | flutter: ">=1.2.0 <2.0.0"
223 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutterapp
2 | description: A new Flutter application.
3 |
4 | dependencies:
5 | flutter:
6 | sdk: flutter
7 | flutter_localizations:
8 | sdk: flutter
9 |
10 | # The following adds the Cupertino Icons font to your application.
11 | # Use with the CupertinoIcons class for iOS style icons.
12 | cupertino_icons: ^0.1.2
13 | english_words: ^3.1.0
14 | transparent_image: ^0.1.0
15 | pulltorefresh_flutter: ^0.1.7
16 | marquee_flutter: ^0.0.2
17 | dragablegridview_flutter: ^0.0.3
18 | camera: ^0.4.3+2
19 | path_provider: ^0.5.0
20 | video_player: ^0.5.2
21 | image_picker: ^0.5.3+1
22 | #cached_network_image: ^0.4.1
23 |
24 | dev_dependencies:
25 | flutter_test:
26 | sdk: flutter
27 |
28 |
29 | # For information on the generic Dart part of this file, see the
30 | # following page: https://www.dartlang.org/tools/pub/pubspec
31 |
32 | # The following section is specific to Flutter.
33 | flutter:
34 |
35 | # The following line ensures that the Material Icons font is
36 | # included with your application, so that you can use the icons in
37 | # the material Icons class.
38 | uses-material-design: true
39 |
40 | # To add assets to your application, add an assets section, like this:
41 | assets:
42 | - images/chaonan1.jpeg
43 | - images/chaonan2.jpg
44 | - images/chaonan3.jpeg
45 | - images/chaonan4.jpeg
46 | - images/refresh.png
47 | - images/icon_arrow.png
48 | - images/icon_cry.png
49 | - images/tianmao.jpg
50 | - images/close.png
51 |
52 | # An image asset can refer to one or more resolution-specific "variants", see
53 | # https://flutter.io/assets-and-images/#resolution-aware.
54 |
55 | # For details regarding adding assets from package dependencies, see
56 | # https://flutter.io/assets-and-images/#from-packages
57 |
58 | # To add custom fonts to your application, add a fonts section here,
59 | # in this "flutter" section. Each entry in this list should have a
60 | # "family" key with the font family name, and a "fonts" key with a
61 | # list giving the asset and other descriptors for the font. For
62 | # example:
63 | # fonts:
64 | # - family: Schyler
65 | # fonts:
66 | # - asset: fonts/Schyler-Regular.ttf
67 | # - asset: fonts/Schyler-Italic.ttf
68 | # style: italic
69 | # - family: Trajan Pro
70 | # fonts:
71 | # - asset: fonts/TrajanPro.ttf
72 | # - asset: fonts/TrajanPro_Bold.ttf
73 | # weight: 700
74 | #
75 | # For details regarding fonts from package dependencies,
76 | # see https://flutter.io/custom-fonts/#from-packages
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | void main() {
2 |
3 | double a=0.12;
4 | print(a.isNaN);
5 | }
6 |
--------------------------------------------------------------------------------