diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml new file mode 100644 index 0000000..4aeda98 --- /dev/null +++ b/.idea/libraries/Dart_Packages.xml @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml new file mode 100644 index 0000000..9747079 --- /dev/null +++ b/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml new file mode 100644 index 0000000..f3ad465 --- /dev/null +++ b/.idea/libraries/Flutter_Plugins.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 8be0b49..3b7f9c5 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,88 @@ # flutter_study +**Flutter免费教学,自己出的良心免费教程,希望你三天可以自己脱离一切视频搞定flutter。**
+1.包括Dart基础
+2.包括Flutter基础
+3.用Flutter手写b站App涉及到封装网络请求,全局状态管理,自定义,滑动监听,3d支持和使用,购物车等各种需要的。
+[视频地址](http://space.bilibili.com/265453330?share_medium=android&share_source=qq&bbid=XY0878202754C3B308DBDBBE7B67B7B5A694E&ts=1557479970694).
+![image](https://github.com/luhenchang/IMAGE/blob/master/img_bizhan/WeChat3d4501c5ea03165d48b5270ac7944463.png?raw=true)!
+![image](https://github.com/luhenchang/IMAGE/blob/master/img_bizhan/appbizhan.jpg?raw=true)!
+ **Flutter学习三天,一天写完Demo:一有时间后面会持续更新的哦** -**2018年,8.1下班没事干,花了一小时实现了比较炫酷的界面** +**2019年,3月份写了一周多了,也就下班写,这个项目按小时计费:效果图如下。如果有需求带同学可以加我qq一起探讨** + +![image](https://github.com/luhenchang/IMAGE/blob/master/home11.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home12.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home13.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home14.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home15.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home16.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home17.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home18.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/home19.png?raw=true)! + +**2018年,10.10日最近接了一个项目可以提供相关页面,遇到困难的萌新可以一起谈论交流。** + +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/program_ios0.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/program_ios1.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/program_ios2.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/program_ios3.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/program_ios4.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/program_ios5.gif?raw=true)! + + + + +**2018年,10.08日对于滑动控制监听滑动高度和结束开始等。来进行效果的实现。** + +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios_scrollLisenner.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios_scrollnotify.gif?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/xuankuss.gif?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/xuankuss1.gif?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/xuankuss2.gif?raw=true)! -**2018年,7月31没事干写了个比较好看的登录注册: -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av1.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av2.png?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av3.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av4.png?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av5.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av6.png?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av7.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av8.png?raw=true)! -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av9.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av11.png?raw=true)! +**2018年,9.03最近没时间玩flutter了,今天在mac安装好了环境,并在iphone运行了** -**2018年,7月25看着qq模仿抖音视频** -今天没事干下午,搞了搞视频方面的希望可以帮助到大家。 -在目录-view--->Video_demo文件里面。 +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios1.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios2.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios3.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios4.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios5.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/ios6.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android10.gif?raw=true)! -如下图: -![image](https://github.com/luhenchang/flutter_study/blob/master/images/douying3.gif?raw=true)! +**2018年,9.03下面是部分android模拟器上面的gif图片 -![image](https://github.com/luhenchang/flutter_study/blob/master/images/av7.png?raw=true)!![image](https://github.com/luhenchang/flutter_study/blob/master/images/av9.png?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android1.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android2.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android3.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/andoid4.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android5.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android6.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android7.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android8.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android9.gif?raw=true)! +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/android10.gif?raw=true)! +**2018年,8.20好久没写Flutter了,写了个各大点餐平台的类表滑动炫酷界面,希望对你有所帮助** +项目下面->lib->test->MeiTuanShopping.dart + +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/shoopper.gif?raw=true)! + +**2018年,8.5没事干,花了一小时实现了大家比较期待的吸附效果和视频播放,希望对你有所帮助** +项目下面->lib->test->SlivScrollListViewTabLayout.dart + +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/eseeyss1112.gif?raw=true)!![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/%E9%A6%96%E9%A1%B5%E4%B8%80%E9%83%A8%E5%88%86.gif?raw=true)! + +**2018年,8.1下班没事干,花了一小时实现了比较炫酷的界面** + +**2018年,7月31没事干写了个比较好看的登录注册:** + + +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/%E7%99%BB%E5%BD%951.gif?raw=true)! **2018年,7月24看着qq模仿了抽屉部件** -如图 -![image](https://github.com/luhenchang/flutter_study/blob/master/images/%5D_2NQ%7D11H2ULR22S52LN0@R.png?raw=true) +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/qq%E8%85%BE%E8%AE%AF.gif?raw=true)![image](https://github.com/luhenchang/flutter_study/blob/master/images/%5D_2NQ%7D11H2ULR22S52LN0@R.png?raw=true) 在lib->flutter_view->view->MyDrawer里面,这里包裹如何将一个背景图片颜色通过设置color来调节亮度,以及圆型图边框,和stack的使用等,我相信看看我的代码就可以了。希望有所帮助。 @@ -41,9 +95,7 @@ 2.CustomPaint提供了可以进行在Canvas画布上面进行绘制我们的显示。 3.GestureDetector提供我们在屏幕上的手势拖缀来给变和刷新我们3d图像。 -![image](https://github.com/luhenchang/flutter_study/blob/master/images/3D.png?raw=true) - -![image](https://github.com/luhenchang/flutter_study/blob/master/images/flutter_chart.gif?raw=true) +![image](https://github.com/luhenchang/IMAGE/blob/master/app/src/main/res/drawable/3D.png?raw=true)![image](https://github.com/luhenchang/flutter_study/blob/master/images/flutter_chart.gif?raw=true) [博客地址:](https://blog.csdn.net/m0_37667770/article/details/81042916). @@ -53,27 +105,28 @@ ![image](https://github.com/luhenchang/flutter_study/blob/master/images/bbc.jpg?raw=true) [博客地址](https://blog.csdn.net/m0_37667770/article/details/80993571). 如何实现各种弧度或者自定义效果的窗体布局: -class ArcClipper extends CustomClipper { - @override - Path getClip(Size size) { - var path = Path(); - path.lineTo(0.0, size.height); - var firstControlPoint = Offset(size.width / 4, size.height - 30); - var firstPoint = Offset(size.width / 2, size.height - 30); - path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, + + class ArcClipper extends CustomClipper { + @override + Path getClip(Size size) { + var path = Path(); + path.lineTo(0.0, size.height); + var firstControlPoint = Offset(size.width / 4, size.height - 30); + var firstPoint = Offset(size.width / 2, size.height - 30); + path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, firstPoint.dx, firstPoint.dy); - var secondControlPoint = + var secondControlPoint = Offset(size.width - (size.width / 4), size.height - 30); - var secondPoint = Offset(size.width, size.height); - path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy, + var secondPoint = Offset(size.width, size.height); + path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy, secondPoint.dx, secondPoint.dy); - path.lineTo(size.width, 0.0); - path.close(); + path.lineTo(size.width, 0.0); + path.close(); - return path; - } + return path; + } **2018年,7月9日晚上更新** 下班没事干,游戏就搁一边,写了一个多小时的界面,模仿美团,搞定了这两个界面,后面地图,定位这些会慢慢更新的。这个界面提供了如何用Dart创建类,然后给集合添加数据,并动态赋值给列表控件等。目录在flutter_intent->modle(这里面是类)->SecondPager和SecondPagerFragment是第二界面。ShopingListPager是二界面滑动的每个列表页面。 @@ -95,25 +148,6 @@ class ArcClipper extends CustomClipper { ![image](https://github.com/luhenchang/flutter_study/blob/master/images/genxin1.png?raw=true) -**一,Flutter:** - -Flutter和“ReactNative”,我想很多作为android和前端或者ios开发人员都听说过,我们可以JavaScript和React获得一致的开发体验,但是RN在实际平台上还需要适配和桥接差异性,这个过程其实很痛苦的。而Flutter则是依靠Flutter Engine虚拟机在iOS和Android上运行,开发人员可以通过Flutter框架和API在内部进行交互。Flutter Engine使用C/C++编写,具有低延迟输入和高帧速率的特点。除此之外,Flutter提供了自己的小部件集合,可以直接在OS平台提供的画布上描绘控件。可以说实际意义上的一个语言实现多平台运行。 -二,学习三天的我写的Demon并且开始开发项目: - -我也是上一周听到几个android群里讨论Flutter的,各种天花乱坠,有些说嵌套很麻烦,我想是不是和前端有点像,有些说提供的框架和第三方不完善,或者说迟早gg,当然了,有一个大佬说看了一个月,也分享了他的博客,我第一时间是看了他的Demon,我当时想上手一个月是不是很难了。接下来我就直接奔着官方网站去进行阅读,当然了搭建环境这个环境我没算到学习时间之内,一步步按照官方API阅读并去写代码。我阅读过程中发现,哇这借鉴了web前端的很多特点,小部件盒子模型,以及熟悉的书写格式bootmstrup这让我很快的用一个早上搞定了小部件部分。而且写了很多的案例。我发现布局流程图如果理解了很好写布局,不存在嵌套太导致思路模糊或者找不见问题。我希望直接入手光放API。最快最直接,最明白。 -写了一天半Demon如下图所示: -当我注重看Flutter框架设计时候,官方网站提供了bottomNavigationBar但是发现设置路由进入子页面之后它没法消失,百度了很多至今没有一个人写个原始的Flutter应用程序框架。这里只好自己写了,当然了思路都一样,用下面点击事件去记录index然后替换显示三个对应的页面就可以了。对于生命传值路由我希望大家可以去看官方网站比较需要理解,而且很好理解的,动态和静态如果设置路由,如何传值这些都是分分钟的事情。Flutter官网连接. -这里写图片描述 -![image](https://github.com/luhenchang/flutter_study/blob/master/images/Flutter_1234556.gif?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/1.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/3.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/4.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/5.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/6.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/7.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/8.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/9.png?raw=true) -![image](https://github.com/luhenchang/flutter_study/blob/master/images/10.png?raw=true) 项目会一直完善的,我github上传失败了,改天上传希望可以帮助你学习。有什么意见和建议的多多留言,我会尽自己最大的可能提供帮助。 哇哦这个会更新么? ## Getting Started diff --git a/android/.idea/codeStyles/Project.xml b/android/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/android/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml new file mode 100644 index 0000000..35a49a8 --- /dev/null +++ b/android/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml new file mode 100644 index 0000000..7bfef59 --- /dev/null +++ b/android/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml new file mode 100644 index 0000000..b7deb7b --- /dev/null +++ b/android/.idea/modules.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/android/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/vcs.xml b/android/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/android/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index e118604..b2f4cd8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -10,7 +10,6 @@ def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } - apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" @@ -34,6 +33,7 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + multiDexEnabled true } buildTypes { @@ -43,15 +43,30 @@ android { signingConfig signingConfigs.debug } } + sourceSets { + main { + jniLibs.srcDirs = ['libs'] /**在libs文件夹下找so文件*/ + } + } } flutter { source '../..' } - +repositories { + mavenCentral() + flatDir { + dirs 'libs' /**在libs文件夹下找aar文件*/ + } +} dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support.constraint:constraint-layout:1.1.2' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + + } + +apply plugin: 'kotlin-android-extensions' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 28244b7..359ae97 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,39 +1,53 @@ + - - - - - + FlutterApplication and put your custom class here. + --> + android:supportsRtl="true" + tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + defined in @style/LaunchTheme). + --> + - - + + + - + + \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/flutterstudy/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutterstudy/MainActivity.kt index 46dcc96..456d43d 100644 --- a/android/app/src/main/kotlin/com/example/flutterstudy/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/flutterstudy/MainActivity.kt @@ -1,13 +1,32 @@ package com.example.flutterstudy import android.os.Bundle - import io.flutter.app.FlutterActivity import io.flutter.plugins.GeneratedPluginRegistrant +import android.content.Intent +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel + + +class MainActivity() : FlutterActivity() { + private val CHANNEL = "demo.plugin" + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // 自定义插件 + MethodChannel(flutterView, CHANNEL).setMethodCallHandler(object : MethodCallHandler { + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + // if (call.method == "interaction") { +// val intent = Intent(this@MainActivity, MainActivityOragnal::class.java) +// intent.putExtra("putstr",call.method); +// this@MainActivity.startActivity(intent) +// result.success("success") + /* } else { + result.notImplemented() + }*/ + } + }) + GeneratedPluginRegistrant.registerWith(this) -class MainActivity(): FlutterActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - GeneratedPluginRegistrant.registerWith(this) - } + } } diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 304732f..5a7cc77 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -4,9 +4,11 @@ - + android:src="@mipmap/lunch_backgroudgg" /> + diff --git a/android/app/src/main/res/layout/activity_main_oragnal.xml b/android/app/src/main/res/layout/activity_main_oragnal.xml new file mode 100644 index 0000000..190bee9 --- /dev/null +++ b/android/app/src/main/res/layout/activity_main_oragnal.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-xhdpi/lonvn9.jpg b/android/app/src/main/res/mipmap-xhdpi/lonvn9.jpg new file mode 100644 index 0000000..0f3b451 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/lonvn9.jpg differ diff --git a/android/app/src/main/res/mipmap-xhdpi/lunch_backgroudgg.png b/android/app/src/main/res/mipmap-xhdpi/lunch_backgroudgg.png new file mode 100644 index 0000000..41ccdae Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/lunch_backgroudgg.png differ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..7abc06d --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1 @@ + diff --git a/android/build.gradle b/android/build.gradle index ed41a28..006a03f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,13 @@ buildscript { - ext.kotlin_version = '1.1.51' + ext.kotlin_version = '1.2.60' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.3' + //添加 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -15,6 +16,7 @@ allprojects { repositories { google() jcenter() + maven {url "https://jitpack.io" } } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index aa901e1..3cb45cb 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Sat Aug 04 00:17:11 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/gradlew b/android/gradlew old mode 100644 new mode 100755 diff --git a/flutter_study.iml b/flutter_study.iml index e5c8371..950e920 100644 --- a/flutter_study.iml +++ b/flutter_study.iml @@ -1,18 +1,75 @@ + + + + + + - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/images/10.png b/images/10.png deleted file mode 100644 index 5827074..0000000 Binary files a/images/10.png and /dev/null differ diff --git a/images/11.png b/images/11.png deleted file mode 100644 index 9aa8332..0000000 Binary files a/images/11.png and /dev/null differ diff --git a/images/2121.png b/images/2121.png deleted file mode 100644 index 09d25e4..0000000 Binary files a/images/2121.png and /dev/null differ diff --git a/images/2323.png b/images/2323.png deleted file mode 100644 index 388d89c..0000000 Binary files a/images/2323.png and /dev/null differ diff --git a/images/3D.png b/images/3D.png deleted file mode 100644 index be9f867..0000000 Binary files a/images/3D.png and /dev/null differ diff --git a/images/5.png b/images/5.png deleted file mode 100644 index 1120c21..0000000 Binary files a/images/5.png and /dev/null differ diff --git a/images/5d.png b/images/5d.png deleted file mode 100644 index b4a01fd..0000000 Binary files a/images/5d.png and /dev/null differ diff --git a/images/6.png b/images/6.png deleted file mode 100644 index d9c4cc1..0000000 Binary files a/images/6.png and /dev/null differ diff --git a/images/7.png b/images/7.png deleted file mode 100644 index b376da1..0000000 Binary files a/images/7.png and /dev/null differ diff --git a/images/8.png b/images/8.png deleted file mode 100644 index 9296fcf..0000000 Binary files a/images/8.png and /dev/null differ diff --git a/images/9.png b/images/9.png deleted file mode 100644 index 412f84c..0000000 Binary files a/images/9.png and /dev/null differ diff --git a/images/Flutter_1234556.gif b/images/Flutter_1234556.gif deleted file mode 100644 index 80edd1b..0000000 Binary files a/images/Flutter_1234556.gif and /dev/null differ diff --git a/images/]_2NQ}11H2ULR22S52LN0@R.png b/images/]_2NQ}11H2ULR22S52LN0@R.png deleted file mode 100644 index b72cc94..0000000 Binary files a/images/]_2NQ}11H2ULR22S52LN0@R.png and /dev/null differ diff --git a/images/aaabbbccc.gif b/images/aaabbbccc.gif deleted file mode 100644 index c196fb5..0000000 Binary files a/images/aaabbbccc.gif and /dev/null differ diff --git a/images/app_background.png b/images/app_background.png deleted file mode 100644 index a5d0a2b..0000000 Binary files a/images/app_background.png and /dev/null differ diff --git a/images/av1.png b/images/av1.png deleted file mode 100644 index 1bc578f..0000000 Binary files a/images/av1.png and /dev/null differ diff --git a/images/av11.png b/images/av11.png deleted file mode 100644 index d4e6c8b..0000000 Binary files a/images/av11.png and /dev/null differ diff --git a/images/av2.png b/images/av2.png deleted file mode 100644 index 6b5acdc..0000000 Binary files a/images/av2.png and /dev/null differ diff --git a/images/av3.png b/images/av3.png deleted file mode 100644 index 52e7b09..0000000 Binary files a/images/av3.png and /dev/null differ diff --git a/images/av4.png b/images/av4.png deleted file mode 100644 index ca22ddf..0000000 Binary files a/images/av4.png and /dev/null differ diff --git a/images/av5.png b/images/av5.png deleted file mode 100644 index c838dbb..0000000 Binary files a/images/av5.png and /dev/null differ diff --git a/images/av6.png b/images/av6.png deleted file mode 100644 index 2b7ceca..0000000 Binary files a/images/av6.png and /dev/null differ diff --git a/images/av7.png b/images/av7.png deleted file mode 100644 index e0cbb47..0000000 Binary files a/images/av7.png and /dev/null differ diff --git a/images/av8.png b/images/av8.png deleted file mode 100644 index 67c7658..0000000 Binary files a/images/av8.png and /dev/null differ diff --git a/images/av9.png b/images/av9.png deleted file mode 100644 index 62f1923..0000000 Binary files a/images/av9.png and /dev/null differ diff --git a/images/bba.jpg b/images/bba.jpg deleted file mode 100644 index f452968..0000000 Binary files a/images/bba.jpg and /dev/null differ diff --git a/images/bbb.jpg b/images/bbb.jpg deleted file mode 100644 index 3ef8481..0000000 Binary files a/images/bbb.jpg and /dev/null differ diff --git a/images/bbc.jpg b/images/bbc.jpg deleted file mode 100644 index 45fd57e..0000000 Binary files a/images/bbc.jpg and /dev/null differ diff --git a/images/douying1.png b/images/douying1.png deleted file mode 100644 index 92b831a..0000000 Binary files a/images/douying1.png and /dev/null differ diff --git a/images/douying2.png b/images/douying2.png deleted file mode 100644 index c49bde7..0000000 Binary files a/images/douying2.png and /dev/null differ diff --git a/images/douying3.gif b/images/douying3.gif deleted file mode 100644 index 2c62195..0000000 Binary files a/images/douying3.gif and /dev/null differ diff --git a/images/flutter_chart.gif b/images/flutter_chart.gif deleted file mode 100644 index 3750440..0000000 Binary files a/images/flutter_chart.gif and /dev/null differ diff --git a/images/genxin1.png b/images/genxin1.png deleted file mode 100644 index 13a3a2d..0000000 Binary files a/images/genxin1.png and /dev/null differ diff --git a/images/genxin2.png b/images/genxin2.png deleted file mode 100644 index 83adc0a..0000000 Binary files a/images/genxin2.png and /dev/null differ diff --git a/images/gxing2018710.jpg b/images/gxing2018710.jpg deleted file mode 100644 index 3f7a5f1..0000000 Binary files a/images/gxing2018710.jpg and /dev/null differ diff --git a/images/xuankuss.gif b/images/xuankuss.gif deleted file mode 100644 index 28e2a00..0000000 Binary files a/images/xuankuss.gif and /dev/null differ diff --git a/images/xuankuss1.gif b/images/xuankuss1.gif deleted file mode 100644 index 84a354d..0000000 Binary files a/images/xuankuss1.gif and /dev/null differ diff --git a/images/xuankuss2.gif b/images/xuankuss2.gif deleted file mode 100644 index 419c512..0000000 Binary files a/images/xuankuss2.gif and /dev/null differ diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..e8efba1 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..399e934 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4465189..0c98417 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -20,6 +19,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + C944EA630AE3A455644105B5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D10779469D7C3E157C585FD /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -40,15 +40,17 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; + 18BA1AF95986B041886AA83D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 3D10779469D7C3E157C585FD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 9770EC2943A0469C38E8EC64 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -63,16 +65,25 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + C944EA630AE3A455644105B5 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 568E398DFF8B132F9D78E69D /* Pods */ = { + isa = PBXGroup; + children = ( + 9770EC2943A0469C38E8EC64 /* Pods-Runner.debug.xcconfig */, + 18BA1AF95986B041886AA83D /* Pods-Runner.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEBA1CF902C7004384FC /* Flutter.framework */, @@ -89,6 +100,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 568E398DFF8B132F9D78E69D /* Pods */, + E5804C36ED1D218DFF87E8E1 /* Frameworks */, ); sourceTree = ""; }; @@ -123,6 +136,14 @@ name = "Supporting Files"; sourceTree = ""; }; + E5804C36ED1D218DFF87E8E1 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3D10779469D7C3E157C585FD /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -130,12 +151,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 86A32EA77E71499D99D6E2B8 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + A5F63E85344683801F46185C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -189,7 +212,6 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -211,6 +233,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; + 86A32EA77E71499D99D6E2B8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -225,6 +269,44 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A5F63E85344683801F46185C /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", + "${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework", + "${BUILT_PRODUCTS_DIR}/device_info/device_info.framework", + "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework", + "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", + "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", + "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", + "${BUILT_PRODUCTS_DIR}/video_player/video_player.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/Readerme b/lib/Readerme index c021c98..d73c39e 100644 --- a/lib/Readerme +++ b/lib/Readerme @@ -1,206 +1,4 @@ -new Center( - child: new Object_3D( - size: const Size(400.0, 400.0), - path: "assets/NVpose1.obj", - asset: - true), //assets/file.obj为我们的本地obj文件,需要到pubspec.yaml中进行配置 -), - showDemoDialog( - context: context, - child: new SimpleDialog( - contentPadding: EdgeInsets.all(0.0), - titlePadding: new EdgeInsets.only( - left: 0.0, bottom: 0.0), - title: new Container( - padding: - new EdgeInsets.all(10.0), - color: Color(0xFF00E5FF), - child: new Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - '去购物', - style: TextStyle( - color: - Colors.redAccent), - ), - IconButton( - icon: Icon(Icons.clear), - onPressed: () { - Navigator.of(context).pop(); - }, - color: Colors.white, - ), - ], - )), - children: [ - new Container( - height: MediaQuery - .of(context) - .size - .height / - 10 * - 6, - width: MediaQuery - .of(context) - .size - .width / - 10 * - 7, - child: Image.asset( - 'images/haha.png', - fit: BoxFit.cover, - )), - ], - ), - ); - - - - - - -刷新 - - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; - -class Example1 extends StatefulWidget { - @override - _Example1State createState() => new _Example1State(); -} - -class _Example1State extends State { -// RefreshMode refreshing = RefreshMode.idle; -// LoadMode loading = LoadMode.idle; - RefreshController _refreshController; - List data = []; - void _getDatas() { - for (int i = 0; i < 14; i++) { - data.add(new Card( - margin: - new EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), - child: new Center( - child: new Text('Data $i'), - ), - )); - } - } - - void enterRefresh() { - _refreshController.requestRefresh(true); - } - - void _onOffsetCallback(bool isUp, double offset) { - // if you want change some widgets state ,you should rewrite the callback - } - - @override - void initState() { - // TODO: implement initState - _getDatas(); - _refreshController = new RefreshController(); - super.initState(); - } - - Widget _headerCreate(BuildContext context, int mode) { - return new ClassicIndicator( - mode: mode, - refreshingText: "", - idleIcon: new Container(), - idleText: "Load more...", - ); - } - -// Widget _footerCreate(BuildContext context,int mode){ -// return new ClassicIndicator(mode: mode); -// } - - @override - Widget build(BuildContext context) { - return new Container( - child: new SmartRefresher( - enablePullDown: true, - enablePullUp: true, - controller: _refreshController, - onRefresh: (up) { - if (up) - new Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { - data.add(new Card( - margin: new EdgeInsets.only( - left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), - child: new Center( - child: new Text('Data '), - ), - )); - - _refreshController.scrollTo(_refreshController.scrollController.offset+100.0); - _refreshController.sendBack(true, RefreshStatus.idle); - setState(() {}); -// refresher.sendStatus(RefreshStatus.completed); - }); - else { - new Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { - data.add(new Card( - margin: new EdgeInsets.only( - left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), - child: new Center( - child: new Text('Data '), - ), - )); - setState(() {}); - _refreshController.sendBack(false, RefreshStatus.idle); - }); - } - }, - onOffsetChange: _onOffsetCallback, - child: new ListView.builder( - reverse: true, - itemExtent: 100.0, - itemCount: data.length, - itemBuilder: (context, index) => new Item(), - ))); - } -} - -class Item extends StatefulWidget { - @override - _ItemState createState() => new _ItemState(); -} - -class _ItemState extends State { - @override - Widget build(BuildContext context) { - return new Card( - margin: - new EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), - child: new Center( - child: new Text('Data'), - ), - ); - } - - @override - void dispose() { - // TODO: implement dispose - print("销毁"); - super.dispose(); - } -} - - - -new Stack( - children: [new MyContainUtils(""),Card(child:new GestureDetector(),)], - - ) +ast_qr_reader_view: ^0.1.2二维码: diff --git a/lib/RegistPager.dart b/lib/RegistPager.dart index 441d0f3..4c52532 100644 --- a/lib/RegistPager.dart +++ b/lib/RegistPager.dart @@ -5,6 +5,7 @@ import 'package:flutter_app/flutter_WidghtUtils/MyContainUtils.dart'; import 'package:flutter_app/http_utils/HttpUtils.dart'; import 'package:flutter_app/showmain.dart'; import 'package:flutter_app/test/SqlUtils.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:image_picker/image_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -39,17 +40,19 @@ class RegistPagerState extends State String rescode = data["rescode"]; print(rescode); if (rescode == '999999') { - showDialog( - context: context, - builder: (ctx) => new AlertDialog( - content: new Text('注册不成功'), - )); + Fluttertoast.showToast( + msg: "注册失败", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIos:1, + ); } else if (rescode == '000000') { - showDialog( - context: context, - builder: (ctx) => new AlertDialog( - content: new Text('注册成功,去登陆'), - )); + Fluttertoast.showToast( + msg: "注册正确", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIos:1, + ); } }); } catch (e) { diff --git a/lib/Widght_3D.dart b/lib/Widght_3D.dart index e3527d2..0903d7d 100644 --- a/lib/Widght_3D.dart +++ b/lib/Widght_3D.dart @@ -241,7 +241,7 @@ class _ObjectPainter extends CustomPainter { } double _degreeToRadian(double degree) { - return degree * (Math.PI / 180.0); + return degree * (Math.pi / 180.0); } List _drawFace(List verticesToDraw, List face) { diff --git a/lib/flutter_intent/view/AppBar2.dart b/lib/flutter_intent/view/AppBar2.dart index 392c4e1..3ab97c7 100644 --- a/lib/flutter_intent/view/AppBar2.dart +++ b/lib/flutter_intent/view/AppBar2.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_app/flutter_widget/view/MainSearchPager.dart'; +import 'package:flutter_app/flutter_widget/view/pop_menu.dart'; class Choice { - const Choice({this.title, this.icon,this.color}); + const Choice({this.title, this.icon, this.color}); final String title; final IconData icon; @@ -12,11 +14,12 @@ class AppBar2 extends StatelessWidget { final int index1; List choices = const [ - const Choice(title: '小汽车', icon: Icons.directions_car,color: Colors.teal), - const Choice(title: '自行车', icon: Icons.directions_bike,color: Colors.teal), - const Choice(title: '嘿嘿车', icon: Icons.directions_boat,color: Colors.teal), - const Choice(title: '公交车', icon: Icons.directions_bus,color: Colors.blue), + const Choice(title: '小汽车', icon: Icons.directions_car, color: Colors.teal), + const Choice(title: '自行车', icon: Icons.directions_bike, color: Colors.teal), + const Choice(title: '嘿嘿车', icon: Icons.directions_boat, color: Colors.teal), + const Choice(title: '公交车', icon: Icons.directions_bus, color: Colors.blue), ]; + AppBar2({Key key, this.index1}) : super(key: key); @override @@ -90,31 +93,44 @@ class AppBar2 extends StatelessWidget { child: Center( child: Form( autovalidate: false, - child: TextFormField( - style: new TextStyle( - color: Colors.teal), - textAlign: TextAlign.start, - decoration: - InputDecoration.collapsed( - fillColor: Colors.white, - /*prefixIcon: Container( + child: GestureDetector( + onTap:(){ + /* Navigator.of(context).push(new PageRouteBuilder( + opaque: false, + pageBuilder: (BuildContext context, _, __) { + return new RowAndColumWidget(index: 0,); + }, + )); //页*/ + //页 + }, + child: TextFormField( + enabled:false, + autofocus:false, + style: new TextStyle( + color: Colors.teal), + textAlign: TextAlign.start, + decoration: InputDecoration + .collapsed( + fillColor: Colors.white, + /*prefixIcon: Container( child: Icon(Icons.search), padding: new EdgeInsets.only(left: 5.0), ),*/ - hintText: '杨米宇黄焖鸡米饭...', - hintStyle: TextStyle( - fontSize: 13.0, - color: Colors.black45), - //contentPadding: new EdgeInsets.only(left: 1.0,top: 16.0), - //isDense: false, - filled: false, - /*border: new OutlineInputBorder( - + hintText: '杨米宇黄焖鸡米饭...', + hintStyle: TextStyle( + fontSize: 13.0, + color: + Colors.black45), + //contentPadding: new EdgeInsets.only(left: 1.0,top: 16.0), + //isDense: false, + filled: false, + /*border: new OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(44.0)), borderSide: BorderSide( color: Colors.white, style: BorderStyle.none), ),*/ + ), ), ), ), @@ -125,28 +141,39 @@ class AppBar2 extends StatelessWidget { ), ], )), - new PopupMenuButton( + new PopupMenuButtons( itemBuilder: (BuildContext context) { return choices .skip(2) .take(4) .map((Choice choice) { - return new PopupMenuItem( + return new PopupMenuItems( value: choice, child: new Container( - decoration: BoxDecoration(color: Colors.white), + padding: new EdgeInsets.all(0.0), + decoration: BoxDecoration( + color: Colors.lightBlueAccent), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - new Text(choice.title,style: TextStyle(color:choice.color ),), - new Icon(choice.icon,color:choice.color,) + new Text( + choice.title, + style: TextStyle( + color: choice.color), + ), + new Icon( + choice.icon, + color: choice.color, + ) ], ), ), ); }).toList(); }, + marginTopHeigt: 51.0, + marginLeftWidth: 2.0, ), ], ), @@ -241,7 +268,6 @@ class AppBar2 extends StatelessWidget { //isDense: false, filled: false, /*border: new OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(44.0)), borderSide: BorderSide( color: Colors.white, diff --git a/lib/flutter_widget/modle/HotSearchBean.dart b/lib/flutter_widget/modle/HotSearchBean.dart new file mode 100644 index 0000000..f405260 --- /dev/null +++ b/lib/flutter_widget/modle/HotSearchBean.dart @@ -0,0 +1,8 @@ +import 'package:flutter/cupertino.dart'; + +class HotSearchBean{ + var icon_Icon; + var title_string; + var color_icon; + HotSearchBean(this.icon_Icon,this.title_string,this.color_icon); +} \ No newline at end of file diff --git a/lib/flutter_widget/view/MainSearchPager.dart b/lib/flutter_widget/view/MainSearchPager.dart new file mode 100644 index 0000000..eaf63f1 --- /dev/null +++ b/lib/flutter_widget/view/MainSearchPager.dart @@ -0,0 +1,372 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/flutter_widget/modle/HotSearchBean.dart'; + +void main() { + runApp(new MaterialApp( + title: '搜索', + theme: new ThemeData( + primaryColor: Colors.redAccent, + primaryTextTheme: TextTheme(title: TextStyle(color: Colors.teal)), + primaryIconTheme: IconThemeData(color: Colors.lightBlue)), + home: new MainSearchPager(), + )); +} + +class MainSearchPager extends StatefulWidget { + @override + _MainSearchPagerState createState() => new _MainSearchPagerState(); +} + +class _MainSearchPagerState extends State { + List mHotData; + List mHostory; + + @override + void initState() { + mHotData = new List(); + mHotData.add( + new HotSearchBean( + Icons.print, + '秦桧一品西安小吃', + Color(0xFFF57F17), + ), + ); + mHotData.add( + new HotSearchBean( + Icons.print, + '杨明宇黄焖鸡米饭', + Color(0xFFF57F17), + ), + ); + mHotData.add( + new HotSearchBean( + Icons.print, + '霸王接头小吃', + Color(0xFFF57F17), + ), + ); + mHotData.add( + new HotSearchBean( + Icons.print, + '酱骨头', + Color(0xFFF57F17), + ), + ); + mHotData.add( + new HotSearchBean( + Icons.print, + '如家漂泊 -云酒店入住', + Color(0xFFF57F17), + ), + ); + + //历史记录 + mHostory = new List(); + mHostory.add( + new HotSearchBean( + Icons.print, + '秦桧一品西安小吃', + Color(0xFF757575), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '杨明宇黄焖鸡米饭', + Color(0xFF757575), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '霸王接', + Color(0xFF757575), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '酱骨头', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '如家漂泊 -云酒店入住', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '秦桧一品西安小吃', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '杨明宇黄焖鸡米饭', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '霸王接头小吃', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '消炎药', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '如家漂泊 -云酒店入住', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '秦桧一品西安小吃', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '杨明宇黄焖鸡米饭', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '霸王接头小吃', + Color(0xFFF57F17), + ), + ); + mHostory.add( + new HotSearchBean( + Icons.print, + '杨明宇黄焖鸡米饭', + Color(0xFFF57F17), + ), + ); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: AppBar( + titleSpacing: 0.0, + textTheme: TextTheme(title: TextStyle(color: Colors.redAccent)), + automaticallyImplyLeading: false, + title: new Container( + child: new Card( + child: Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Container( + child: IconButton( + onPressed: (){ + Navigator.of(context).pop(); + }, + icon:Icon( Icons.keyboard_arrow_left), + color: Colors.grey, + ), + margin: new EdgeInsets.only( + left: 0.0, top: 8.0, bottom: 12.0), + ), + new Container( + child: Container( + child: Text( + '天津', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.black), + ), + margin: new EdgeInsets.only(left: 1.0), + ), + ), + new Container( + margin: new EdgeInsets.only(left: 5.0, right:5.0), + padding: new EdgeInsets.only(left: 10.0), + height: 30.0, + width: 220.0, + decoration: BoxDecoration( + color: Color(0xFFEEEEEE), + borderRadius: + BorderRadius.all(const Radius.circular(58.0))), + child: Row( + children: [ + Icon( + Icons.search, + size: 20.0, + color: Colors.black54, + ), + Container( + child: Container( + padding: new EdgeInsets.only(left: 10.0), + child: Center( + child: Form( + autovalidate: true, + child: TextFormField( + style: new TextStyle(color: Colors.teal), + textAlign: TextAlign.start, + decoration: InputDecoration.collapsed( + fillColor: Colors.white, + hintText: '杨米宇黄焖鸡米饭...', + hintStyle: TextStyle( + fontSize: 13.0, + color: Colors.black45), + filled: false, + ), + ), + ), + ), + ), + width: 130.0, + height: 35.0, + ), + ], + + ), + ), + IconButton(padding:new EdgeInsets.all(1.0),icon: Icon(Icons.search), onPressed: () {}) + ], + ), + width: 600.0, + height: 55.0, + ), + margin: new EdgeInsets.only(top: 1.0, bottom: 2.0), + ), + )), + body: ListView( + children: [ + Container( + margin: new EdgeInsets.only(left: 12.0, top: 20.0), + child: new Text( + '热门搜索', + style: TextStyle( + fontSize: 13.0, + color: Colors.grey, + fontWeight: FontWeight.bold), + ), + ), + Container( + margin: new EdgeInsets.only(left: 6.0), + child: Wrap( + children: List.generate( + mHotData.length, + (i) => Container( + height: 32.0, + margin: new EdgeInsets.all(5.9), + padding: new EdgeInsets.only( + left: 10.0, right: 5.0, top: 8.0, bottom: 11.0), + decoration: BoxDecoration( + color: Color(0xFFE0E0E0), + borderRadius: BorderRadius.all( + Radius.circular(4.9), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + i < 2 + ? Icon( + mHotData[i].icon_Icon, + size: 15.0, + color: mHotData[i].color_icon, + ) + : Container(), + new Text( + mHotData[i].title_string, + style: TextStyle( + fontSize: 14.0, + color: Colors.black, + ), + ) + ], + ), + ), + ), + ), + ), + Container( + margin: new EdgeInsets.only(left: 12.0, top: 5.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Text( + '历史记录', + style: TextStyle( + fontSize: 15.0, + color: Colors.grey, + fontWeight: FontWeight.bold), + ), + Padding( + padding: new EdgeInsets.only(right: 8.0), + child: Icon( + Icons.delete_forever, + size: 22.0, + color: Colors.grey, + ), + ), + ], + ), + ), + Container( + margin: new EdgeInsets.only(left: 6.0), + child: Wrap( + children: List.generate( + mHostory.length, + (i) => Container( + height: 32.0, + margin: new EdgeInsets.all(4.9), + padding: new EdgeInsets.only( + left: 10.0, right: 5.0, top: 8.0, bottom: 11.0), + decoration: BoxDecoration( + color: Color(0xFFE0E0E0), + borderRadius: BorderRadius.all( + Radius.circular(5.9), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + i < 2 + ? Icon( + mHostory[i].icon_Icon, + size: 15.0, + color: mHostory[i].color_icon, + ) + : Container(), + new Text( + mHostory[i].title_string, + style: TextStyle( + fontSize: 14.0, + color: Colors.black, + ), + ) + ], + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/flutter_widget/view/XuankuPager.dart b/lib/flutter_widget/view/XuankuPager.dart index d2df16a..dd543f9 100644 --- a/lib/flutter_widget/view/XuankuPager.dart +++ b/lib/flutter_widget/view/XuankuPager.dart @@ -3,16 +3,7 @@ import 'package:flutter_app/flutter_widget/view/XunkuPager2.dart'; void main() => runApp(new MaterialApp( debugShowCheckedModeBanner: false, - theme: new ThemeData(primaryColor:Color(0xFF00838F)),/*decoration: BoxDecoration( - gradient: new LinearGradient( - begin:Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [ - Color(0xFF00838F), - Color(0xFF4DD0E1) - ], - ), - ),*/ + theme: new ThemeData(primaryColor:Color(0xFF00838F)), home: new XuankuPage(), )); @@ -56,7 +47,8 @@ class _XuankuPageState extends State elevation: 0.0, leading: new IconButton( onPressed: () { - animationController.fling(velocity: isPanelVisible ? -1.0 : 1.0); + //这里给滑动的速度来设置一个阻尼速度的大小。-1.0如果动画完成了或者在开始前往运行过程时候阻尼速度为-1.0向下运行,当动画消失或者返回是速度为1.0正方形向上, + animationController.fling(velocity: isPanelVisible ?-1.0 :1.0); }, icon: new AnimatedIcon( icon: AnimatedIcons.close_menu, @@ -64,9 +56,12 @@ class _XuankuPageState extends State ), ), ), - body: new XuankuPage2( - controller: animationController, + body:new XuankuPage2( + controllers: animationController, ), ); } } +/*new XuankuPage2( + controllers: animationController, + ),*/ \ No newline at end of file diff --git a/lib/flutter_widget/view/XunkuPager2.dart b/lib/flutter_widget/view/XunkuPager2.dart index c1033ca..22ea7ec 100644 --- a/lib/flutter_widget/view/XunkuPager2.dart +++ b/lib/flutter_widget/view/XunkuPager2.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; class XuankuPage2 extends StatefulWidget { - final AnimationController controller; + final AnimationController controllers; - XuankuPage2({this.controller}); + XuankuPage2({this.controllers}); @override State createState() { @@ -19,13 +19,13 @@ class _XuankuPageState2 extends State final height = constai.biggest.height; final backPaneHeight = height - header_height; final fromPanelHeight = -header_height; - + //TODO 3.0相对矩形直接的动画: return new RelativeRectTween( begin: - new RelativeRect.fromLTRB(0.0, backPaneHeight, 0.0, fromPanelHeight), + new RelativeRect.fromLTRB(0.0, backPaneHeight, 0.0, fromPanelHeight),//TODO 当然了这里的设置是从上面开始向下,可以设置从左向右,从右边想左面。等 end: new RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0), ).animate( - new CurvedAnimation(parent: widget.controller, curve: Curves.linear), + new CurvedAnimation(parent: widget.controllers, curve: Curves.bounceInOut),//TODO 这里可以设置动画延伸效果。例如回弹等。 ); } @@ -34,6 +34,7 @@ class _XuankuPageState2 extends State return new Container( child: new Stack( children: [ + //TODO 1.0 背景 '炫酷Flutter' new Container( color: theme.primaryColor, child: new Center( @@ -46,8 +47,8 @@ class _XuankuPageState2 extends State begin:Alignment.bottomCenter, end: Alignment.topCenter, colors: [ - Color(0xFFFFCDD2), - Color(0xFF00838F) + Color(0xFF4DD0E1), + Colors.white ], ), ), @@ -58,6 +59,8 @@ class _XuankuPageState2 extends State ), ), ), + + //TODO 2.0 背景 上面的动画以及圆形图片 new PositionedTransition( rect: getPaneLanimation(constraints), child: Padding( diff --git a/lib/flutter_widget/view/pop_menu.dart b/lib/flutter_widget/view/pop_menu.dart new file mode 100644 index 0000000..50798eb --- /dev/null +++ b/lib/flutter_widget/view/pop_menu.dart @@ -0,0 +1,952 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_app/Widght_3D.dart'; +import 'package:flutter_app/flutter_intent/view/AppBar2.dart'; +import 'package:flutter_app/flutter_intent/view/SecondPager.dart'; +import 'package:flutter_app/flutter_person/PersonPager.dart'; +import 'package:flutter_app/flutter_system/SystemPage.dart'; +import 'package:flutter_app/flutter_widget/modle/HomePageBean.dart'; +import 'package:flutter_app/flutter_widget/view/DouyinPager.dart'; +import 'package:flutter_app/flutter_widget/view/MyDrawer.dart'; +import 'package:flutter_app/flutter_widget/view/MyWell_Screen.dart'; +import 'package:flutter_app/flutter_widget/view/NetWidget.dart'; +import 'package:flutter_app/flutter_widget/view/XuankuPager.dart'; +import 'package:flutter_app/test/SlivScrollListViewTabLayout.dart'; +import 'package:flutter_app/test/video_demo.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_app/flutter_intent/view/NetDataPager.dart'; +import 'package:flutter_app/flutter_intent/view/interactioPager.dart'; +import 'package:flutter_app/flutter_system/systemPager.dart'; +import 'package:flutter_app/flutter_widget/WidgetPager.dart'; +import 'package:flutter_app/flutter_widget/view/SmallWidget.dart'; +import 'package:flutter_app/flutter_widget/WidgetText.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:flutter_app/http_utils/HttpUtils.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import "package:pull_to_refresh/pull_to_refresh.dart"; + +// Examples can assume: +// enum Commands { heroAndScholar, hurricaneCame } +// dynamic _heroAndScholar; + +const Duration _kMenuDuration = const Duration(milliseconds: 300); +const double _kBaselineOffsetFromBottom = 20.0; +const double _kMenuCloseIntervalEnd = 2.0 / 3.0; +const double _kMenuHorizontalPadding = 16.0; +const double _kMenuItemHeight = 48.0; +const double _kMenuDividerHeight = 16.0; +const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; +const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; +const double _kMenuVerticalPadding = 8.0; +const double _kMenuWidthStep = 56.0; +const double _kMenuScreenPadding = 8.0; + +/// A base class for entries in a material design popup menu. +/// +/// The popup menu widget uses this interface to interact with the menu items. +/// To show a popup menu, use the [showMenu] function. To create a button that +/// shows a popup menu, consider using [PopupMenuButton]. +/// +/// The type `T` is the type of the value(s) the entry represents. All the +/// entries in a given menu must represent values with consistent types. +/// +/// A [PopupMenuEntry] may represent multiple values, for example a row with +/// several icons, or a single entry, for example a menu item with an icon (see +/// [PopupMenuItems]), or no value at all (for example, [PopupMenuDivider]). +/// +/// See also: +/// +/// * [PopupMenuItems], a popup menu entry for a single value. +/// * [PopupMenuDivider], a popup menu entry that is just a horizontal line. +/// * [CheckedPopupMenuItems], a popup menu item with a checkmark. +/// * [showMenu], a method to dynamically show a popup menu at a given location. +/// * [PopupMenuButton], an [IconButton] that automatically shows a menu when +/// it is tapped. +abstract class PopupMenuEntry extends StatefulWidget { + /// Abstract const constructor. This constructor enables subclasses to provide + /// const constructors so that they can be used in const expressions. + const PopupMenuEntry({ Key key }) : super(key: key); + + /// The amount of vertical space occupied by this entry. + /// + /// This value is used at the time the [showMenu] method is called, if the + /// `initialValue` argument is provided, to determine the position of this + /// entry when aligning the selected entry over the given `position`. It is + /// otherwise ignored. + double get height; + + /// Whether this entry represents a particular value. + /// + /// This method is used by [showMenu], when it is called, to align the entry + /// representing the `initialValue`, if any, to the given `position`, and then + /// later is called on each entry to determine if it should be highlighted (if + /// the method returns true, the entry will have its background color set to + /// the ambient [ThemeData.highlightColor]). If `initialValue` is null, then + /// this method is not called. + /// + /// If the [PopupMenuEntry] represents a single value, this should return true + /// if the argument matches that value. If it represents multiple values, it + /// should return true if the argument matches any of them. + bool represents(T value); +} + +/// A horizontal divider in a material design popup menu. +/// +/// This widget adapts the [Divider] for use in popup menus. +/// +/// See also: +/// +/// * [PopupMenuItems], for the kinds of items that this widget divides. +/// * [showMenu], a method to dynamically show a popup menu at a given location. +/// * [PopupMenuButton], an [IconButton] that automatically shows a menu when +/// it is tapped. +class PopupMenuDivider extends PopupMenuEntry { + /// Creates a horizontal divider for a popup menu. + /// + /// By default, the divider has a height of 16 logical pixels. + const PopupMenuDivider({ Key key, this.height = _kMenuDividerHeight }) : super(key: key); + + /// The height of the divider entry. + /// + /// Defaults to 16 pixels. + @override + final double height; + + @override + bool represents(dynamic value) => false; + + @override + _PopupMenuDividerState createState() => new _PopupMenuDividerState(); +} + +class _PopupMenuDividerState extends State { + @override + Widget build(BuildContext context) => new Divider(height: widget.height); +} + +/// An item in a material design popup menu. +/// +/// To show a popup menu, use the [showMenu] function. To create a button that +/// shows a popup menu, consider using [PopupMenuButton]. +/// +/// To show a checkmark next to a popup menu item, consider using +/// [CheckedPopupMenuItems]. +/// +/// Typically the [child] of a [PopupMenuItems] is a [Text] widget. More +/// elaborate menus with icons can use a [ListTile]. By default, a +/// [PopupMenuItems] is 48 pixels high. If you use a widget with a different +/// height, it must be specified in the [height] property. +/// +/// ## Sample code +/// +/// Here, a [Text] widget is used with a popup menu item. The `WhyFarther` type +/// is an enum, not shown here. +/// +/// ```dart +/// const PopupMenuItems( +/// value: WhyFarther.harder, +/// child: const Text('Working a lot harder'), +/// ) +/// ``` +/// +/// See the example at [PopupMenuButton] for how this example could be used in a +/// complete menu, and see the example at [CheckedPopupMenuItems] for one way to +/// keep the text of [PopupMenuItems]s that use [Text] widgets in their [child] +/// slot aligned with the text of [CheckedPopupMenuItems]s or of [PopupMenuItems] +/// that use a [ListTile] in their [child] slot. +/// +/// See also: +/// +/// * [PopupMenuDivider], which can be used to divide items from each other. +/// * [CheckedPopupMenuItems], a variant of [PopupMenuItems] with a checkmark. +/// * [showMenu], a method to dynamically show a popup menu at a given location. +/// * [PopupMenuButton], an [IconButton] that automatically shows a menu when +/// it is tapped. +class PopupMenuItems extends PopupMenuEntry { + /// Creates an item for a popup menu. + /// + /// By default, the item is [enabled]. + /// + /// The `height` and `enabled` arguments must not be null. + const PopupMenuItems({ + Key key, + this.value, + this.enabled = true, + this.height = _kMenuItemHeight, + @required this.child, + }) : assert(enabled != null), + assert(height != null), + super(key: key); + + /// The value that will be returned by [showMenu] if this entry is selected. + final T value; + + /// Whether the user is permitted to select this entry. + /// + /// Defaults to true. If this is false, then the item will not react to + /// touches. + final bool enabled; + + /// The height of the entry. + /// + /// Defaults to 48 pixels. + @override + final double height; + + /// The widget below this widget in the tree. + /// + /// Typically a single-line [ListTile] (for menus with icons) or a [Text]. An + /// appropriate [DefaultTextStyle] is put in scope for the child. In either + /// case, the text should be short enough that it won't wrap. + final Widget child; + + @override + bool represents(T value) => value == this.value; + + @override + PopupMenuItemsState> createState() => new PopupMenuItemsState>(); +} + +/// The [State] for [PopupMenuItems] subclasses. +/// +/// By default this implements the basic styling and layout of Material Design +/// popup menu items. +/// +/// The [buildChild] method can be overridden to adjust exactly what gets placed +/// in the menu. By default it returns [PopupMenuItems.child]. +/// +/// The [handleTap] method can be overridden to adjust exactly what happens when +/// the item is tapped. By default, it uses [Navigator.pop] to return the +/// [PopupMenuItems.value] from the menu route. +/// +/// This class takes two type arguments. The second, `W`, is the exact type of +/// the [Widget] that is using this [State]. It must be a subclass of +/// [PopupMenuItems]. The first, `T`, must match the type argument of that widget +/// class, and is the type of values returned from this menu. +class PopupMenuItemsState> extends State { + /// The menu item contents. + /// + /// Used by the [build] method. + /// + /// By default, this returns [PopupMenuItems.child]. Override this to put + /// something else in the menu entry. + @protected + Widget buildChild() => widget.child; + + /// The handler for when the user selects the menu item. + /// + /// Used by the [InkWell] inserted by the [build] method. + /// + /// By default, uses [Navigator.pop] to return the [PopupMenuItems.value] from + /// the menu route. + @protected + void handleTap() { + Navigator.pop(context, widget.value); + } + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + TextStyle style = theme.textTheme.subhead; + if (!widget.enabled) + style = style.copyWith(color: theme.disabledColor); + + Widget item = new AnimatedDefaultTextStyle( + style: style, + duration: kThemeChangeDuration, + child: new Baseline( + baseline: widget.height - _kBaselineOffsetFromBottom, + baselineType: style.textBaseline, + child: buildChild(), + ) + ); + if (!widget.enabled) { + final bool isDark = theme.brightness == Brightness.dark; + item = IconTheme.merge( + data: new IconThemeData(opacity: isDark ? 0.5 : 0.38), + child: item, + ); + } + + return new InkWell( + onTap: widget.enabled ? handleTap : null, + child: new Container( + height: widget.height, + padding: const EdgeInsets.symmetric(horizontal: _kMenuHorizontalPadding), + child: item, + ), + ); + } +} + +/// An item with a checkmark in a material design popup menu. +/// +/// To show a popup menu, use the [showMenu] function. To create a button that +/// shows a popup menu, consider using [PopupMenuButton]. +/// +/// A [CheckedPopupMenuItems] is 48 pixels high, which matches the default height +/// of a [PopupMenuItems]. The horizontal layout uses a [ListTile]; the checkmark +/// is an [Icons.done] icon, shown in the [ListTile.leading] position. +/// +/// ## Sample code +/// +/// Suppose a `Commands` enum exists that lists the possible commands from a +/// particular popup menu, including `Commands.heroAndScholar` and +/// `Commands.hurricaneCame`, and further suppose that there is a +/// `_heroAndScholar` member field which is a boolean. The example below shows a +/// menu with one menu item with a checkmark that can toggle the boolean, and +/// one menu item without a checkmark for selecting the second option. (It also +/// shows a divider placed between the two menu items.) +/// +/// ```dart +/// new PopupMenuButton( +/// onSelected: (Commands result) { +/// switch (result) { +/// case Commands.heroAndScholar: +/// setState(() { _heroAndScholar = !_heroAndScholar; }); +/// break; +/// case Commands.hurricaneCame: +/// // ...handle hurricane option +/// break; +/// // ...other items handled here +/// } +/// }, +/// itemBuilder: (BuildContext context) => >[ +/// new CheckedPopupMenuItems( +/// checked: _heroAndScholar, +/// value: Commands.heroAndScholar, +/// child: const Text('Hero and scholar'), +/// ), +/// const PopupMenuDivider(), +/// const PopupMenuItems( +/// value: Commands.hurricaneCame, +/// child: const ListTile(leading: const Icon(null), title: const Text('Bring hurricane')), +/// ), +/// // ...other items listed here +/// ], +/// ) +/// ``` +/// +/// In particular, observe how the second menu item uses a [ListTile] with a +/// blank [Icon] in the [ListTile.leading] position to get the same alignment as +/// the item with the checkmark. +/// +/// See also: +/// +/// * [PopupMenuItems], a popup menu entry for picking a command (as opposed to +/// toggling a value). +/// * [PopupMenuDivider], a popup menu entry that is just a horizontal line. +/// * [showMenu], a method to dynamically show a popup menu at a given location. +/// * [PopupMenuButton], an [IconButton] that automatically shows a menu when +/// it is tapped. +class CheckedPopupMenuItems extends PopupMenuItems { + /// Creates a popup menu item with a checkmark. + /// + /// By default, the menu item is [enabled] but unchecked. To mark the item as + /// checked, set [checked] to true. + /// + /// The `checked` and `enabled` arguments must not be null. + const CheckedPopupMenuItems({ + Key key, + T value, + this.checked = false, + bool enabled = true, + Widget child, + }) : assert(checked != null), + super( + key: key, + value: value, + enabled: enabled, + child: child, + ); + + /// Whether to display a checkmark next to the menu item. + /// + /// Defaults to false. + /// + /// When true, an [Icons.done] checkmark is displayed. + /// + /// When this popup menu item is selected, the checkmark will fade in or out + /// as appropriate to represent the implied new state. + final bool checked; + + /// The widget below this widget in the tree. + /// + /// Typically a [Text]. An appropriate [DefaultTextStyle] is put in scope for + /// the child. The text should be short enough that it won't wrap. + /// + /// This widget is placed in the [ListTile.title] slot of a [ListTile] whose + /// [ListTile.leading] slot is an [Icons.done] icon. + @override + Widget get child => super.child; + + @override + _CheckedPopupMenuItemsState createState() => new _CheckedPopupMenuItemsState(); +} + +class _CheckedPopupMenuItemsState extends PopupMenuItemsState> with SingleTickerProviderStateMixin { + static const Duration _fadeDuration = const Duration(milliseconds: 150); + AnimationController _controller; + Animation get _opacity => _controller.view; + + @override + void initState() { + super.initState(); + _controller = new AnimationController(duration: _fadeDuration, vsync: this) + ..value = widget.checked ? 1.0 : 0.0 + ..addListener(() => setState(() { /* animation changed */ })); + } + + @override + void handleTap() { + // This fades the checkmark in or out when tapped. + if (widget.checked) + _controller.reverse(); + else + _controller.forward(); + super.handleTap(); + } + + @override + Widget buildChild() { + return new ListTile( + enabled: widget.enabled, + leading: new FadeTransition( + opacity: _opacity, + child: new Icon(_controller.isDismissed ? null : Icons.done) + ), + title: widget.child, + ); + } +} + +class _PopupMenu extends StatelessWidget { + const _PopupMenu({ + Key key, + this.route, + this.semanticLabel, + }) : super(key: key); + + final _PopupMenuRoute route; + final String semanticLabel; + + @override + Widget build(BuildContext context) { + final double unit = 1.0 / (route.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade. + final List children = []; + + for (int i = 0; i < route.items.length; i += 1) { + final double start = (i + 1) * unit; + final double end = (start + 1.5 * unit).clamp(0.0, 1.0); + final CurvedAnimation opacity = new CurvedAnimation( + parent: route.animation, + curve: new Interval(start, end) + ); + Widget item = route.items[i]; + if (route.initialValue != null && route.items[i].represents(route.initialValue)) { + item = new Container( + color: Theme.of(context).highlightColor, + child: item, + ); + } + children.add(new FadeTransition( + opacity: opacity, + child: item, + )); + } + + final CurveTween opacity = new CurveTween(curve: const Interval(0.0, 1.0 / 3.0)); + final CurveTween width = new CurveTween(curve: new Interval(0.0, unit)); + final CurveTween height = new CurveTween(curve: new Interval(0.0, unit * route.items.length)); + + final Widget child = new ConstrainedBox( + constraints: const BoxConstraints( + minWidth: _kMenuMinWidth, + maxWidth: _kMenuMaxWidth, + ), + child: new IntrinsicWidth( + stepWidth: _kMenuWidthStep, + child: new SingleChildScrollView( + padding: const EdgeInsets.symmetric( + vertical: _kMenuVerticalPadding + ), + child: new ListBody(children: children), + ) + ) + ); + + return new AnimatedBuilder( + animation: route.animation, + builder: (BuildContext context, Widget child) { + return new Opacity( + opacity: opacity.evaluate(route.animation), + child: new Material( + type: MaterialType.card, + elevation: route.elevation, + child: new Align( + alignment: AlignmentDirectional.topEnd, + widthFactor: width.evaluate(route.animation), + heightFactor: height.evaluate(route.animation), + child: new Semantics( + scopesRoute: true, + namesRoute: true, + explicitChildNodes: true, + label: semanticLabel, + child: child, + ), + ), + ), + ); + }, + child: child, + ); + } +} + +// Positioning of the menu on the screen. +class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { + _PopupMenuRouteLayout(this.position, this.selectedItemOffset, this.textDirection); + + // Rectangle of underlying button, relative to the overlay's dimensions. + final RelativeRect position; + + // The distance from the top of the menu to the middle of selected item. + // + // This will be null if there's no item to position in this way. + final double selectedItemOffset; + + // Whether to prefer going to the left or to the right. + final TextDirection textDirection; + + // We put the child wherever position specifies, so long as it will fit within + // the specified parent size padded (inset) by 8. If necessary, we adjust the + // child's position so that it fits. + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + // The menu can be at most the size of the overlay minus 8.0 pixels in each + // direction. + return new BoxConstraints.loose(constraints.biggest - const Offset(_kMenuScreenPadding * 2.0, _kMenuScreenPadding * 2.0)); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + // size: The size of the overlay. + // childSize: The size of the menu, when fully open, as determined by + // getConstraintsForChild. + + // Find the ideal vertical position. + double y; + if (selectedItemOffset == null) { + y = position.top; + } else { + y = position.top + (size.height - position.top - position.bottom) / 2.0 - selectedItemOffset; + } + + // Find the ideal horizontal position. + double x; + if (position.left > position.right) { + // Menu button is closer to the right edge, so grow to the left, aligned to the right edge. + x = size.width - position.right - childSize.width; + } else if (position.left < position.right) { + // Menu button is closer to the left edge, so grow to the right, aligned to the left edge. + x = position.left; + } else { + // Menu button is equidistant from both edges, so grow in reading direction. + assert(textDirection != null); + switch (textDirection) { + case TextDirection.rtl: + x = size.width - position.right - childSize.width; + break; + case TextDirection.ltr: + x = position.left; + break; + } + } + + // Avoid going outside an area defined as the rectangle 8.0 pixels from the + // edge of the screen in every direction. + if (x < _kMenuScreenPadding) + x = _kMenuScreenPadding; + else if (x + childSize.width > size.width - _kMenuScreenPadding) + x = size.width - childSize.width - _kMenuScreenPadding; + if (y < _kMenuScreenPadding) + y = _kMenuScreenPadding; + else if (y + childSize.height > size.height - _kMenuScreenPadding) + y = size.height - childSize.height - _kMenuScreenPadding; + return new Offset(x, y); + } + + @override + bool shouldRelayout(_PopupMenuRouteLayout oldDelegate) { + return position != oldDelegate.position; + } +} + +class _PopupMenuRoute extends PopupRoute { + _PopupMenuRoute({ + this.position, + this.items, + this.initialValue, + this.elevation, + this.theme, + this.barrierLabel, + this.semanticLabel, + }); + + final RelativeRect position; + final List> items; + final dynamic initialValue; + final double elevation; + final ThemeData theme; + final String semanticLabel; + + @override + Animation createAnimation() { + return new CurvedAnimation( + parent: super.createAnimation(), + curve: Curves.linear, + reverseCurve: const Interval(0.0, _kMenuCloseIntervalEnd) + ); + } + + @override + Duration get transitionDuration => _kMenuDuration; + + @override + bool get barrierDismissible => true; + + @override + Color get barrierColor => null; + + @override + final String barrierLabel; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + double selectedItemOffset; + if (initialValue != null) { + double y = _kMenuVerticalPadding; + for (PopupMenuEntry entry in items) { + if (entry.represents(initialValue)) { + selectedItemOffset = y + entry.height / 2.0; + break; + } + y += entry.height; + } + } + + Widget menu = new _PopupMenu(route: this, semanticLabel: semanticLabel); + if (theme != null) + menu = new Theme(data: theme, child: menu); + + return new MediaQuery.removePadding( + context: context, + removeTop: true, + removeBottom: true, + removeLeft: true, + removeRight: true, + child: new Builder( + builder: (BuildContext context) { + return new CustomSingleChildLayout( + delegate: new _PopupMenuRouteLayout( + position, + selectedItemOffset, + Directionality.of(context), + ), + child: menu, + ); + }, + ), + ); + } +} + +/// Show a popup menu that contains the `items` at `position`. +/// +/// If `initialValue` is specified then the first item with a matching value +/// will be highlighted and the value of `position` gives the rectangle whose +/// vertical center will be aligned with the vertical center of the highlighted +/// item (when possible). +/// +/// If `initialValue` is not specified then the top of the menu will be aligned +/// with the top of the `position` rectangle. +/// +/// In both cases, the menu position will be adjusted if necessary to fit on the +/// screen. +/// +/// Horizontally, the menu is positioned so that it grows in the direction that +/// has the most room. For example, if the `position` describes a rectangle on +/// the left edge of the screen, then the left edge of the menu is aligned with +/// the left edge of the `position`, and the menu grows to the right. If both +/// edges of the `position` are equidistant from the opposite edge of the +/// screen, then the ambient [Directionality] is used as a tie-breaker, +/// preferring to grow in the reading direction. +/// +/// The positioning of the `initialValue` at the `position` is implemented by +/// iterating over the `items` to find the first whose +/// [PopupMenuEntry.represents] method returns true for `initialValue`, and then +/// summing the values of [PopupMenuEntry.height] for all the preceding widgets +/// in the list. +/// +/// The `elevation` argument specifies the z-coordinate at which to place the +/// menu. The elevation defaults to 8, the appropriate elevation for popup +/// menus. +/// +/// The `context` argument is used to look up the [Navigator] and [Theme] for +/// the menu. It is only used when the method is called. Its corresponding +/// widget can be safely removed from the tree before the popup menu is closed. +/// +/// The `semanticLabel` argument is used by accessibility frameworks to +/// announce screen transitions when the menu is opened and closed. If this +/// label is not provided, it will default to +/// [MaterialLocalizations.popupMenuLabel]. +/// +/// See also: +/// +/// * [PopupMenuItems], a popup menu entry for a single value. +/// * [PopupMenuDivider], a popup menu entry that is just a horizontal line. +/// * [CheckedPopupMenuItems], a popup menu item with a checkmark. +/// * [PopupMenuButton], which provides an [IconButton] that shows a menu by +/// calling this method automatically. +/// * [SemanticsConfiguration.namesRoute], for a description of edge triggered +/// semantics. +Future showMenu({ + @required BuildContext context, + RelativeRect position, + @required List> items, + T initialValue, + double elevation = 8.0, + String semanticLabel, +}) { + assert(context != null); + assert(items != null && items.isNotEmpty); + String label = semanticLabel; + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + label = semanticLabel; + break; + case TargetPlatform.android: + case TargetPlatform.fuchsia: + label = semanticLabel ?? MaterialLocalizations.of(context)?.popupMenuLabel; + } + + return Navigator.push(context, new _PopupMenuRoute( + position: position, + items: items, + initialValue: initialValue, + elevation: elevation, + semanticLabel: label, + theme: Theme.of(context, shadowThemeOnly: true), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); +} + +/// Signature for the callback invoked when a menu item is selected. The +/// argument is the value of the [PopupMenuItems] that caused its menu to be +/// dismissed. +/// +/// Used by [PopupMenuButton.onSelected]. +typedef void PopupMenuItemsSelected(T value); + +/// Signature for the callback invoked when a [PopupMenuButton] is dismissed +/// without selecting an item. +/// +/// Used by [PopupMenuButton.onCanceled]. +typedef void PopupMenuCanceled(); + +/// Signature used by [PopupMenuButton] to lazily construct the items shown when +/// the button is pressed. +/// +/// Used by [PopupMenuButton.itemBuilder]. +typedef List> PopupMenuItemsBuilder(BuildContext context); + +/// Displays a menu when pressed and calls [onSelected] when the menu is dismissed +/// because an item was selected. The value passed to [onSelected] is the value of +/// the selected menu item. +/// +/// One of [child] or [icon] may be provided, but not both. If [icon] is provided, +/// then [PopupMenuButton] behaves like an [IconButton]. +/// +/// If both are null, then a standard overflow icon is created (depending on the +/// platform). +/// +/// ## Sample code +/// +/// This example shows a menu with four items, selecting between an enum's +/// values and setting a `_selection` field based on the selection. +/// +/// ```dart +/// // This is the type used by the popup menu below. +/// enum WhyFarther { harder, smarter, selfStarter, tradingCharter } +/// +/// // This menu button widget updates a _selection field (of type WhyFarther, +/// // not shown here). +/// new PopupMenuButton( +/// onSelected: (WhyFarther result) { setState(() { _selection = result; }); }, +/// itemBuilder: (BuildContext context) => >[ +/// const PopupMenuItems( +/// value: WhyFarther.harder, +/// child: const Text('Working a lot harder'), +/// ), +/// const PopupMenuItems( +/// value: WhyFarther.smarter, +/// child: const Text('Being a lot smarter'), +/// ), +/// const PopupMenuItems( +/// value: WhyFarther.selfStarter, +/// child: const Text('Being a self-starter'), +/// ), +/// const PopupMenuItems( +/// value: WhyFarther.tradingCharter, +/// child: const Text('Placed in charge of trading charter'), +/// ), +/// ], +/// ) +/// ``` +/// +/// See also: +/// +/// * [PopupMenuItems], a popup menu entry for a single value. +/// * [PopupMenuDivider], a popup menu entry that is just a horizontal line. +/// * [CheckedPopupMenuItems], a popup menu item with a checkmark. +/// * [showMenu], a method to dynamically show a popup menu at a given location. +class PopupMenuButtons extends StatefulWidget { + /// Creates a button that shows a popup menu. + /// + /// The [itemBuilder] argument must not be null. + const PopupMenuButtons({ + Key key, + @required this.itemBuilder, + this.initialValue, + this.onSelected, + this.onCanceled, + this.tooltip, + this.elevation = 8.0, + this.padding = const EdgeInsets.all(8.0), + this.child, + this.icon, + this.marginTopHeigt, + this.marginLeftWidth + }) : assert(itemBuilder != null), + assert(!(child != null && icon != null)), // fails if passed both parameters + super(key: key); + + /// Called when the button is pressed to create the items to show in the menu. + final PopupMenuItemsBuilder itemBuilder; + + /// The value of the menu item, if any, that should be highlighted when the menu opens. + final T initialValue; + + /// Called when the user selects a value from the popup menu created by this button. + /// + /// If the popup menu is dismissed without selecting a value, [onCanceled] is + /// called instead. + final PopupMenuItemsSelected onSelected; + + /// Called when the user dismisses the popup menu without selecting an item. + /// + /// If the user selects a value, [onSelected] is called instead. + final PopupMenuCanceled onCanceled; + + /// Text that describes the action that will occur when the button is pressed. + /// + /// This text is displayed when the user long-presses on the button and is + /// used for accessibility. + final String tooltip; + + /// The z-coordinate at which to place the menu when open. This controls the + /// size of the shadow below the menu. + /// + /// Defaults to 8, the appropriate elevation for popup menus. + final double elevation; + + /// Matches IconButton's 8 dps padding by default. In some cases, notably where + /// this button appears as the trailing element of a list item, it's useful to be able + /// to set the padding to zero. + final EdgeInsetsGeometry padding; + + /// If provided, the widget used for this button. + final Widget child; + + /// If provided, the icon used for this button. + final Icon icon; + final double marginTopHeigt; + final double marginLeftWidth; + + @override + _PopupMenuButtonState createState() => new _PopupMenuButtonState(marginTopHeigt,marginLeftWidth); +} + +class _PopupMenuButtonState extends State> { + final double marginTopHeigt; + final double marginLeftWidth; + _PopupMenuButtonState(this.marginTopHeigt,this.marginLeftWidth); + void showButtonMenu() { + final RenderBox button = context.findRenderObject(); + final RenderBox overlay = Overlay.of(context).context.findRenderObject(); + + final RelativeRect position = new RelativeRect.fromRect( + new Rect.fromPoints( + button.localToGlobal(Offset.zero, ancestor: overlay), + button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay), + ), + // Offset.zero & overlay.size, + Offset.lerp(Offset(-marginLeftWidth,-marginTopHeigt),Offset(-marginLeftWidth,-marginTopHeigt),0.0)&overlay.size, + ); + showMenu( + context: context, + elevation: widget.elevation, + items: widget.itemBuilder(context), + initialValue: widget.initialValue, + position: position, + ) + .then((T newValue) { + if (!mounted) + return null; + if (newValue == null) { + if (widget.onCanceled != null) + widget.onCanceled(); + return null; + } + if (widget.onSelected != null) + widget.onSelected(newValue); + }); + } + + Icon _getIcon(TargetPlatform platform) { + assert(platform != null); + switch (platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + return const Icon(Icons.more_vert); + case TargetPlatform.iOS: + return const Icon(Icons.more_horiz); + } + return null; + } + + @override + Widget build(BuildContext context) { + return widget.child != null + ? new InkWell( + onTap: showButtonMenu, + child: widget.child, + ) + : new IconButton( + icon: widget.icon ?? _getIcon(Theme.of(context).platform), + padding: widget.padding, + tooltip: widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, + onPressed: showButtonMenu, + ); + } +} diff --git a/lib/http_utils/Toasty.dart b/lib/http_utils/Toasty.dart new file mode 100644 index 0000000..2897320 --- /dev/null +++ b/lib/http_utils/Toasty.dart @@ -0,0 +1,34 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +class Toasty { + static const MethodChannel _channel = + const MethodChannel('toasty'); + + static success (String content) async { + await _channel.invokeMethod('success', { + "message": content, + }); + } + static info (String content) async { + await _channel.invokeMethod('info', { + "message": content, + }); + } + static warning (String content) async { + await _channel.invokeMethod('warning', { + "message": content, + }); + } + static normal (String content) async { + await _channel.invokeMethod('normal', { + "message": content, + }); + } + static error (String content) async { + await _channel.invokeMethod('error', { + "message": content, + }); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index ddbfa20..d47e6b5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter/services.dart'; import 'package:flutter_app/RegistPager.dart'; import 'package:flutter_app/flutter_WidghtUtils/MyContainUtils.dart'; import 'package:flutter_app/http_utils/HttpUtils.dart'; +import 'package:flutter_app/http_utils/Toasty.dart'; import 'package:flutter_app/showmain.dart'; import 'package:flutter_app/test/SqlUtils.dart'; import 'package:image_picker/image_picker.dart'; @@ -15,15 +17,13 @@ import 'package:path_provider/path_provider.dart'; import 'package:flutter_app/http_utils/HttpUtils.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; - +import 'package:fluttertoast/fluttertoast.dart'; void main() { runApp( new MaterialApp( title: 'app', theme: new ThemeData( - primaryColor: Color(0xFF00838F), - primarySwatch: Colors.purple, - accentColor: Colors.orangeAccent[400], + primaryColor:Colors.lightBlueAccent, ), home: new MyLoginWidget(), ), @@ -59,6 +59,7 @@ class LoginButton extends StatelessWidget { Scaffold.of(context).showSnackBar(snackBar); } }, + child: new Text( '登陆', style: TextStyle(color: Colors.white, fontSize: 16.0), @@ -81,6 +82,8 @@ class MyLoginWidget extends StatefulWidget { class MyLoginState extends State with TickerProviderStateMixin{ final scaffoldState = GlobalKey(); + var demonPlugin=new MethodChannel('demo.plugin'); + TodoProvider todoProvider = new TodoProvider(); AppLifecycleState _lastLifecycleState; GlobalKey _formKey = GlobalKey(); @@ -151,14 +154,20 @@ class MyLoginState extends State with TickerProviderStateMixin{ todoProvider.open(path); } - Future _Login( - String userName, String password, BuildContext context) async { + Future _Login(String userName, String password, BuildContext context) async { /*//数据库插入语句: Todo todo = new Todo(); todo.title =userName; todo.done = true; todoProvider.insert(todo); + */ + Navigator.of(context).push(new PageRouteBuilder( + opaque: false, + pageBuilder: (BuildContext context, _, __) { + return new MyHomePager(); + }, + )); String url = "http://116.62.149.237:8080/USR000100001?usrName=$userName&passwd=$password"; bool result; @@ -169,11 +178,18 @@ class MyLoginState extends State with TickerProviderStateMixin{ String rescode = data["rescode"]; print(rescode); if (rescode == '999999') { - showDialog( + /* showDialog( context: context, builder: (ctx) => new AlertDialog( content: new Text('登录不成功'), - )); + ));*/ + Fluttertoast.showToast( + msg: " 登录失败 ", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIos:1, + + ); } else if (rescode == '000000') { _writerDataToFile(); Navigator.of(context).push(new PageRouteBuilder( @@ -182,11 +198,19 @@ class MyLoginState extends State with TickerProviderStateMixin{ return new MyHomePager(); }, )); + Fluttertoast.showToast( + msg: " 登录成功! ", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + timeInSecForIos:1, + + ); } }); } catch (e) { return result; } + return result; } @@ -209,6 +233,7 @@ class MyLoginState extends State with TickerProviderStateMixin{ final height_screen = MediaQuery.of(context).size.height; final width_srcreen = MediaQuery.of(context).size.width; return Scaffold( + resizeToAvoidBottomPadding:false, key: scaffoldState, backgroundColor: Colors.white, body: new GestureDetector( @@ -313,7 +338,9 @@ class MyLoginState extends State with TickerProviderStateMixin{ mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ InkWell( - onTap: () {}, + onTap: () { + demonPlugin.invokeMethod('http://jzvd.nathen.cn/d525f756aabf4b0588c2152fb94e07f5/d9f59bef829a472a9ca066620d9b871a-5287d2089db37e62345123a1be272f8b.mp4'); + }, child: Text( 'Forget pd', style: TextStyle( diff --git a/lib/showmain.dart b/lib/showmain.dart index d09d917..d593984 100644 --- a/lib/showmain.dart +++ b/lib/showmain.dart @@ -7,10 +7,12 @@ import 'package:flutter_app/flutter_person/PersonPager.dart'; import 'package:flutter_app/flutter_system/SystemPage.dart'; import 'package:flutter_app/flutter_widget/modle/HomePageBean.dart'; import 'package:flutter_app/flutter_widget/view/DouyinPager.dart'; +import 'package:flutter_app/flutter_widget/view/MainSearchPager.dart'; import 'package:flutter_app/flutter_widget/view/MyDrawer.dart'; import 'package:flutter_app/flutter_widget/view/MyWell_Screen.dart'; import 'package:flutter_app/flutter_widget/view/NetWidget.dart'; import 'package:flutter_app/flutter_widget/view/XuankuPager.dart'; +import 'package:flutter_app/test/SlivScrollListViewTabLayout.dart'; import 'package:flutter_app/test/video_demo.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -28,6 +30,64 @@ import 'package:http/http.dart' as http; import 'dart:convert'; import "package:pull_to_refresh/pull_to_refresh.dart"; +class WidgetPagerss extends StatefulWidget { + @override + State createState() { + return new FirstPageStates(); + } +} + +class FirstPageStates extends State { + @override + Widget build(BuildContext context) { + //TODO 第二个布局 + return new Container( + //距离每个边缘四周32像素 + color: Colors.white30, + margin: EdgeInsets.all(3.0), + child: new Container( + color: Colors.white, + //最外层为一行包裹里面的 + child: new Row( + //里面包含三个大布局子控件控件【两行文字,文字,五角星】 + children: [ + //TODO 第一个子控件里面两行字体,让其占用多余的控件,这样右边的控件所占之外的所有控件都被他所占用这样展开的更长不然右边控件会往左边跑。 + new Container( + margin: new EdgeInsets.only( + left: 9.0, top: 8.0, right: 45.0, bottom: 5.0), + //这个列里面装两行文字 + child: new Column( + //文字从这个左边开始 + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + //距离下面一个文字8像素 + padding: const EdgeInsets.only(bottom: 8.0), + child: new Text( + '2018年度好看电视剧', + style: new TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + //第二行灰色的文字标题,当然了这里可以直接去掉new Container因为不需要修改 + new Container( + //这里不需要距离上下边距。所以new Container是可以不用写的哦 + padding: const EdgeInsets.only(bottom: 8.0), + child: new Text( + '冰与火之歌', + style: new TextStyle(color: Colors.grey[500]), + )), + ], + ), + ), + ], + ), + ), + ); + } +} + class WidgetPagers extends StatefulWidget { @override State createState() { @@ -658,7 +718,8 @@ class MyHomePager extends StatefulWidget { enum _RadioGroup { foo1, foo2 } class _MyHomePageState extends State - with SingleTickerProviderStateMixin { + with TickerProviderStateMixin { + List mImagesAdate; RefreshController _refreshController; bool preed_is = true; bool preed_is_second = false; @@ -759,6 +820,7 @@ class _MyHomePageState extends State } }); } + _pressedChangerd_four() { setState(() { if (index != 3) { @@ -811,6 +873,28 @@ class _MyHomePageState extends State @override void initState() { super.initState(); + /*/* https://github.com/luhenchang/flutter_study/blob/master/images/longnv5.jpeg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/long_wuman.jpeg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/longwuman3.jpg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/lonnv6.jpg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/lonnv10.jpg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/longnv5.jpeg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/long_wuman.jpeg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/longwuman3.jpg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/lonnv6.jpg?raw=true +* https://github.com/luhenchang/flutter_study/blob/master/images/lonnv10.jpg?raw=true +* */ + * */ + mImagesAdate = List(); + mImagesAdate.clear(); + mImagesAdate.add( + "https://github.com/luhenchang/flutter_study/blob/master/images/longnv5.jpeg?raw=true"); + mImagesAdate.add( + "https://github.com/luhenchang/flutter_study/blob/master/images/long_wuman.jpeg?raw=true"); + mImagesAdate.add( + "https://github.com/luhenchang/flutter_study/blob/master/images/longwuman3.jpg?raw=true"); + mImagesAdate.add( + "https://github.com/luhenchang/flutter_study/blob/master/images/lonvn9.jpg?raw=true"); _refreshController = new RefreshController(); loadData(); initData(); @@ -831,22 +915,25 @@ class _MyHomePageState extends State } Widget getItemWidget(String url) { - return new InkWell( - onTap:(){ - Navigator.of(context).push( - new MaterialPageRoute( - builder: (context) { - return new MyWell_Screen(); - }, - ), - ); - }, - child:Image.asset( - url, - fit: BoxFit.cover, - width: 80.0, - height: 80.0, - ),); + return Material( + child: new InkWell( + onTap: () { + Navigator.of(context).push( + new MaterialPageRoute( + builder: (context) { + return new MyWell_Screen(); + }, + ), + ); + }, + child: Image.asset( + url, + fit: BoxFit.cover, + width: 80.0, + height: 80.0, + ), + ), + ); } List _ItemList() { @@ -883,9 +970,20 @@ class _MyHomePageState extends State ? new AppBar( titleSpacing: 0.0, automaticallyImplyLeading: false, - title: AppBar2( - index1: index, - )) + title: GestureDetector( + onTap:(){ + Navigator.of(context).push(new PageRouteBuilder( + opaque: false, + pageBuilder: (BuildContext context, _, __) { + return new MainSearchPager(); + }, + )); + }, + child: AppBar2( + index1: index, + ), + ), + ) : index == 1 ? AppBar( titleSpacing: 0.0, @@ -1053,12 +1151,15 @@ class _MyHomePageState extends State children: [ new GestureDetector( onTap: () { - - Navigator.of(context).push(new PageRouteBuilder( - pageBuilder: (BuildContext context, _, __) { - return new XuankuPage(); - }, - )); + Navigator + .of(context) + .push(new PageRouteBuilder( + pageBuilder: + (BuildContext context, _, + __) { + return new XuankuPage(); + }, + )); }, child: Container( child: Column( @@ -1155,6 +1256,59 @@ class _MyHomePageState extends State mainAxisSpacing: 6.0, children: _ItemList(), )), + WidgetPagerss(), + new Container( + color: Colors.white, + height: + MediaQuery.of(context).size.width / 2 + 15, + width: MediaQuery.of(context).size.width, + child: new GridView.builder( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 11.0, + mainAxisSpacing: 11.0, + childAspectRatio: 2.0), + primary: false, + itemCount: mImagesAdate.length, + padding: const EdgeInsets.all(10.0), + itemBuilder: (BuildContext context, int i) { + return Container( + height: 400.0, + width: MediaQuery.of(context).size.width, + color: Colors.teal, + child: Hero( + tag: mImagesAdate[i], + child: Material( + child: InkWell( + child: new FadeInImage( + image: new NetworkImage( + mImagesAdate[i]), + fit: BoxFit.cover, + placeholder: new AssetImage( + 'images/wallfy.png'), + ), + onTap: () { + Navigator + .of(context) + .push(new PageRouteBuilder( + opaque: false, + pageBuilder: + (BuildContext context, + _, __) { + return new MyAppsss( + mImagesAdate[i], + mImagesAdate[i]); + }, + )); + }, + ), + ), + ), + ); + }, + )), + WidgetPagers(), new WidgetStudy(), new WidgetText(), @@ -1308,7 +1462,7 @@ class _MyHomePageState extends State .get('http://116.62.149.237:8080/USR000100002') .then((http.Response response) { print(response.body); - var datas = JSON.decode(response.body); + var datas = json.decode(response.body); String rescode = datas["rescode"]; var listData = datas["resobj"]; setState(() { diff --git a/lib/test/CountButtonView.dart b/lib/test/CountButtonView.dart new file mode 100644 index 0000000..3338363 --- /dev/null +++ b/lib/test/CountButtonView.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +typedef void CountButtonClickCallBack(int count); + +class CountButtonView extends StatefulWidget { + final int initialCount; + final CountButtonClickCallBack onChange; + CountButtonView({this.initialCount, this.onChange}); + @override + _CountButtonViewState createState() => _CountButtonViewState(); +} + +class _CountButtonViewState extends State { + int count; + + @override + void initState() { + // TODO: implement initState + super.initState(); + count = widget.initialCount; + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + void updateCount(int addValue) { + if (count + addValue >= 0) { + setState(() { + count += addValue; + }); + if (widget.onChange != null) { + widget.onChange(count); + } + } + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 110.0, + height: 44.0, + child: Center( + child: Container( + decoration: BoxDecoration( + color: Color(0xddFFFFFF), + border: Border.all(color: Colors.orange, width: 1.0), + borderRadius: BorderRadius.circular(22.0)), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + updateCount(-1); + }, + child: Container( + width: 40.0, + child: Center( + child: Text( + '-', + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: Colors.orange, + decoration: TextDecoration.none), + )))), + Container( + child: Center( + child: Text( + '$count', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.orange, + decoration: TextDecoration.none), + )), + ), + GestureDetector( + onTap: () { + updateCount(1); + }, + child: Container( + width: 40.0, + child: Center( + child: Text( + '+', + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: Colors.orange, + decoration: TextDecoration.none), + )))), + ], + ), + ), + ), + ); + } +} diff --git a/lib/test/DishesList.dart b/lib/test/DishesList.dart new file mode 100644 index 0000000..7239b67 --- /dev/null +++ b/lib/test/DishesList.dart @@ -0,0 +1,107 @@ +class Dish { + String imgUrl; + String name; + double price; + String unit; + String desc; + Dish({this.imgUrl, this.name, this.price, this.unit, this.desc}); +} + +final Map> _dishes = { + '热菜': [ + Dish( + imgUrl: + 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1518412925400&di=a4052bd2a342477effd73969ef88dc5d&imgtype=0&src=http%3A%2F%2Fpic29.photophoto.cn%2F20131221%2F0042040249766610_b.jpg', + name: '宫保鸡丁', + price: 45.0, + unit: '例', + desc: + '川菜中的保留家常菜,由鸡丁、干辣椒、花生米等炒制而成。由于其入口鲜辣,鸡肉的鲜嫩配合花生的香脆,深受大众喜欢。川菜中的保留家常菜,由鸡丁、干辣椒、花生米等炒制而成。由于其入口鲜辣,鸡肉的鲜嫩配合花生的香脆,深受大众喜欢。川菜中的保留家常菜,由鸡丁、干辣椒、花生米等炒制而成。由于其入口鲜辣,鸡肉的鲜嫩配合花生的香脆,深受大众喜欢。'), + Dish( + imgUrl: 'http://images.meishij.net/p/20111202/13c8d3aede342b8e02d0dbf1bb389519.jpg', + name: '番茄牛腩', + price: 35.6, + unit: '碗', + desc: '很暖和的一道菜'), + Dish( + imgUrl: 'http://recipe0.hoto.cn/pic/recipe/l/1c/d3/250652_a7373c.jpg', + name: '油焖大虾', + price: 70.5, + unit: '例', + desc: '油焖大虾,经典鲁菜,菜色泽枣红亮丽,味香飘逸,鲜嫩微甜,油润适口。'), + ], + '凉菜': [ + Dish( + imgUrl: + 'http://c.hiphotos.baidu.com/baike/s%3D235/sign=4e9e519417950a7b713549c73fd0625c/6a600c338744ebf818da6e9dd3f9d72a6159a7ec.jpg', + name: '爆肚', + price: 25.0, + unit: '盘', + desc: '天津和北京风味小吃中著名的回族小吃'), + Dish( + imgUrl: + 'https://gss1.bdstatic.com/9vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=f9eaa3f4bf3eb13544c7b0bd9e25cfee/58ee3d6d55fbb2fb3af6d70e4c4a20a44723dcc9.jpg', + name: '鸡丝拉皮', + price: 15.0, + unit: '碟', + desc: '鸡丝拉皮是一道色香味俱全的地方名肴,属于豫菜系'), + Dish( + imgUrl: + 'http://c.hiphotos.baidu.com/baike/s%3D235/sign=4e9e519417950a7b713549c73fd0625c/6a600c338744ebf818da6e9dd3f9d72a6159a7ec.jpg', + name: '爆肚', + price: 25.5, + unit: '盘', + desc: '天津和北京风味小吃中著名的回族小吃'), + Dish( + imgUrl: + 'http://c.hiphotos.baidu.com/baike/s%3D235/sign=4e9e519417950a7b713549c73fd0625c/6a600c338744ebf818da6e9dd3f9d72a6159a7ec.jpg', + name: '爆肚', + price: 25.6, + unit: '盘', + desc: '天津和北京风味小吃中著名的回族小吃'), + ], +}; + +Dish dishAtIndex(int index) { + int keyNum = _dishes.keys.length; + int totalNum = 0; + for (int i = 0; i < keyNum; i++) { + String key = _dishes.keys.toList()[i]; + List dishesInCurrentKey = _dishes[key]; + if (index >= totalNum && index < totalNum + dishesInCurrentKey.length) { + return dishesInCurrentKey[index - totalNum]; + } + totalNum += dishesInCurrentKey.length; + } + return null; +} + +String typeAtIndex(int index) { + if (index < _dishes.keys.length) { + return _dishes.keys.toList()[index]; + } + return null; +} + +Map> orderedDishes = {}; + +int orderedCountForDish(Dish dish) { + final result = orderedDishes[dish.name]; + if (result == null) { + return 0; + } + final count = result['count']; + return count; +} + +void orderDish(Dish dish, count) { + if (count < 0) { + return; + } + final result = orderedDishes[dish.name]; + if (result == null) { + orderedDishes[dish.name] = {'count': 1, 'dish': dish}; + } else { + result['count'] = count; + } +} diff --git a/lib/test/ImageHero.dart b/lib/test/ImageHero.dart new file mode 100644 index 0000000..883cecf --- /dev/null +++ b/lib/test/ImageHero.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'dart:ui' as ui; + +import 'package:flutter_app/test/SlivScrollListViewTabLayout.dart'; + +void main() { + runApp(new MaterialApp( + theme: new ThemeData( + primaryColor: Color(0xFF00838F), + primarySwatch: Colors.purple, + accentColor: Colors.orangeAccent[400], + ), + home: new MyApp(), + )); +} + +class MyApp extends StatefulWidget { + @override + State createState() { + return new MyAppState(); + } +} + +class MyAppState extends State with TickerProviderStateMixin { + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Hero( + tag: "haha", + child: InkWell( + child:Image.network('https://github.com/luhenchang/flutter_study/blob/master/images/long_wuman.jpeg?raw=true',height:220.0,width:110.0,fit:BoxFit.cover,), + onTap: () { + Navigator.of(context).push(new PageRouteBuilder( + opaque: false, + pageBuilder: (BuildContext context, _, __) { + // return new MyAppsss(); + }, + )); + }, + )), + ); + } +} diff --git a/lib/test/LineaAnimal.dart b/lib/test/LineaAnimal.dart new file mode 100644 index 0000000..d69bb5b --- /dev/null +++ b/lib/test/LineaAnimal.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class SignaturePainter extends CustomPainter { + SignaturePainter(this._animation); + + final AnimationController _animation; + List pointss; + + void paint(Canvas canvas, Size size) { + Path path1 = new Path(); + //y=从200变为150减少了50这里动画,将50看做一个百分百。 + print(_animation.value); + path1.moveTo(44.0, 200.0 - _animation.value); + path1.lineTo(44.0, 200.0 - _animation.value); + var firstControlPoint = Offset(size.width / 4, 200.0); + var firstPoint = Offset(size.width / 2, 200.0); + path1.quadraticBezierTo(firstControlPoint.dx-20.0, firstControlPoint.dy, + firstPoint.dx, firstPoint.dy); + + path1.lineTo(size.width - 100, 200.0); + Paint paint = new Paint(); + paint.color =_animation.isCompleted?Colors.blue:Colors.black; + paint.style = PaintingStyle.stroke; + paint.strokeWidth = 3.0; + canvas.drawPath(path1, paint); + } + + bool shouldRepaint(SignaturePainter other) => other._animation != _animation; +} + +class Signature extends StatefulWidget { + SignatureState createState() => new SignatureState(); +} + +class SignatureState extends State with TickerProviderStateMixin { + AnimationController _animation; + + + @override + void initState() { + // TODO: implement initState + super.initState(); + _animation = new AnimationController( + vsync: this, + duration: Duration(seconds: 3), + lowerBound: 0.0, + upperBound: 50.0); + } + + void _startAnimation() { + _animation.forward(from: 0.0); + } + + Widget build(BuildContext context) { + return Column( + children: [ + new Padding( + padding:new EdgeInsets.only(top: 50.0), + child: IconButton( + icon: Icon(Icons.add), + onPressed: () { + _startAnimation(); + }, + ), + ), + new SizedBox( + height: 200.0, + child: CustomPaint( + painter: new SignaturePainter(_animation), size: Size.infinite), + ) + ], + ); + } +} + +class DemoApp extends StatelessWidget { + Widget build(BuildContext context) => new Scaffold(body: new Signature()); +} + +void main() => runApp(new MaterialApp(home: new DemoApp())); diff --git a/lib/test/MeiTuanShopping.dart b/lib/test/MeiTuanShopping.dart new file mode 100644 index 0000000..d264a69 --- /dev/null +++ b/lib/test/MeiTuanShopping.dart @@ -0,0 +1,570 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_app/test/CountButtonView.dart'; +import 'package:flutter_app/test/DishesList.dart'; +import 'package:flutter_app/test/OrderPage.dart'; +import 'dart:ui' as ui; + +import 'package:flutter_app/test/TitleBar.dart'; +import 'package:shimmer/shimmer.dart'; + +void main() { + runApp(new MaterialApp( + title: '', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new MeiTuanShopping(), + )); +} + +//列表上面吸附APPBar切换 +class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { + _SliverAppBarDelegate(this._tabBar); + + final TabBar _tabBar; + + @override + double get minExtent => _tabBar.preferredSize.height; + + @override + double get maxExtent => _tabBar.preferredSize.height; + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return new Container( + color: Colors.white, + child: _tabBar, + ); + } + + @override + bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { + return false; + } +} + +class MeiTuanShopping extends StatefulWidget { + @override + State createState() => new MeiTuanShopping_State(); +} + +class MeiTuanShopping_State extends State + with TickerProviderStateMixin { + @override + Widget build(BuildContext context) { + return new Scaffold( + backgroundColor: Colors.white, + body: NestedScrollView( + //滑动的头部 + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + leading: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Icon( + Icons.chevron_left, + size: 29.0, + color: Colors.white, + )), + expandedHeight: 216.0, + actions: [ + Padding( + padding: new EdgeInsets.only(right: 30.0), + child: Row( + children: [ + Icon( + Icons.favorite_border, + size: 25.0, + color: Colors.white, + ), + Padding( + child: Icon( + Icons.refresh, + size: 25.0, + color: Colors.white, + ), + padding: new EdgeInsets.only(left: 20.0), + ), + ], + )), + ], + pinned: true, + flexibleSpace: FlexibleSpaceBar( + centerTitle: true, + background: Container( + decoration: new BoxDecoration( + image: new DecorationImage( + fit: BoxFit.cover, + image: new AssetImage("images/haha.png"), + )), + child: Container( + child: new BackdropFilter( + filter: + new ui.ImageFilter.blur(sigmaX: 13.0, sigmaY: 13.0), + child: new Container( + color: Colors.redAccent.withOpacity(0.06), + padding: const EdgeInsets.only(top: 60.0), + width: 90.0, + height: 238.0, + child: Stack( + alignment: Alignment(-0.9, -0.7), + children: [ + new Container( + margin: EdgeInsets.only( + top: 24.0, + ), + alignment: Alignment.topLeft, + child: Container( + child: Column( + children: [ + Container( + child: Column( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(left: 60.0), + child: Text( + "杨明宇黄焖鸡米饭(双林点)", + style: TextStyle( + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + Container( + margin: EdgeInsets.only( + left: 10.0, top: 5.0), + child: Text( + "欢迎光临,很高兴为你服务", + style: TextStyle( + color: Colors.white70, + fontSize: 14.0, + ), + ), + ), + Container( + margin: EdgeInsets.only( + left: 111.0, top:6.0,bottom:6.0), + alignment: Alignment.center, + child: Row( + children: [ + Text("分量足"), + Text("饭好吃"), + ], + ), + ), + ], + ), + ), + Container( + padding: new EdgeInsets.only(top:17.0), + height:90.0, + width: MediaQuery.of(context).size.width, + color: Colors.white, + //TODO 这里是白色部分滑动头布局设置 + child:Row( + children: [ + Container( + margin:new EdgeInsets.all(10.0), + padding: new EdgeInsets.all(2.0), + color:Colors.redAccent, + child: Text("减",style: TextStyle(color: Colors.white),), + ), + Container( + margin:new EdgeInsets.all(10.0), + padding: new EdgeInsets.all(2.0), + child: Text("满15减3;满30减5,;满50减7",style: TextStyle(color: Colors.blueGrey),), + ) + ], + ), + ) + ], + ), + ), + ), + Image.asset( + "images/haha.png", + width: 90.0, + height: 90.0, + ), + ], + ), + ), + ), + ), + ), + ), + ), + SliverPersistentHeader( + pinned: true, + delegate: _SliverAppBarDelegate( + TabBar( + controller: new TabController(length: 2, vsync: this), + labelColor: Colors.teal, + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.teal, + labelStyle: TextStyle(fontWeight: FontWeight.w100), + tabs: [ + Tab(text: "播放列表"), + Tab(text: "视频介绍"), + ], + ), + ), + ) + ]; + }, + //滑动的商品部分 + body: BodySliver(), + ), + ); + } +} + +//最下面商品滑动的一部分。 +class BodySliver extends StatefulWidget { + @override + BodySliverState createState() => new BodySliverState(); +} + +class BodySliverState extends State { + //用来控制左边菜单分类滑动列表的。 + final LeftConstroller = ScrollController(); + + //用来控制右边菜单滑动列表的。 + final RightConstroller = ScrollController(); + int selectedIndex; + bool scrollingOrderList = false; + + @override + void initState() { + super.initState(); + selectedIndex = 0; + //右边菜单列表监听 + RightConstroller.addListener(() { + double offset = RightConstroller.offset; + if (scrollingOrderList) { + return; + } + if (selectedIndex > 0 && offset < 110.0 * 3) { + //这里去更新菜单选择状态。 + setState(() { + selectedIndex = 0; + }); + } else if (selectedIndex == 0 && offset >= 110.0 * 3) { + setState(() { + selectedIndex = 1; + }); + } + }); + } + + @override + void dispose() { + LeftConstroller.dispose(); + RightConstroller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 100.0, + child: Container( + color: Color(0xFFE0E0E0), + child: TypeList( + controller: LeftConstroller, + selectedIndex: selectedIndex, + indexSelected: (index) { + scrollingOrderList = true; + setState(() { + selectedIndex = index; + RightConstroller.animateTo(index * 110.0 * 3, + duration: Duration(milliseconds: 200), + curve: Curves.easeInOut) + .then((a) { + scrollingOrderList = false; + }); + }); + }, + ), + ), + ), + Expanded( + child: OrderList( + controller: RightConstroller, + )), + ], + ); + } +} + +class TypeList extends StatefulWidget { + TypeList({this.controller, this.indexSelected, this.selectedIndex = 0}); + + final controller; + final selectedIndex; + final IndexSelectCallBack indexSelected; + + @override + TypeListState createState() => new TypeListState(); +} + +class TypeListState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ListView.builder(itemBuilder: (context, index) { + String title = typeAtIndex(index); + if (title == null) { + return null; + } + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 60.0, + color: index == widget.selectedIndex + ? Colors.white + : Color(0xFFE0E0E0), + child: FlatButton( + padding: EdgeInsets.zero, + onPressed: () { + widget.indexSelected(index); + }, + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + index == 0 + ? Container( + padding: new EdgeInsets.only(right: 3.0), + child: Icon( + Icons.print, + color: Colors.lightBlueAccent, + size: 15.0, + ), + ) + : Container(), + Text(title), + ], + ))), + ), + ], + ); + }); + } +} + +class OrderList extends StatefulWidget { + OrderList({this.controller}); + + final controller; + + @override + OrderListState createState() => new OrderListState(); +} + +class OrderListState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + void cellSelected(BuildContext context, Dish dish) { + print('selected ${dish.name}'); + showDialog( + context: context, + builder: (context) { + return Theme( + data: Theme.of(context), + child: Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: Container( + color: Colors.grey.shade100, + width: 300.0, + height: 350.0, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 100.0, + height:100.0, + child: _buildImage(dish), + ), + _buildPopupFooter(dish) + ]), + )), + )), + ); + }); + } + + Widget _buildPopupFooter(Dish dish) { + return Container( +// height: 120.0, + padding: EdgeInsets.all(10.0), + color: Colors.grey.shade100, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleRow(dish), + Container( + color: Colors.transparent, + height: 5.0, + ), + Text( + dish.desc, + softWrap: true, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.normal, + fontSize: 15.0, + decoration: TextDecoration.none), + ), + ], + ), + ); + } + + Widget _buildImage(Dish dish) { + return Stack( + fit: StackFit.expand, +// alignment: Alignment.center, + children: [ + Image.asset( + "images/haha.png", + fit: BoxFit.cover, + height:80.0, + width:80.0, + ), + ], + ); + } + + Widget _buildTitleRow(Dish dish) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + dish.name, + style: TextStyle( + color: Colors.black, + fontSize: 19.0, + decoration: TextDecoration.none), + ), + Text( + '¥${dish.price} / ${dish.unit}', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.w800, + fontSize: 19.0, + decoration: TextDecoration.none), + ) + ], + ); + } + + Widget _buildCellFooter(Dish dish) { + return Container( + height: 90.0, + width:130.0, + padding: EdgeInsets.all(10.0), + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("先扫码后下单!",style: TextStyle(fontSize:13.0,fontWeight:FontWeight.bold),), + Row(children: [ + Text("销售0 ",style: TextStyle(fontSize:13.0,fontWeight:FontWeight.bold,color: Colors.grey),), + Text(" 赞0",style: TextStyle(fontSize:13.0,fontWeight:FontWeight.bold,color: Colors.grey),), + ],), + Text( + "¥999", + maxLines:1, + softWrap: true, + style:TextStyle(fontSize:16.0,color: Colors.redAccent), + ), + ], + ), + ); + } + + Widget _buildCell(BuildContext context, int index) { + Dish dish = dishAtIndex(index); + if (dish == null) { + return null; + } + return Center( + child: FlatButton( + onPressed: () { + cellSelected(context, dish); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SizedBox( + width: 250.0, + height:100.0, + child: Row( + children: [ + Container( + width: 80.0, + height:80.0, + child: _buildImage(dish), + ), + _buildCellFooter(dish) + ], + ), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + child: ListView.builder( + controller: this.widget.controller, + itemBuilder: (context, index) { + if (index % 2 == 0) { + return _buildCell(context, index ~/ 2); + } else { + return Container( + height: 10.0, + color: Colors.transparent, + ); + } + }), + ); + } +} diff --git a/lib/test/OrderPage.dart b/lib/test/OrderPage.dart new file mode 100644 index 0000000..83019a4 --- /dev/null +++ b/lib/test/OrderPage.dart @@ -0,0 +1,349 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/test/CountButtonView.dart'; +import 'package:flutter_app/test/DishesList.dart'; + + +typedef void IndexSelectCallBack(int index); + + +void main() { + runApp( + new MaterialApp( + title: '', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new OrderPage(), + ), + ); +} + +class OrderPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('OrderPage'), + ), + body: OrderPageContent(), + ); + } +} + +class OrderPageContent extends StatefulWidget { + @override + OrderPageContentState createState() => new OrderPageContentState(); +} + +class OrderPageContentState extends State { + final typeListController = ScrollController(); + final orderListController = ScrollController(); + int selectedIndex; + bool scrollingOrderList = false; + @override + void initState() { + super.initState(); + selectedIndex = 0; + orderListController.addListener(() { + double offset = orderListController.offset; + if (scrollingOrderList) { + return; + } + if (selectedIndex > 0 && offset < 260.0 * 3) { + //菜单列表滚动,更新菜类选中,待定制tableview做好以后,需要优化 + setState(() { + selectedIndex = 0; + }); + } else if (selectedIndex == 0 && offset >= 260.0 * 3) { + setState(() { + selectedIndex = 1; + }); + } + }); + } + + @override + void dispose() { + typeListController.dispose(); + orderListController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 100.0, + child: Container( + color: Colors.blue, + child: TypeList( + controller: typeListController, + selectedIndex: selectedIndex, + indexSelected: (index) { + scrollingOrderList = true; + setState(() { + selectedIndex = index; + orderListController + .animateTo(index * 260.0 * 3, + duration: Duration(milliseconds: 200), curve: Curves.easeInOut) + .then((a) { + scrollingOrderList = false; + }); + }); + }, + ), + ), + ), + Expanded( + child: OrderList( + controller: orderListController, + )), + ], + ); + } +} + +class TypeList extends StatefulWidget { + TypeList({this.controller, this.indexSelected, this.selectedIndex = 0}); + final controller; + final selectedIndex; + final IndexSelectCallBack indexSelected; + @override + TypeListState createState() => new TypeListState(); +} + +class TypeListState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ListView.builder(itemBuilder: (context, index) { + String title = typeAtIndex(index); + if (title == null) { + return null; + } + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 60.0, + color: index == widget.selectedIndex ? Colors.white : Colors.grey, + child: FlatButton( + padding: EdgeInsets.zero, + onPressed: () { + widget.indexSelected(index); + }, + child: Center( + child: Text(title), + )), + ), + Container( + height: 1.0, + color: Colors.grey, + ) + ], + ); + }); + } +} + +class OrderList extends StatefulWidget { + OrderList({this.controller}); + final controller; + @override + OrderListState createState() => new OrderListState(); +} + +class OrderListState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + void cellSelected(BuildContext context, Dish dish) { + print('selected ${dish.name}'); + showDialog( + context: context, + builder: (context) { + return Theme( + data: Theme.of(context), + child: Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: Container( + color: Colors.grey.shade100, + width: 300.0, + height: 350.0, + child: SingleChildScrollView( + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Container( + width: 300.0, + height: 200.0, + child: _buildImage(dish), + ), + _buildPopupFooter(dish) + ]), + )), + )), + ); + }); + } + + Widget _buildPopupFooter(Dish dish) { + return Container( +// height: 120.0, + padding: EdgeInsets.all(10.0), + color: Colors.grey.shade100, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleRow(dish), + Container( + color: Colors.transparent, + height: 5.0, + ), + Text( + dish.desc, + softWrap: true, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.normal, + fontSize: 15.0, + decoration: TextDecoration.none), + ), + ], + ), + ); + } + + Widget _buildImage(Dish dish) { + return Stack( + fit: StackFit.expand, +// alignment: Alignment.center, + children: [ + Image.network( + dish.imgUrl, + fit: BoxFit.cover, + ), + Positioned( + right: 8.0, + bottom: 8.0, + child: CountButtonView( + initialCount: orderedCountForDish(dish), + onChange: (count) { + orderDish(dish, count); + }, + )), + ], + ); + } + + Widget _buildTitleRow(Dish dish) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + dish.name, + style: TextStyle(color: Colors.black, fontSize: 19.0, decoration: TextDecoration.none), + ), + Text( + '¥${dish.price } / ${dish.unit}', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.w800, + fontSize: 19.0, + decoration: TextDecoration.none), + ) + ], + ); + } + + Widget _buildCellFooter(Dish dish) { + return Container( + height: 90.0, + padding: EdgeInsets.all(10.0), + color: Colors.grey.shade100, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleRow(dish), + Text( + dish.desc, + maxLines: 2, + softWrap: true, + ), + ], + ), + ); + } + + Widget _buildCell(BuildContext context, int index) { + Dish dish = dishAtIndex(index); + if (dish == null) { + return null; + } + return Center( + child: FlatButton( + onPressed: () { + cellSelected(context, dish); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SizedBox( + width: 250.0, + height: 250.0, + child: Column( + children: [ + Container( + width: 250.0, + height: 160.0, + child: _buildImage(dish), + ), + _buildCellFooter(dish) + ], + ), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + child: ListView.builder( + controller: this.widget.controller, + itemBuilder: (context, index) { + if (index % 2 == 0) { + return _buildCell(context, index ~/ 2); + } else { + return Container( + height: 10.0, + color: Colors.transparent, + ); + } + }), + ); + } +} diff --git a/lib/test/SlivScrollListViewTabLayout.dart b/lib/test/SlivScrollListViewTabLayout.dart new file mode 100644 index 0000000..ca111c0 --- /dev/null +++ b/lib/test/SlivScrollListViewTabLayout.dart @@ -0,0 +1,374 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'dart:ui' as ui; + +import 'package:flutter_app/test/TitleBar.dart'; +import 'package:shimmer/shimmer.dart'; + +class Entry { + Entry(this.title, [this.children = const []]); + + final String title; + final List children; +} + +// The entire multilevel list displayed by this app. +final List data = [ + new Entry( + '在线播放【推荐】', + [ + new Entry('HD1280高清汉语中文版'), + ], + ), + new Entry( + '外部播放【推荐】', + [ + new Entry('HD1280高清汉语中文版'), + ], + ), + new Entry( + '在线【推荐】', + [ + new Entry('高清汉语中文字幕'), + ], + ), +]; + +class MyAppsss extends StatefulWidget { + var imagePath; + var Tag; + + MyAppsss(this.imagePath, this.Tag); + + @override + State createState() { + return new MyAppState(this.imagePath, this.Tag); + } +} + +class MyAppState extends State with TickerProviderStateMixin { + final List listData = []; + var imagePath; + var Tag; + + MyAppState(this.imagePath, this.Tag); + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + listData + .add(new ListItem("在线播放[推荐]", Icons.important_devices, Colors.teal)); + listData.add(new ListItem("外部播放[推荐]", Icons.computer, Colors.redAccent)); + listData.add(new ListItem("在线播放[推荐]", Icons.save, Color(0xFFAB47BC))); + + return Scaffold( + backgroundColor: Colors.white, + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + leading: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Icon( + Icons.chevron_left, + size: 29.0, + color: Colors.white, + )), + expandedHeight: 300.0, + actions: [ + Padding( + padding: new EdgeInsets.only(right: 30.0), + child: Row( + children: [ + Icon( + Icons.favorite_border, + size: 25.0, + color: Colors.white, + ), + Padding( + child: Icon( + Icons.refresh, + size: 25.0, + color: Colors.white, + ), + padding: new EdgeInsets.only(left: 20.0), + ), + ], + )), + ], + pinned: true, + flexibleSpace: FlexibleSpaceBar( + centerTitle: true, + title: new Shimmer.fromColors( + direction: ShimmerDirection.ltr, + period: new Duration(milliseconds:3000), + baseColor: Colors.white, + highlightColor: Colors.grey, + child: Text( + "王者:冰与火之歌", + style: TextStyle( + color: Colors.white, + fontSize: 14.0, + ), + ), + ), + background: Container( + decoration: new BoxDecoration( + image: new DecorationImage( + fit: BoxFit.cover, + image: new NetworkImage(imagePath), + )), + child: Container( + child: new BackdropFilter( + filter: + new ui.ImageFilter.blur(sigmaX: 13.0, sigmaY: 13.0), + child: new Container( + color: Colors.blue.withOpacity(0.06), + padding: const EdgeInsets.only(top: 30.0, left: 17.0), + width: 90.0, + height: 90.0, + child: new Container( + margin: EdgeInsets.only(top: 40.0), + alignment: Alignment.topLeft, + child: Hero( + tag: Tag, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Image.network( + imagePath, + height: 190.0, + width: 140.0, + fit: BoxFit.cover, + ), + new Padding( + padding: new EdgeInsets.only(left: 20.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Padding( + padding: + new EdgeInsets.only(top: 5.0), + child: Text( + '美国/权利游戏', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w400, + color: Colors.white, + letterSpacing: 1.0), + ), + ), + Padding( + padding: + new EdgeInsets.only(top: 5.0), + child: Text( + '2018/119分钟', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w400, + color: Colors.white), + ), + ), + Padding( + padding: + new EdgeInsets.only(top: 5.0), + child: Text( + 'BD1280高清中文字幕', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w400, + color: Colors.white), + ), + ), + Padding( + padding: + new EdgeInsets.only(top: 5.0), + child: Text( + '4次浏览', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w400, + color: Colors.white), + ), + ), + ], + ), + ), + ], + )), + ), + ), + ), + ), + ), + ), + ), + SliverPersistentHeader( + pinned: true, + delegate: _SliverAppBarDelegate( + TabBar( + controller: new TabController(length: 2, vsync: this), + labelColor: Colors.teal, + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.teal, + labelStyle: TextStyle(fontWeight: FontWeight.w100), + tabs: [ + Tab(text: "播放列表"), + Tab(text: "视频介绍"), + ], + ), + ), + ) + ]; + }, + body: Container( + color: Colors.white, + child: Container( + child: new ListView.builder( + itemBuilder: (BuildContext context, int index) => + new EntryItem(data[index], listData[index]), + itemCount: data.length, + ), + ), + ), + ), + ); + } +} + +class EntryItem extends StatefulWidget { + const EntryItem(this.entry, this.listItem); + + final ListItem listItem; + final Entry entry; + + @override + State createState() { + return EntryItemState(this.listItem, this.entry); + } +} + +class EntryItemState extends State { + var demonPlugin = new MethodChannel('demo.plugin'); + ListItem listItem; + Entry entry; + var colortitle = false; + + EntryItemState(this.listItem, this.entry); + + Widget _buildTiles(Entry root) { + if (root.children.isEmpty) + return new ListTile( + leading: InkWell( + onTap: () { + demonPlugin.invokeMethod( + 'http://jzvd.nathen.cn/d525f756aabf4b0588c2152fb94e07f5/d9f59bef829a472a9ca066620d9b871a-5287d2089db37e62345123a1be272f8b.mp4'); + }, + child: Padding( + padding: new EdgeInsets.only(left: 20.0), + child: new Icon( + Icons.play_circle_outline, + color: Colors.black, + size: 23.0, + ), + ), + ), + title: new Text( + root.title, + style: TextStyle(fontSize: 15.0), + ), + ); + return new ExpansionTile( + onExpansionChanged: (exple) { + colortitle = exple; + setState(() { + print(exple); + }); + }, + key: new PageStorageKey(root), + leading: new Icon( + listItem.iconData, + color: listItem.colors, + size: 30.0, + ), + title: new Text( + root.title, + style: TextStyle(color: colortitle ? Colors.blue : Colors.black), + ), + children: root.children.map(_buildTiles).toList(), + ); + } + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + return _buildTiles(entry); + } +} + +class ListItem { + final String title; + final IconData iconData; + final Color colors; + + ListItem(this.title, this.iconData, this.colors); +} + +class ListItemWidget extends StatelessWidget { + final ListItem listItem; + + ListItemWidget(this.listItem); + + @override + Widget build(BuildContext context) { + return new InkWell( + child: new ListTile( + leading: new Icon( + listItem.iconData, + color: listItem.colors, + ), + title: new Text(listItem.title), + ), + onTap: () {}, + ); + } +} + +class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { + _SliverAppBarDelegate(this._tabBar); + + final TabBar _tabBar; + + @override + double get minExtent => _tabBar.preferredSize.height; + + @override + double get maxExtent => _tabBar.preferredSize.height; + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return new Container( + color: Colors.white, + child: _tabBar, + ); + } + + @override + bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { + return false; + } +} diff --git a/lib/test/TitleBar.dart b/lib/test/TitleBar.dart new file mode 100644 index 0000000..532d855 --- /dev/null +++ b/lib/test/TitleBar.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; + +class CustomTitleBar extends StatefulWidget { + final Key key; + final double height; + final CustomTitleBarController controller; + final GestureTapCallback onMenuTap; + final GestureTapCallback onMessageTap; + + CustomTitleBar({ + this.onMenuTap, + this.onMessageTap, + this.controller, + this.height: 80.0, + this.key + }) :super(key: key); + + @override + State createState() { + // TODO: implement createState + return new CustomTitleBarState(); + } +} + +class CustomTitleBarState extends State { + TextEditingController _textController = new TextEditingController(); + CustomTitleBarController _controller; + + Widget _buildSearch() { + Widget titleItem = null; + titleItem = new Container( + height: 80.0, + alignment: Alignment.center, + child: new Padding( + padding: new EdgeInsets.only(top: 0.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Padding(padding: new EdgeInsets.only(left: 1.0)), + new Container( + height: 35.0, + width: 200.0, + child: new Material( + color: Colors.white70, + borderRadius: new BorderRadius.horizontal( + left: new Radius.circular(20.0), + right: new Radius.circular(20.0)), + child: new Padding( + padding: new EdgeInsets.only(right: 5.0), + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.only(left: 5.0)), + new Icon( + Icons.search, + color: const Color(0xFF616161)), + new Padding( + padding: new EdgeInsets.only(left: 3.0)), + new Flexible(child: new TextField( + maxLines: 1, + controller: _textController, + onChanged: (v) { +// _handleOnSeachChange(); + }, + onSubmitted: (v) { +// _handleOnSeachChange(); + }, + style: new TextStyle( + color: const Color(0xFF616161), + fontSize: 14.0), + decoration: new InputDecoration.collapsed( + hintText: "请输入关键字"), + ), + ), + ], + ),) + ), + ), + new Padding(padding: new EdgeInsets.only(left: 1.0)), + ], + ),), + ); + return titleItem; + } + + _buildTitle() { + Widget mWidget = null; + mWidget = new Container( + height: widget.height, + color: new Color.fromARGB(_controller.value.alpha, 25, 112, 183), + child: new Padding(padding: new EdgeInsets.only(top: 25.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Padding(padding: new EdgeInsets.only(right: 5.0)), + + new GestureDetector( + onTap: widget.onMenuTap==null?(){}: widget.onMenuTap, + child: new InkWell( + child: new Icon( + Icons.format_list_bulleted, color: Colors.white), + ), + ), + _buildSearch(), + new GestureDetector( + onTap: widget.onMessageTap==null?(){}: widget.onMessageTap, + child: new InkWell( + + child: new Icon(Icons.message, color: Colors.white), + ), + ), + new Padding(padding: new EdgeInsets.only(right: 5.0)), + ], + ),), + ); + return mWidget; + } + + + @override + Widget build(BuildContext context) { + if (widget.controller == null) { + _controller = new CustomTitleBarController(); + _controller.value.alpha = 0; + } else { + _controller = widget.controller; + } + return _buildTitle(); + } +} + + +class CustomTitleBarController extends ValueNotifier { + CustomTitleBarController() :super(new ContomTitleAlphaValue()); +} + +class ContomTitleAlphaValue { + int alpha; +} \ No newline at end of file diff --git a/lib/test/WrapTest.dart b/lib/test/WrapTest.dart new file mode 100644 index 0000000..2cce845 --- /dev/null +++ b/lib/test/WrapTest.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; + +void main() { + runApp(new MaterialApp( + title: '', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new WrapTest(), + )); +} + +class WrapTest extends StatefulWidget { + @override + _State createState() => new _State(); +} + +class _State extends State { + List mList; + List boshlit = new List(); + + @override + void initState() { + boshlit.add( + new BoxShadow(offset: Offset(0.0, 0.0), color: Colors.redAccent), + ); + mList = new List(); + for (var i = 0; i < 14; i++) { + mList.add( + new Container( + child: new Row( + children: [ + Icon( + Icons.important_devices, + size: 15.0, + ), + Text('五牛') + ], + ), + ), + ); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(''), + ), + /* Wrap({ + Key key, + this.direction = Axis.horizontal, + this.alignment = WrapAlignment.start, + this.spacing = 0.0, + this.runAlignment = WrapAlignment.start, + this.runSpacing = 0.0, + this.crossAxisAlignment = WrapCrossAlignment.start, + this.textDirection, + this.verticalDirection = VerticalDirection.down, + List children = const [], + }) : super(key: key, children: children);*/ + body: Wrap( + children: List.generate( + 20, + (i) => Container( + margin: new EdgeInsets.all(10.0), + decoration: BoxDecoration( + /**/ + + // boxShadow: boshlit, + color: Color(0xFFEEEEEE), + border: Border( + left: BorderSide( + color:Color(0xFFE0F7FA), width: 11.9), + right: BorderSide( + color:Color(0xFFE0F7FA), width: 11.9)), + ), + child: ListTile( + contentPadding: new EdgeInsets.all(10.9), + leading: Icon(Icons.important_devices), + title: Text('haha'), + )), + ), + )); + } +} diff --git a/lib/test/aaa.dart b/lib/test/aaa.dart new file mode 100644 index 0000000..134dba2 --- /dev/null +++ b/lib/test/aaa.dart @@ -0,0 +1,337 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/test/CountButtonView.dart'; +import 'package:flutter_app/test/DishesList.dart'; + + + +typedef void IndexSelectCallBack(int index); + +class OrderPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('OrderPage'), + ), + body: OrderPageContent(), + ); + } +} + +class OrderPageContent extends StatefulWidget { + @override + OrderPageContentState createState() => new OrderPageContentState(); +} + +class OrderPageContentState extends State { + final typeListController = ScrollController(); + final orderListController = ScrollController(); + int selectedIndex; + bool scrollingOrderList = false; + @override + void initState() { + super.initState(); + selectedIndex = 0; + orderListController.addListener(() { + double offset = orderListController.offset; + if (scrollingOrderList) { + return; + } + if (selectedIndex > 0 && offset < 260.0 * 3) { + //菜单列表滚动,更新菜类选中,待定制tableview做好以后,需要优化 + setState(() { + selectedIndex = 0; + }); + } else if (selectedIndex == 0 && offset >= 260.0 * 3) { + setState(() { + selectedIndex = 1; + }); + } + }); + } + + @override + void dispose() { + typeListController.dispose(); + orderListController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 100.0, + child: Container( + color: Colors.blue, + child: TypeList( + controller: typeListController, + selectedIndex: selectedIndex, + indexSelected: (index) { + scrollingOrderList = true; + setState(() { + selectedIndex = index; + orderListController + .animateTo(index * 260.0 * 3, + duration: Duration(milliseconds: 200), curve: Curves.easeInOut) + .then((a) { + scrollingOrderList = false; + }); + }); + }, + ), + ), + ), + Expanded( + child: OrderList( + controller: orderListController, + )), + ], + ); + } +} + +class TypeList extends StatefulWidget { + TypeList({this.controller, this.indexSelected, this.selectedIndex = 0}); + final controller; + final selectedIndex; + final IndexSelectCallBack indexSelected; + @override + TypeListState createState() => new TypeListState(); +} + +class TypeListState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ListView.builder(itemBuilder: (context, index) { + String title = typeAtIndex(index); + if (title == null) { + return null; + } + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 60.0, + color: index == widget.selectedIndex ? Colors.white : Colors.grey, + child: FlatButton( + padding: EdgeInsets.zero, + onPressed: () { + widget.indexSelected(index); + }, + child: Center( + child: Text(title), + )), + ), + Container( + height: 1.0, + color: Colors.grey, + ) + ], + ); + }); + } +} + +class OrderList extends StatefulWidget { + OrderList({this.controller}); + final controller; + @override + OrderListState createState() => new OrderListState(); +} + +class OrderListState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + void cellSelected(BuildContext context, Dish dish) { + print('selected ${dish.name}'); + showDialog( + context: context, + builder: (context) { + return Theme( + data: Theme.of(context), + child: Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: Container( + color: Colors.grey.shade100, + width: 300.0, + height: 350.0, + child: SingleChildScrollView( + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Container( + width: 300.0, + height: 200.0, + child: _buildImage(dish), + ), + _buildPopupFooter(dish) + ]), + )), + )), + ); + }); + } + + Widget _buildPopupFooter(Dish dish) { + return Container( +// height: 120.0, + padding: EdgeInsets.all(10.0), + color: Colors.grey.shade100, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleRow(dish), + Container( + color: Colors.transparent, + height: 5.0, + ), + Text( + dish.desc, + softWrap: true, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.normal, + fontSize: 15.0, + decoration: TextDecoration.none), + ), + ], + ), + ); + } + + Widget _buildImage(Dish dish) { + return Stack( + fit: StackFit.expand, +// alignment: Alignment.center, + children: [ + Image.network( + dish.imgUrl, + fit: BoxFit.cover, + ), + Positioned( + right: 8.0, + bottom: 8.0, + child: CountButtonView( + initialCount: orderedCountForDish(dish), + onChange: (count) { + orderDish(dish, count); + }, + )), + ], + ); + } + + Widget _buildTitleRow(Dish dish) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + dish.name, + style: TextStyle(color: Colors.black, fontSize: 19.0, decoration: TextDecoration.none), + ), + Text( + '¥${dish.price } / ${dish.unit}', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.w800, + fontSize: 19.0, + decoration: TextDecoration.none), + ) + ], + ); + } + + Widget _buildCellFooter(Dish dish) { + return Container( + height: 90.0, + padding: EdgeInsets.all(10.0), + color: Colors.grey.shade100, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitleRow(dish), + Text( + dish.desc, + maxLines: 2, + softWrap: true, + ), + ], + ), + ); + } + + Widget _buildCell(BuildContext context, int index) { + Dish dish = dishAtIndex(index); + if (dish == null) { + return null; + } + return Center( + child: FlatButton( + onPressed: () { + cellSelected(context, dish); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: SizedBox( + width: 250.0, + height: 250.0, + child: Column( + children: [ + Container( + width: 250.0, + height: 160.0, + child: _buildImage(dish), + ), + _buildCellFooter(dish) + ], + ), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + child: ListView.builder( + controller: this.widget.controller, + itemBuilder: (context, index) { + if (index % 2 == 0) { + return _buildCell(context, index ~/ 2); + } else { + return Container( + height: 10.0, + color: Colors.transparent, + ); + } + }), + ); + } +} \ No newline at end of file diff --git a/lib/test/animal3d.dart b/lib/test/animal3d.dart new file mode 100644 index 0000000..1e51764 --- /dev/null +++ b/lib/test/animal3d.dart @@ -0,0 +1,425 @@ +import 'package:flutter/material.dart'; +import 'dart:math' as math; +import 'dart:async'; + +void main() => runApp(new MyApp()); + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Flutter Demo', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new MyHomePage(title: 'Flip Animation'), + ); + } +} + +class MyHomePage extends StatelessWidget { + final digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]; + final String title; + + MyHomePage({this.title}); + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(title), + ), + body: new Center( + child: FlipPanel.builder( + itemBuilder: (context, index) => Container( + alignment: Alignment.center, + width: 96.0, + height: 128.0, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '${digits[index]}', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 80.0, + color: Colors.yellow), + ), + ), + itemsCount: digits.length, + period: Duration(milliseconds: 1000), + loop: -1, + ), + ), + ); + } +} + +/// Signature for a function that creates a widget for a given index, e.g., in a +/// list. +typedef Widget IndexedItemBuilder(BuildContext, int); + +/// Signature for a function that creates a widget for a value emitted from a [Stream] +typedef Widget StreamItemBuilder(BuildContext, T); + +/// A widget for flip panel with built-in animation +/// Content of the panel is built from [IndexedItemBuilder] or [StreamItemBuilder] +/// +/// Note: the content size should be equal + +enum FlipDirection { up, down } + +class FlipPanel extends StatefulWidget { + final IndexedItemBuilder indexedItemBuilder; + final StreamItemBuilder streamItemBuilder; + final Stream itemStream; + final int itemsCount; + final Duration period; + final Duration duration; + final int loop; + final int startIndex; + final T initValue; + final double spacing; + final FlipDirection direction; + + FlipPanel({ + Key key, + this.indexedItemBuilder, + this.streamItemBuilder, + this.itemStream, + this.itemsCount, + this.period, + this.duration, + this.loop, + this.startIndex, + this.initValue, + this.spacing, + this.direction, + }) : super(key: key); + + /// Create a flip panel from iterable source + /// [itemBuilder] is called periodically in each time of [period] + /// The animation is looped in [loop] times before finished. + /// Setting [loop] to -1 makes flip animation run forever. + /// The [period] should be two times greater than [duration] of flip animation, + /// if not the animation becomes jerky/stuttery. + FlipPanel.builder({ + Key key, + @required IndexedItemBuilder itemBuilder, + @required this.itemsCount, + @required this.period, + this.duration = const Duration(milliseconds: 500), + this.loop = 1, + this.startIndex = 0, + this.spacing = 0.5, + this.direction = FlipDirection.up, + }) : assert(itemBuilder != null), + assert(itemsCount != null), + assert(startIndex < itemsCount), + assert(period == null || + period.inMilliseconds >= 2 * duration.inMilliseconds), + indexedItemBuilder = itemBuilder, + streamItemBuilder = null, + itemStream = null, + initValue = null, + super(key: key); + + /// Create a flip panel from stream source + /// [itemBuilder] is called whenever a new value is emitted from [itemStream] + FlipPanel.stream({ + Key key, + @required this.itemStream, + @required StreamItemBuilder itemBuilder, + this.initValue, + this.duration = const Duration(milliseconds: 500), + this.spacing = 0.5, + this.direction = FlipDirection.up, + }) : assert(itemStream != null), + indexedItemBuilder = null, + streamItemBuilder = itemBuilder, + itemsCount = 0, + period = null, + loop = 0, + startIndex = 0, + super(key: key); + + @override + _FlipPanelState createState() => _FlipPanelState(); +} + +class _FlipPanelState extends State + with TickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + int _currentIndex; + bool _isReversePhase; + bool _isStreamMode; + bool _running; + final _perspective = 0.003; + final _zeroAngle = 0.0001; // There's something wrong in the perspective transform, I use a very small value instead of zero to temporarily get it around. + int _loop; + T _currentValue, _nextValue; + Timer _timer; + StreamSubscription _subscription; + + Widget _child1, _child2; + Widget _upperChild1, _upperChild2; + Widget _lowerChild1, _lowerChild2; + + @override + void initState() { + super.initState(); + _currentIndex = widget.startIndex; + _isStreamMode = widget.itemStream != null; + _isReversePhase = false; + _running = false; + _loop = 0; + + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _isReversePhase = true; + _controller.reverse(); + } + if (status == AnimationStatus.dismissed) { + _currentValue = _nextValue; + _running = false; + } + }) + ..addListener(() { + setState(() { + _running = true; + }); + }); + _animation = Tween(begin: _zeroAngle, end: math.pi / 2).animate(_controller); + + if (widget.period != null) { + _timer = Timer.periodic(widget.period, (_) { + if (widget.loop < 0 || _loop < widget.loop) { + if (_currentIndex + 1 == widget.itemsCount - 2) { + _loop++; + } + _currentIndex = (_currentIndex + 1) % widget.itemsCount; + _child1 = null; + _isReversePhase = false; + _controller.forward(); + } else { + _timer.cancel(); + _currentIndex = (_currentIndex + 1) % widget.itemsCount; + setState(() { + _running = false; + }); + } + }); + } + + if (_isStreamMode) { + _currentValue = widget.initValue; + _subscription = widget.itemStream.distinct().listen((value) { + if (_currentValue == null) { + _currentValue = value; + } else if (value != _currentValue) { + _nextValue = value; + _child1 = null; + _isReversePhase = false; + _controller.forward(); + } + }); + } else if (widget.loop < 0 || _loop < widget.loop) { + _controller.forward(); + } + } + + @override + void dispose() { + _controller.dispose(); + if (_subscription != null) _subscription.cancel(); + if (_timer != null) _timer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _buildChildWidgetsIfNeed(context); + + return _buildPanel(); + } + + void _buildChildWidgetsIfNeed(BuildContext context) { + Widget makeUpperClip(Widget widget) { + return ClipRect( + child: Align( + alignment: Alignment.topCenter, + heightFactor: 0.5, + child: widget, + ), + ); + } + + Widget makeLowerClip(Widget widget) { + return ClipRect( + child: Align( + alignment: Alignment.bottomCenter, + heightFactor: 0.5, + child: widget, + ), + ); + } + + if (_running) { + if (_child1 == null) { + _child1 = _child2 != null + ? _child2 + : _isStreamMode + ? widget.streamItemBuilder(context, _currentValue) + : widget.indexedItemBuilder( + context, _currentIndex % widget.itemsCount); + _child2 = null; + _upperChild1 = + _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); + _lowerChild1 = + _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); + } + if (_child2 == null) { + _child2 = _isStreamMode + ? widget.streamItemBuilder(context, _nextValue) + : widget.indexedItemBuilder( + context, (_currentIndex + 1) % widget.itemsCount); + _upperChild2 = makeUpperClip(_child2); + _lowerChild2 = makeLowerClip(_child2); + } + } else { + _child1 = _child2 != null + ? _child2 + : _isStreamMode + ? widget.streamItemBuilder(context, _currentValue) + : widget.indexedItemBuilder( + context, _currentIndex % widget.itemsCount); + _upperChild1 = + _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); + _lowerChild1 = + _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); + } + } + + Widget _buildUpperFlipPanel() => widget.direction == FlipDirection.up + ? Stack( + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild1 + ), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? _animation.value : math.pi / 2), + child: _upperChild2, + ), + ], + ) + : Stack( + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild2 + ), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? math.pi / 2 : _animation.value), + child: _upperChild1, + ), + ], + ); + + Widget _buildLowerFlipPanel() => widget.direction == FlipDirection.up + ? Stack( + children: [ + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild2 + ), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? math.pi / 2 : -_animation.value), + child: _lowerChild1, + ) + ], + ) + : Stack( + children: [ + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild1 + ), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? -_animation.value : math.pi / 2), + child: _lowerChild2, + ) + ], + ); + + Widget _buildPanel() { + return _running + ? Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildUpperFlipPanel(), + Padding( + padding: EdgeInsets.only(top: widget.spacing), + ), + _buildLowerFlipPanel(), + ], + ) + : _isStreamMode && _currentValue == null + ? Container() + : Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild1 + ), + Padding( + padding: EdgeInsets.only(top: widget.spacing), + ), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild1 + ) + ], + ); + } +} \ No newline at end of file diff --git a/lib/test/mohu.dart b/lib/test/mohu.dart new file mode 100644 index 0000000..aaacac6 --- /dev/null +++ b/lib/test/mohu.dart @@ -0,0 +1,193 @@ +import 'package:flutter/material.dart'; +import 'dart:core'; +import 'dart:ui' as ui; + +import 'package:flutter/rendering.dart'; + +/// 一个BackdropFilter模糊的例子,指出了BackdropFilter不能适配非矩形区域模糊效果的BUG +/// +/// 此文件在本项目中未被使用 +/// 保留此文件做学习用 +/// + +/// 运行请取消此注释 + void main() { + runApp(new MaterialApp( + home: new AppH(), + )); + } + +class AppH extends StatefulWidget { + _HomePageState createState() => new _HomePageState(); +} + +class _HomePageState extends State { + double _sigma = 3.0; + double _opacity = 0.5; + bool _showText = true; + BoxShape _innerClip; + BoxShape _outerClip; + + @override + Widget build(BuildContext context) { + Widget test = new BackdropFilter( + filter: new ui.ImageFilter.blur(sigmaX: _sigma, sigmaY: _sigma), + child: new Container( + color: Colors.blue.withOpacity(_opacity), + padding: const EdgeInsets.all(30.0), + // decoration: BoxDecoration( + // color: Colors.blue.withOpacity(_opacity), + // shape: BoxShape.circle, + // ), + width: 90.0, + height: 90.0, + child: new Center( + child: _showText ? new Text('Test') : null, + ), + ), + ); + switch (_innerClip) { + case BoxShape.circle: + test = new ClipOval( + child: test, + ); + break; + case BoxShape.rectangle: + test = new ClipRRect( + borderRadius: new BorderRadius.all(new Radius.circular(4.0)), + child: test, + ); + break; + } + test = new Container( + decoration: new BoxDecoration( + color: Colors.grey.shade200.withOpacity(_opacity), + ), + padding: new EdgeInsets.all(30.0), + child: test, + ); + switch (_outerClip) { + case BoxShape.circle: + test = new ClipOval(child: test); + break; + case BoxShape.rectangle: + test = new ClipRect(child: test); + break; + } + test = new Container( + height: 200.0, + margin: new EdgeInsets.all(10.0), + decoration: new BoxDecoration( + image: new DecorationImage( + fit: BoxFit.cover, + image: new NetworkImage( + 'http://www.powerpointhintergrund.com/uploads/abstract-pattern-background-0.jpeg'), + )), + child: new Center( + child: test, + ), + ); + return new Scaffold( + appBar: new AppBar( + title: new Text('BackdropFilter Test'), + ), + body: new Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + test, + new Expanded( + child: new ListView( + children: [ + new ListTile( + title: new Text('Sigma'), + subtitle: new Slider( + min: 0.0, + max: 50.0, + value: _sigma, + onChanged: (double value) { + setState(() { + _sigma = value; + }); + }, + ), + ), + new ListTile( + title: new Text('Opacity'), + subtitle: new Slider( + min: 0.0, + max: 1.0, + value: _opacity, + onChanged: (double value) { + setState(() { + _opacity = value; + }); + }, + ), + ), + new CheckboxListTile( + value: _showText, + onChanged: (bool value) { + setState(() { + _showText = value; + }); + }, + title: new Text('Show text'), + ), + new ListTile( + title: new Text('Inner clip'), + subtitle: new DropdownButton( + onChanged: (BoxShape value) { + setState(() { + _innerClip = value; + }); + }, + value: _innerClip, + items: >[ + new DropdownMenuItem( + value: null, + child: new Text('None'), + ), + new DropdownMenuItem( + value: BoxShape.circle, + child: new Text('ClipOval'), + ), + new DropdownMenuItem( + value: BoxShape.rectangle, + child: new Text('ClipRect'), + ), + ], + ), + ), + new ListTile( + title: new Text('Outer clip'), + subtitle: new DropdownButton( + onChanged: (BoxShape value) { + setState(() { + _outerClip = value; + }); + }, + value: _outerClip, + items: >[ + new DropdownMenuItem( + value: null, + child: new Text('None'), + ), + new DropdownMenuItem( + value: BoxShape.circle, + child: new Text('ClipOval'), + ), + new DropdownMenuItem( + value: BoxShape.rectangle, + child: new Text('ClipRect'), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/test/testcoum.dart b/lib/test/testcoum.dart new file mode 100644 index 0000000..cf3abcd --- /dev/null +++ b/lib/test/testcoum.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(new MaterialApp( + title: '', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new CoumLum(), + )); +} + +class CoumLum extends StatefulWidget { + @override + _State createState() => new _State(); +} + +class _State extends State { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(''), + ), + body: Container( + alignment: Alignment.centerLeft, + height:150.0, + child: Card( + margin: new EdgeInsets.all(10.0), + color: Colors.white, + elevation: 2.0, + child: new Row( + mainAxisAlignment:MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment:CrossAxisAlignment.center, + children: [ + Padding(padding: new EdgeInsets.only(top:30.0,left:30.0),child:Text('title',style: TextStyle(color: Colors.redAccent,fontSize:27.0),) ,), + Padding(padding: new EdgeInsets.only(top:10.0,left:30.0),child:Text('subject') ,), + ], + ), + Padding(padding: new EdgeInsets.only(top:16.0,left:60.0,bottom:50.0,right:10.0),child:Image.network( + 'https://avatar-static.segmentfault.com/168/531/1685319841-58d33ed24b9ce_big64',width:65.0,height:65.0,),), + + ], + ), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 1ca026b..7cd87bc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,69 +1,55 @@ # Generated by pub -# See https://www.dartlang.org/tools/pub/glossary#lockfile +# See https://dart.dev/tools/pub/glossary#lockfile packages: - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.31.2-alpha.2" - args: - dependency: transitive - description: - name: args - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.3" async: dependency: transitive description: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.7" + version: "2.2.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.3" + version: "1.0.4" cached_network_image: dependency: "direct main" description: name: cached_network_image url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.1" + version: "0.6.0" charcode: dependency: transitive description: name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.1" + version: "1.1.2" charts_common: dependency: transitive description: name: charts_common url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.0" + version: "0.4.0" charts_flutter: dependency: "direct main" description: name: charts_flutter url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.0" + version: "0.4.0" collection: dependency: "direct main" description: name: collection url: "https://pub.flutter-io.cn" source: hosted - version: "1.14.6" + version: "1.14.11" connectivity: dependency: "direct main" description: @@ -77,21 +63,14 @@ packages: name: convert url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.1.1" crypto: dependency: transitive description: name: crypto url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.5" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.14.4" + version: "2.0.6" cupertino_icons: dependency: "direct main" description: @@ -112,7 +91,7 @@ packages: name: english_words url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.0" + version: "3.1.5" flutter: dependency: "direct main" description: flutter @@ -124,325 +103,213 @@ packages: name: flutter_cache_manager url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.1" + version: "0.3.2" + flutter_page_indicator: + dependency: transitive + description: + name: flutter_page_indicator + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.3" + flutter_slidable: + dependency: "direct main" + description: + name: flutter_slidable + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.9" flutter_staggered_grid_view: dependency: "direct main" description: name: flutter_staggered_grid_view url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.2" + version: "0.2.7" flutter_swiper: dependency: "direct main" description: name: flutter_swiper url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.2" + version: "1.1.5" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - front_end: - dependency: transitive - description: - name: front_end - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.1.0-alpha.12" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.5" - html: - dependency: transitive + fluttertoast: + dependency: "direct main" description: - name: html + name: fluttertoast url: "https://pub.flutter-io.cn" source: hosted - version: "0.13.3+1" + version: "3.0.3" http: dependency: "direct main" description: name: http url: "https://pub.flutter-io.cn" source: hosted - version: "0.11.3+16" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.5" + version: "0.12.0+1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.2" + version: "3.1.3" image_picker: dependency: "direct main" description: name: image_picker url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.5" + version: "0.4.12+1" intl: dependency: "direct main" description: name: intl url: "https://pub.flutter-io.cn" source: hosted - version: "0.15.6" - io: - dependency: transitive - description: - name: io - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.2+1" - js: - dependency: transitive - description: - name: js - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.6.1" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.8" - kernel: - dependency: transitive - description: - name: kernel - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.0-alpha.12" + version: "0.15.7" logging: dependency: transitive description: name: logging url: "https://pub.flutter-io.cn" source: hosted - version: "0.11.3+1" + version: "0.11.3+2" matcher: dependency: transitive description: name: matcher url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.2" + version: "0.12.5" meta: dependency: transitive description: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.5" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.6+1" - multi_server_socket: - dependency: transitive - description: - name: multi_server_socket - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.1" - node_preamble: - dependency: transitive - description: - name: node_preamble - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.2" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.3" - package_resolver: - dependency: transitive - description: - name: package_resolver - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.3" + version: "1.1.6" path: dependency: transitive description: name: path url: "https://pub.flutter-io.cn" source: hosted - version: "1.6.1" + version: "1.6.2" path_provider: - dependency: "direct main" - description: - name: path_provider - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.4.1" - plugin: - dependency: transitive - description: - name: plugin - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.0+2" - pool: dependency: transitive description: - name: pool + name: path_provider url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.5" - pub_semver: + version: "0.5.0+1" + pedantic: dependency: transitive description: - name: pub_semver + name: pedantic url: "https://pub.flutter-io.cn" source: hosted - version: "1.4.1" + version: "1.7.0" pull_to_refresh: dependency: "direct main" description: name: pull_to_refresh url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.5" + version: "1.1.6" quiver: dependency: transitive description: name: quiver url: "https://pub.flutter-io.cn" source: hosted - version: "0.29.0+1" + version: "2.0.3" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.2" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.7.3+1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.3" - shelf_static: - dependency: transitive - description: - name: shelf_static - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.7+1" - shelf_web_socket: - dependency: transitive + version: "0.4.3" + shimmer: + dependency: "direct main" description: - name: shelf_web_socket + name: shimmer url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.2+2" + version: "0.0.6" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.4" - source_maps: - dependency: transitive - description: - name: source_maps - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.10.5" source_span: dependency: transitive description: name: source_span url: "https://pub.flutter-io.cn" source: hosted - version: "1.4.0" + version: "1.5.5" sqflite: dependency: "direct main" description: name: sqflite url: "https://pub.flutter-io.cn" source: hosted - version: "0.11.0+1" + version: "1.1.3" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.flutter-io.cn" source: hosted - version: "1.9.2" + version: "1.9.3" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.flutter-io.cn" source: hosted - version: "1.6.7+1" + version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.2" + version: "1.0.4" synchronized: dependency: transitive description: name: synchronized url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.0+1" + version: "2.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" - test: + version: "1.1.0" + test_api: dependency: transitive description: - name: test + name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.41" + version: "0.2.5" + transformer_page_view: + dependency: transitive + description: + name: transformer_page_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.5" transparent_image: dependency: "direct main" description: @@ -456,28 +323,21 @@ packages: name: typed_data url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.5" - utf: - dependency: transitive - description: - name: utf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.0+4" + version: "1.1.6" uuid: dependency: transitive description: name: uuid url: "https://pub.flutter-io.cn" source: hosted - version: "0.5.3" + version: "2.0.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.6" + version: "2.0.8" video_player: dependency: "direct main" description: @@ -485,34 +345,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.6.1" - vm_service_client: - dependency: transitive - description: - name: vm_service_client - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.4+3" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.7+8" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.8" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.1.14" sdks: - dart: ">=2.0.0-dev.62.0 <=2.0.0-dev.63.0.flutter-4c9689c1d2" - flutter: ">=0.2.5 <2.0.0" + dart: ">=2.2.2 <3.0.0" + flutter: ">=1.2.1 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b998099..1497aa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,22 +9,25 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 english_words: ^3.1.0 - http: ^0.11.3+16 + http: ^0.12.0+1 image_picker: "^0.4.5" shared_preferences: "^0.4.2" transparent_image: "^0.1.0" flutter_swiper : "^1.0.2" - charts_flutter: "^0.3.0" - path_provider: "^0.4.1" - cached_network_image: "0.4.1" - sqflite: "^0.11.0+1" - pull_to_refresh: "^1.1.5" + charts_flutter: "^0.4.0" + cached_network_image: "0.6.0" + sqflite: ^1.1.0 + pull_to_refresh: ^1.1.6 video_player: "0.6.1" - collection: 1.14.6 + collection: 1.14.11 device_info: 0.2.1 - intl: 0.15.6 + intl: 0.15.7 connectivity: 0.3.1 + fluttertoast: ^3.0.0 + shimmer: ^0.0.4 flutter_staggered_grid_view: + flutter_slidable: "^0.4.9" + dev_dependencies: flutter_test: @@ -41,82 +44,83 @@ flutter: # the material Icons class. uses-material-design: true assets: - - assets/NVpose1.obj - - assets/bb.obj - - images/lake.jpg - - images/long_wuman1.jpg - - images/pic1.jpg - - images/pic2.jpg - - images/pic3.jpg - - images/pic4.jpg - - images/pic5.jpg - - images/pic6.jpg - - images/pic7.jpg - - images/pic8.jpg - - images/pic9.jpg - - images/pic10.jpg - - images/pic11.jpg - - images/pic12.jpg - - images/pic13.jpg - - images/pic14.jpg - - images/pic15.jpg - - images/pic16.jpg - - images/pic17.jpg - - images/pic18.jpg - - images/pic19.jpg - - images/pic20.jpg - - images/pic21.jpg - - images/pic22.jpg - - images/pic23.jpg - - images/pic24.jpg - - images/pic25.jpg - - images/pic26.jpg - - images/pic27.jpg - - images/pic28.jpg - - images/pic29.jpg - - images/pic30.jpg - - images/longnv5.jpeg - - images/longwuman3.jpg - - images/lonnv6.jpg - - images/lonvn9.jpg - - images/lonnv8.jpg - - images/lonnv10.jpg - - images/haha.png - - images/row.png - - images/jpejej.png - - images/aaaaa.png - - images/app_background.png - - images/qq.png - - images/weixing.png - - images/backgroud.jpg - - images/backgroud2.jpg - - images/backgroud4.jpg - - images/backgroud6.jpg - - images/background1.jpg - - images/item1.png - - images/1.png - - images/2.png - - images/3.png - - images/4.png - - images/poster.png - - images/item1.png - - images/item2.png - - images/item3.png - - images/item4.png - - images/ellie.png - - images/eric.png - - images/jenny.png - - images/kevin.png - - images/louis.png - - images/banner.png - - images/header_my.png - - images/myheader.png - - images/my_header.png - - images/drawbg.png - - images/erweima.png - - images/lunch_yasuo.png - - images/bbbb.png - - images/wallfy.png + - assets/NVpose1.obj + - assets/bb.obj + - images/lake.jpg + - images/long_wuman1.jpg + - images/pic1.jpg + - images/pic2.jpg + - images/pic3.jpg + - images/pic4.jpg + - images/pic5.jpg + - images/pic6.jpg + - images/pic7.jpg + - images/pic8.jpg + - images/pic9.jpg + - images/pic10.jpg + - images/pic11.jpg + - images/pic12.jpg + - images/pic13.jpg + - images/pic14.jpg + - images/pic15.jpg + - images/pic16.jpg + - images/pic17.jpg + - images/pic18.jpg + - images/pic19.jpg + - images/pic20.jpg + - images/pic21.jpg + - images/pic22.jpg + - images/pic23.jpg + - images/pic24.jpg + - images/pic25.jpg + - images/pic26.jpg + - images/pic27.jpg + - images/pic28.jpg + - images/pic29.jpg + - images/pic30.jpg + - images/longnv5.jpeg + - images/longwuman3.jpg + - images/lonnv6.jpg + - images/lonvn9.jpg + - images/lonnv8.jpg + - images/lonnv10.jpg + - images/haha.png + - images/row.png + - images/jpejej.png + - images/aaaaa.png + - images/qq.png + - images/weixing.png + - images/backgroud.jpg + - images/backgroud2.jpg + - images/backgroud4.jpg + - images/backgroud6.jpg + - images/background1.jpg + - images/item1.png + - images/1.png + - images/2.png + - images/3.png + - images/4.png + - images/poster.png + - images/item1.png + - images/item2.png + - images/item3.png + - images/item4.png + - images/ellie.png + - images/eric.png + - images/jenny.png + - images/kevin.png + - images/louis.png + - images/banner.png + - images/header_my.png + - images/myheader.png + - images/my_header.png + - images/drawbg.png + - images/erweima.png + - images/lunch_yasuo.png + - images/bbbb.png + - images/wallfy.png + + # To add assets to your plugin package, add an assets section, like this: # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg