├── .flutter-plugins-dependencies
├── .gitignore
├── .metadata
├── .vscode
└── launch.json
├── README.md
├── android
├── app
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── easy_market
│ │ │ │ └── MainActivity.java
│ │ └── res
│ │ │ ├── drawable
│ │ │ ├── launch_background.xml
│ │ │ └── open.jpg
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ ├── network_security_config.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── key.properties
└── settings.gradle
├── assets
└── images
│ ├── address.png
│ ├── collect.png
│ ├── good.png
│ ├── hongbao.png
│ ├── huiyuan.png
│ ├── ic_tab_group_active.png
│ ├── ic_tab_group_normal.png
│ ├── ic_tab_home_active.png
│ ├── ic_tab_home_normal.png
│ ├── ic_tab_profile_active.png
│ ├── ic_tab_profile_normal.png
│ ├── ic_tab_shiji_active.png
│ ├── ic_tab_shiji_normal.png
│ ├── ic_tab_subject_active.png
│ ├── ic_tab_subject_normal.png
│ ├── issure.png
│ ├── kefu.png
│ ├── logout.png
│ ├── more.png
│ ├── openAd.jpg
│ ├── oppen.png
│ ├── order.png
│ ├── safe.png
│ ├── tab_cart_active.png
│ ├── tab_cart_default.png
│ ├── tab_copy_active.png
│ ├── tab_copy_default.png
│ ├── tab_home_active.png
│ ├── tab_home_default.png
│ ├── tab_mine_active.png
│ ├── tab_mine_default.png
│ ├── tab_sort_active.png
│ ├── tab_sort_default.png
│ ├── timg.jpg
│ └── week.png
├── imges
├── ad.png
├── brand.png
├── catalog.png
├── goodsDetail.png
├── goodsSize.png
├── home.png
├── login.png
├── mine.png
├── qrCode.png
├── sort.png
├── topic.png
└── topicDetail.png
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ ├── Flutter.podspec
│ ├── Release.xcconfig
│ └── flutter_export_environment.sh
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── lib
├── Advertisement
│ └── openAd.dart
├── api
│ └── index.dart
├── component
│ ├── SliverCustomHeader.dart
│ ├── bottom_sheet.dart
│ ├── count.dart
│ ├── linearBar.dart
│ ├── swiper.dart
│ ├── tab.dart
│ ├── tabAppBar.dart
│ └── verticalTab.dart
├── main.dart
├── model
│ └── index.dart
├── page
│ ├── app.dart
│ ├── cart
│ │ └── index.dart
│ ├── home
│ │ ├── index.dart
│ │ └── topic.dart
│ ├── index.dart
│ ├── mine
│ │ └── index.dart
│ ├── sort
│ │ └── index.dart
│ ├── topic
│ │ └── index.dart
│ └── wrapper.dart
├── router
│ ├── brand
│ │ └── index.dart
│ ├── catalog
│ │ ├── catalogGoods.dart
│ │ └── index.dart
│ ├── goodsDetail
│ │ └── index.dart
│ ├── index.dart
│ ├── login
│ │ └── index.dart
│ ├── moreComment
│ │ └── index.dart
│ ├── noFound.dart
│ ├── search
│ │ └── index.dart
│ ├── tipicDetail
│ │ └── index.dart
│ └── writeComment
│ │ └── index.dart
└── utils
│ ├── cache.dart
│ ├── help.dart
│ ├── http.dart
│ └── rem.dart
├── pubspec.lock
└── pubspec.yaml
/.flutter-plugins-dependencies:
--------------------------------------------------------------------------------
1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_webview_plugin","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.7/","dependencies":[]},{"name":"path_provider","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-0.4.3/","dependencies":[]},{"name":"sqflite","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/sqflite-1.3.1/","dependencies":[]}],"android":[{"name":"flutter_webview_plugin","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.7/","dependencies":[]},{"name":"path_provider","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-0.4.3/","dependencies":[]},{"name":"sqflite","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/sqflite-1.3.1/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_macos-0.0.4+3/","dependencies":[]},{"name":"sqflite","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/sqflite-1.3.1/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/peroluo/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-0.0.1+2/","dependencies":[]}],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_webview_plugin","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-08-03 17:03:07.842902","version":"1.17.5"}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 |
67 | # Exceptions to above rules.
68 | !**/ios/**/default.mode1v3
69 | !**/ios/**/default.mode2v3
70 | !**/ios/**/default.pbxuser
71 | !**/ios/**/default.perspectivev3
72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
73 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 20e59316b8b8474554b38493b8ca888794b0234a
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EasyMarketFlutter
2 |
3 | > 1、EasyMarketFlutter 是仿网易严选 设计的 App(商城类)。项目是基于 Flutter 框架的混合开发(Android 与 IOS)
4 | >
5 | > 2、EasyMarketFlutter 主要技术栈:provider(全局数据管理)、dio(数据请求)、shared_preferences(缓存)。
6 | >
7 | > 3、本项目主要是以学习 Flutter 框架为主,主要可学内容:UI 设计、组件封装、解决 Flutter 中遇到的坑。可能项目中有许多缺陷,希望吐槽,来不断完善。
8 |
9 | ## 扫码体验 Android 版(请在浏览器内扫码!)
10 |
11 |
12 |
13 |
14 |
15 | ## 预览
16 |
17 | |  |  |  |  |
18 | | ---------------------------- | ---------------------------- | -------------------------- | ---------------------- |
19 | |  |  |  |  |
20 | |  |  |  | |
21 |
22 | ## 已实现
23 |
24 | - Provider+shared_preferences 实现数据状态管理、缓存。
25 | - App 的启动页、广告页。
26 | - Rem 适配方案。
27 | - Dio 的二次封装,API 模块化。
28 | - 封装侧边栏 Tab 切换组件。
29 | - 封装 Appbar 与 Tab 的 AppbarTab 组件。
30 | - 封装滚动渐变的 Appbar 组件。
31 | - 下拉刷新与上拉加载更多。
32 | - 路由模块管理。
33 |
34 | ## 还需要做的事
35 |
36 | 1. 此项目还在开发中,后续会把业务补充完整。(商品、专题、制造商、购物车、用户信息管理)页面的完善。
37 | 2. 项目优化,从 UI 到性能分析,我也是 Flutter 的初学者,后续如果有学到好的方案,需迭代。
38 | 3. 尝试将部分模块以 WebView+H5 进行混合开发。
39 | 4. 后续会补充我在开发中遇到的问题,进行补充、和记录。
40 |
41 | ## 需注意的东西
42 |
43 | - 目前只提供了 android 的下载体验,IOS 请自行下载代码体验。
44 | - 在开发环境的 debug 可能会稍微卡顿,属正常现象,良好的体验请进行打 release 包。
45 |
46 | ## 友情链接
47 |
48 | 1. [Flutter 中文网](https://flutterchina.club/)
49 | 2. [Dart 从入门到放弃](http://dart.goodev.org/)
50 | 3. [Flutter 从入门到放弃](https://book.flutterchina.club/)
51 | 4. [Flutter-go](https://github.com/alibaba/flutter-go)
52 | 5. [Flutter 路由管理](https://github.com/theyakka/fluro)
53 | 6. [Flutter 很全的 Api 说明](https://github.com/yang7229693/flutter-study)
54 | 7. [我写的项目](https://github.com/Peroluo/easyMarketFlutter)
55 | 8. [常用的一些包](https://www.cnblogs.com/yangyxd/p/9232308.html)
56 | 9. [阿里巴巴 Flutter 代码规范](https://github.com/alibaba/flutter-go/blob/master/Flutter_Go%20%E4%BB%A3%E7%A0%81%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md)
57 |
58 | ## 最后
59 |
60 | - 如果 EasyMarketFlutter 对你有帮助,留下你的 Star 或者 fork,你的支持是我不断更新的动力!
61 | - 欢迎你们的 Issues,希望 Flutter 越来越好,大家一起学习!Love Coding!
62 | - Thanks!
63 |
64 | ## 关于我
65 |
66 | Name: pero 罗
67 |
68 | QQ: 1025558554
69 |
70 | Email:[1025558554@qq.com](mailto:1025558554@qq.com)
71 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 | def keystorePropertiesFile = rootProject.file("key.properties")
27 | def keystoreProperties = new Properties()
28 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
29 | android {
30 | compileSdkVersion 28
31 |
32 | lintOptions {
33 | disable 'InvalidPackage'
34 | }
35 |
36 | defaultConfig {
37 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
38 | applicationId "com.example.easy_market"
39 | minSdkVersion 16
40 | targetSdkVersion 28
41 | versionCode flutterVersionCode.toInteger()
42 | versionName flutterVersionName
43 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
44 | }
45 | signingConfigs {
46 | release {
47 | keyAlias keystoreProperties['keyAlias']
48 | keyPassword keystoreProperties['keyPassword']
49 | storeFile file("D:/Android_keystore/key.jks")
50 | storePassword keystoreProperties['storePassword']
51 | }
52 | }
53 | buildTypes {
54 | release {
55 | signingConfig signingConfigs.release
56 |
57 | // minifyEnabled true
58 | // useProguard true
59 |
60 | // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
61 | // TODO: Add your own signing config for the release build.
62 | // Signing with the debug keys for now, so `flutter run --release` works.
63 | // signingConfig signingConfigs.debug
64 | }
65 | }
66 | }
67 |
68 | flutter {
69 | source '../..'
70 | }
71 |
72 | dependencies {
73 | testImplementation 'junit:junit:4.12'
74 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
75 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
76 | }
77 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | #Flutter Wrapper
2 | -keep class io.flutter.app.** { *; }
3 | -keep class io.flutter.plugin.** { *; }
4 | -keep class io.flutter.util.** { *; }
5 | -keep class io.flutter.view.** { *; }
6 | -keep class io.flutter.** { *; }
7 | -keep class io.flutter.plugins.** { *; }
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
13 |
20 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/example/easy_market/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easy_market;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/open.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/drawable/open.jpg
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
3 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/key.properties:
--------------------------------------------------------------------------------
1 | storePassword=lgx112535
2 | keyPassword=lgx112535
3 | keyAlias=key
4 | storeFile=D:\Android_keystore/key.jks
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/assets/images/address.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/address.png
--------------------------------------------------------------------------------
/assets/images/collect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/collect.png
--------------------------------------------------------------------------------
/assets/images/good.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/good.png
--------------------------------------------------------------------------------
/assets/images/hongbao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/hongbao.png
--------------------------------------------------------------------------------
/assets/images/huiyuan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/huiyuan.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_group_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_group_active.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_group_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_group_normal.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_home_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_home_active.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_home_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_home_normal.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_profile_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_profile_active.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_profile_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_profile_normal.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_shiji_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_shiji_active.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_shiji_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_shiji_normal.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_subject_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_subject_active.png
--------------------------------------------------------------------------------
/assets/images/ic_tab_subject_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/ic_tab_subject_normal.png
--------------------------------------------------------------------------------
/assets/images/issure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/issure.png
--------------------------------------------------------------------------------
/assets/images/kefu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/kefu.png
--------------------------------------------------------------------------------
/assets/images/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/logout.png
--------------------------------------------------------------------------------
/assets/images/more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/more.png
--------------------------------------------------------------------------------
/assets/images/openAd.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/openAd.jpg
--------------------------------------------------------------------------------
/assets/images/oppen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/oppen.png
--------------------------------------------------------------------------------
/assets/images/order.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/order.png
--------------------------------------------------------------------------------
/assets/images/safe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/safe.png
--------------------------------------------------------------------------------
/assets/images/tab_cart_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_cart_active.png
--------------------------------------------------------------------------------
/assets/images/tab_cart_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_cart_default.png
--------------------------------------------------------------------------------
/assets/images/tab_copy_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_copy_active.png
--------------------------------------------------------------------------------
/assets/images/tab_copy_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_copy_default.png
--------------------------------------------------------------------------------
/assets/images/tab_home_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_home_active.png
--------------------------------------------------------------------------------
/assets/images/tab_home_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_home_default.png
--------------------------------------------------------------------------------
/assets/images/tab_mine_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_mine_active.png
--------------------------------------------------------------------------------
/assets/images/tab_mine_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_mine_default.png
--------------------------------------------------------------------------------
/assets/images/tab_sort_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_sort_active.png
--------------------------------------------------------------------------------
/assets/images/tab_sort_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/tab_sort_default.png
--------------------------------------------------------------------------------
/assets/images/timg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/timg.jpg
--------------------------------------------------------------------------------
/assets/images/week.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/assets/images/week.png
--------------------------------------------------------------------------------
/imges/ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/ad.png
--------------------------------------------------------------------------------
/imges/brand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/brand.png
--------------------------------------------------------------------------------
/imges/catalog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/catalog.png
--------------------------------------------------------------------------------
/imges/goodsDetail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/goodsDetail.png
--------------------------------------------------------------------------------
/imges/goodsSize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/goodsSize.png
--------------------------------------------------------------------------------
/imges/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/home.png
--------------------------------------------------------------------------------
/imges/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/login.png
--------------------------------------------------------------------------------
/imges/mine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/mine.png
--------------------------------------------------------------------------------
/imges/qrCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/qrCode.png
--------------------------------------------------------------------------------
/imges/sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/sort.png
--------------------------------------------------------------------------------
/imges/topic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/topic.png
--------------------------------------------------------------------------------
/imges/topicDetail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/imges/topicDetail.png
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Flutter.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # NOTE: This podspec is NOT to be published. It is only used as a local source!
3 | #
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'Flutter'
7 | s.version = '1.0.0'
8 | s.summary = 'High-performance, high-fidelity mobile apps.'
9 | s.description = <<-DESC
10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
11 | DESC
12 | s.homepage = 'https://flutter.io'
13 | s.license = { :type => 'MIT' }
14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
16 | s.ios.deployment_target = '8.0'
17 | s.vendored_frameworks = 'Flutter.framework'
18 | end
19 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/peroluo/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/peroluo/github/easyMarketFlutter"
5 | export "FLUTTER_TARGET=/Users/peroluo/github/easyMarketFlutter/lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
9 | export "FLUTTER_FRAMEWORK_DIR=/Users/peroluo/flutter/bin/cache/artifacts/engine/ios"
10 | export "FLUTTER_BUILD_NAME=1.0.0"
11 | export "FLUTTER_BUILD_NUMBER=1"
12 | export "TRACK_WIDGET_CREATION=true"
13 | export "DART_DEFINES=flutter.inspector.structuredErrors=true"
14 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | generated_key_values = {}
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) do |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | generated_key_values[podname] = podpath
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | end
32 | generated_key_values
33 | end
34 |
35 | target 'Runner' do
36 | # Flutter Pod
37 |
38 | copied_flutter_dir = File.join(__dir__, 'Flutter')
39 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
40 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
41 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
42 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
43 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
44 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
45 |
46 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
47 | unless File.exist?(generated_xcode_build_settings_path)
48 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
49 | end
50 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
51 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
52 |
53 | unless File.exist?(copied_framework_path)
54 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
55 | end
56 | unless File.exist?(copied_podspec_path)
57 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
58 | end
59 | end
60 |
61 | # Keep pod path relative so it can be checked into Podfile.lock.
62 | pod 'Flutter', :path => 'Flutter'
63 |
64 | # Plugin Pods
65 |
66 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
67 | # referring to absolute paths on developers' machines.
68 | system('rm -rf .symlinks')
69 | system('mkdir -p .symlinks/plugins')
70 | plugin_pods = parse_KV_file('../.flutter-plugins')
71 | plugin_pods.each do |name, path|
72 | symlink = File.join('.symlinks', 'plugins', name)
73 | File.symlink(path, symlink)
74 | pod name, :path => File.join(symlink, 'ios')
75 | end
76 | end
77 |
78 | post_install do |installer|
79 | installer.pods_project.targets.each do |target|
80 | target.build_configurations.each do |config|
81 | config.build_settings['ENABLE_BITCODE'] = 'NO'
82 | end
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_webview_plugin (0.0.1):
4 | - Flutter
5 | - FMDB (2.7.5):
6 | - FMDB/standard (= 2.7.5)
7 | - FMDB/standard (2.7.5)
8 | - path_provider (0.0.1):
9 | - Flutter
10 | - path_provider_linux (0.0.1):
11 | - Flutter
12 | - path_provider_macos (0.0.1):
13 | - Flutter
14 | - shared_preferences (0.0.1):
15 | - Flutter
16 | - sqflite (0.0.1):
17 | - Flutter
18 | - FMDB (~> 2.7.2)
19 |
20 | DEPENDENCIES:
21 | - Flutter (from `Flutter`)
22 | - flutter_webview_plugin (from `.symlinks/plugins/flutter_webview_plugin/ios`)
23 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
24 | - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
25 | - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
26 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
27 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
28 |
29 | SPEC REPOS:
30 | trunk:
31 | - FMDB
32 |
33 | EXTERNAL SOURCES:
34 | Flutter:
35 | :path: Flutter
36 | flutter_webview_plugin:
37 | :path: ".symlinks/plugins/flutter_webview_plugin/ios"
38 | path_provider:
39 | :path: ".symlinks/plugins/path_provider/ios"
40 | path_provider_linux:
41 | :path: ".symlinks/plugins/path_provider_linux/ios"
42 | path_provider_macos:
43 | :path: ".symlinks/plugins/path_provider_macos/ios"
44 | shared_preferences:
45 | :path: ".symlinks/plugins/shared_preferences/ios"
46 | sqflite:
47 | :path: ".symlinks/plugins/sqflite/ios"
48 |
49 | SPEC CHECKSUMS:
50 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
51 | flutter_webview_plugin: ed9e8a6a96baf0c867e90e1bce2673913eeac694
52 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
53 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
54 | path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
55 | path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
56 | shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523
57 | sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
58 |
59 | PODFILE CHECKSUM: f32fb4e7c14f8b3ca19a369d7be425dd9241af27
60 |
61 | COCOAPODS: 1.9.3
62 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luoguoxiong/easyMarketFlutter/770ba75f0b0b2279f0505ebdde6a5e179e1e0b21/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 | NSAllowsArbitraryLoadsInWebContent
10 |
11 |
12 | CFBundleDevelopmentRegion
13 | $(DEVELOPMENT_LANGUAGE)
14 | CFBundleExecutable
15 | $(EXECUTABLE_NAME)
16 | CFBundleIdentifier
17 | $(PRODUCT_BUNDLE_IDENTIFIER)
18 | CFBundleInfoDictionaryVersion
19 | 6.0
20 | CFBundleName
21 | easy_market
22 | CFBundlePackageType
23 | APPL
24 | CFBundleShortVersionString
25 | $(FLUTTER_BUILD_NAME)
26 | CFBundleSignature
27 | ????
28 | CFBundleVersion
29 | $(FLUTTER_BUILD_NUMBER)
30 | LSRequiresIPhoneOS
31 |
32 | UILaunchStoryboardName
33 | LaunchScreen
34 | UIMainStoryboardFile
35 | Main
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 | UIViewControllerBasedStatusBarAppearance
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/Advertisement/openAd.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 广告页
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-26 17:29:18
5 | */
6 | import 'package:flutter/material.dart';
7 |
8 | class OpenAd extends StatelessWidget {
9 | OpenAd(this.time);
10 | final int time;
11 | Widget build(BuildContext context) {
12 | return Container(
13 | width: double.infinity,
14 | height: double.infinity,
15 | decoration: BoxDecoration(
16 | image: DecorationImage(
17 | image: AssetImage('assets/images/timg.jpg'),
18 | fit: BoxFit.cover,
19 | ),
20 | ),
21 | child: Stack(
22 | children: [
23 | Positioned(
24 | bottom: 30,
25 | right: 10,
26 | child: Container(
27 | width: 60,
28 | height: 30,
29 | decoration: BoxDecoration(
30 | color: Color.fromARGB(100, 59, 70, 88),
31 | borderRadius: new BorderRadius.all(new Radius.circular(15.0)),
32 | ),
33 | child: Center(
34 | child: Text(
35 | '$time S',
36 | style: TextStyle(color: Colors.white),
37 | ),
38 | ),
39 | ),
40 | )
41 | ],
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/api/index.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: API管理
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-26 17:29:18
5 | */
6 | import 'package:easy_market/utils/http.dart';
7 |
8 | var http = new HttpUtils();
9 |
10 | class Api {
11 | // 获取首页数据
12 | static Future getHomeData() async {
13 | return await http.get('/');
14 | }
15 |
16 | // 获取专题页数据
17 | static Future getTopicData({int page, int size}) async {
18 | return await http.get('/topic/list', {'page': page, 'size': size});
19 | }
20 |
21 | // 获取分类页tabList
22 | static Future getSortTabs() async {
23 | return await http.get('/catalog/index');
24 | }
25 |
26 | // 获取所有商品的数量
27 | static Future getGoodsCount() async {
28 | return await http.get('/goods/count');
29 | }
30 |
31 | // 获取某分类的相关信息
32 | static Future getCategoryMsg({int id}) async {
33 | return await http.get('/catalog/current', {'id': id});
34 | }
35 |
36 | // 通过手机号码登录
37 | static Future loginByMobile({String mobile, String password}) async {
38 | return await http
39 | .post('/auth/loginByMobile', {'mobile': mobile, 'password': password});
40 | }
41 |
42 | // 获取兄弟分类
43 | static Future getBrotherCatalog({int id}) async {
44 | return await http.get('/goods/category', {'id': id});
45 | }
46 |
47 | // 某分类的商品
48 | static Future getGoods({
49 | int page,
50 | int size,
51 | int categoryId,
52 | }) async {
53 | return await http.get(
54 | '/goods/list', {'page': page, 'size': size, 'categoryId': categoryId});
55 | }
56 |
57 | // 某制造商的相关信息
58 | static Future getBrandMsg({int id}) async {
59 | return await http.get('/brand/detail', {'id': id});
60 | }
61 |
62 | // 某制造商下的商品
63 | static Future getBrandGoods({
64 | int page,
65 | int size,
66 | int brandId,
67 | }) async {
68 | return await http
69 | .get('/goods/list', {'page': page, 'size': size, 'brandId': brandId});
70 | }
71 |
72 | // 某专题的相关信息
73 | static Future getTopicMsg({int id}) async {
74 | return await http.get('/topic/detail', {'id': id});
75 | }
76 |
77 | // 获取某专题的评论
78 | static Future getTopicComment({
79 | int valueId,
80 | int typeId,
81 | int page,
82 | int size,
83 | }) async {
84 | return await http.get('/comment/list',
85 | {'valueId': valueId, 'typeId': typeId, 'page': page, 'size': size});
86 | }
87 |
88 | // 某专题相关专题
89 | static Future getRelatedTopic({int id}) async {
90 | return await http.get('/topic/related', {'id': id});
91 | }
92 |
93 | // 商品信息
94 | static Future getGoodsMSG({int id, String token}) async {
95 | return await http.getToken('/goods/detail', token, {'id': id});
96 | }
97 |
98 | // 获取购物信息
99 | static Future getCartMsg({String token, int id}) async {
100 | return await http.getToken('/cart/index', token, {'id': id});
101 | }
102 |
103 | // 添加到购物车
104 | static Future postAddCart({String token, int id}) async {
105 | return await http
106 | .postToken('/collect/addordelete', token, {'valueId': id, 'typeId': 0});
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/lib/component/SliverCustomHeader.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class SliverCustomHeaderDelegate extends SliverPersistentHeaderDelegate {
4 | final double collapsedHeight;
5 | final double expandedHeight;
6 | final double paddingTop;
7 | final Widget child;
8 | final String title;
9 |
10 | SliverCustomHeaderDelegate({
11 | this.collapsedHeight,
12 | this.expandedHeight,
13 | this.paddingTop,
14 | this.child,
15 | this.title,
16 | });
17 |
18 | @override
19 | double get minExtent => this.collapsedHeight + this.paddingTop;
20 |
21 | @override
22 | double get maxExtent => this.expandedHeight;
23 |
24 | @override
25 | bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
26 | return true;
27 | }
28 |
29 | Color makeStickyHeaderBgColor(shrinkOffset) {
30 | final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255)
31 | .clamp(0, 255)
32 | .toInt();
33 | return Color.fromARGB(alpha, 255, 255, 255);
34 | }
35 |
36 | Color makeStickyHeaderTextColor(shrinkOffset, isIcon) {
37 | if (shrinkOffset <= 50) {
38 | return isIcon ? Colors.white : Colors.transparent;
39 | } else {
40 | final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255)
41 | .clamp(0, 255)
42 | .toInt();
43 | return Color.fromARGB(alpha, 0, 0, 0);
44 | }
45 | }
46 |
47 | @override
48 | Widget build(
49 | BuildContext context, double shrinkOffset, bool overlapsContent) {
50 | return Container(
51 | height: this.maxExtent,
52 | width: MediaQuery.of(context).size.width,
53 | child: Stack(
54 | fit: StackFit.expand,
55 | children: [
56 | // 背景图
57 | this.child,
58 | // 收起头部
59 | Positioned(
60 | left: 0,
61 | right: 0,
62 | top: 0,
63 | child: Container(
64 | color: this.makeStickyHeaderBgColor(shrinkOffset), // 背景颜色
65 | child: SafeArea(
66 | bottom: false,
67 | child: Container(
68 | height: this.collapsedHeight,
69 | child: Row(
70 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
71 | children: [
72 | IconButton(
73 | icon: Icon(
74 | Icons.keyboard_arrow_left,
75 | color: this.makeStickyHeaderTextColor(
76 | shrinkOffset, true), // 返回图标颜色
77 | ),
78 | onPressed: () => Navigator.pop(context),
79 | ),
80 | Text(
81 | this.title,
82 | style: TextStyle(
83 | fontSize: 18,
84 | color: this.makeStickyHeaderTextColor(
85 | shrinkOffset, false), // 标题颜色
86 | ),
87 | ),
88 | IconButton(
89 | icon: Icon(
90 | Icons.share,
91 | color: Colors.transparent, // 分享图标颜色
92 | ),
93 | onPressed: () {},
94 | ),
95 | ],
96 | ),
97 | ),
98 | ),
99 | ),
100 | ),
101 | ],
102 | ),
103 | );
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/component/bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | import 'dart:async';
6 |
7 | import 'package:flutter/foundation.dart';
8 | import 'package:flutter/scheduler.dart';
9 | import 'package:flutter/widgets.dart';
10 |
11 | import 'package:flutter/material.dart';
12 |
13 | const Duration _bottomSheetDuration = Duration(milliseconds: 200);
14 | const double _minFlingVelocity = 700.0;
15 | const double _closeProgressThreshold = 0.5;
16 |
17 | /// A material design bottom sheet.
18 | ///
19 | /// There are two kinds of bottom sheets in material design:
20 | ///
21 | /// * _Persistent_. A persistent bottom sheet shows information that
22 | /// supplements the primary content of the app. A persistent bottom sheet
23 | /// remains visible even when the user interacts with other parts of the app.
24 | /// Persistent bottom sheets can be created and displayed with the
25 | /// [ScaffoldState.showBottomSheet] function or by specifying the
26 | /// [Scaffold.bottomSheet] constructor parameter.
27 | ///
28 | /// * _Modal_. A modal bottom sheet is an alternative to a menu or a dialog and
29 | /// prevents the user from interacting with the rest of the app. Modal bottom
30 | /// sheets can be created and displayed with the [showModalBottomSheet]
31 | /// function.
32 | ///
33 | /// The [BottomSheet] widget itself is rarely used directly. Instead, prefer to
34 | /// create a persistent bottom sheet with [ScaffoldState.showBottomSheet] or
35 | /// [Scaffold.bottomSheet], and a modal bottom sheet with [showModalBottomSheet].
36 | ///
37 | /// See also:
38 | ///
39 | /// * [showBottomSheet] and [ScaffoldState.showBottomSheet], for showing
40 | /// non-modal "persistent" bottom sheets.
41 | /// * [showModalBottomSheet], which can be used to display a modal bottom
42 | /// sheet.
43 | /// *
44 | class BottomSheet extends StatefulWidget {
45 | /// Creates a bottom sheet.
46 | ///
47 | /// Typically, bottom sheets are created implicitly by
48 | /// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by
49 | /// [showModalBottomSheet], for modal bottom sheets.
50 | const BottomSheet({
51 | Key key,
52 | this.animationController,
53 | this.enableDrag = true,
54 | this.backgroundColor,
55 | this.elevation,
56 | this.shape,
57 | @required this.onClosing,
58 | @required this.builder,
59 | }) : assert(enableDrag != null),
60 | assert(onClosing != null),
61 | assert(builder != null),
62 | assert(elevation == null || elevation >= 0.0),
63 | super(key: key);
64 |
65 | /// The animation controller that controls the bottom sheet's entrance and
66 | /// exit animations.
67 | ///
68 | /// The BottomSheet widget will manipulate the position of this animation, it
69 | /// is not just a passive observer.
70 | final AnimationController animationController;
71 |
72 | /// Called when the bottom sheet begins to close.
73 | ///
74 | /// A bottom sheet might be prevented from closing (e.g., by user
75 | /// interaction) even after this callback is called. For this reason, this
76 | /// callback might be call multiple times for a given bottom sheet.
77 | final VoidCallback onClosing;
78 |
79 | /// A builder for the contents of the sheet.
80 | ///
81 | /// The bottom sheet will wrap the widget produced by this builder in a
82 | /// [Material] widget.
83 | final WidgetBuilder builder;
84 |
85 | /// If true, the bottom sheet can be dragged up and down and dismissed by
86 | /// swiping downards.
87 | ///
88 | /// Default is true.
89 | final bool enableDrag;
90 |
91 | /// The bottom sheet's background color.
92 | ///
93 | /// Defines the bottom sheet's [Material.color].
94 | ///
95 | /// Defaults to null and falls back to [Material]'s default.
96 | final Color backgroundColor;
97 |
98 | /// The z-coordinate at which to place this material relative to its parent.
99 | ///
100 | /// This controls the size of the shadow below the material.
101 | ///
102 | /// Defaults to 0. The value is non-negative.
103 | final double elevation;
104 |
105 | /// The shape of the bottom sheet.
106 | ///
107 | /// Defines the bottom sheet's [Material.shape].
108 | ///
109 | /// Defaults to null and falls back to [Material]'s default.
110 | final ShapeBorder shape;
111 |
112 | @override
113 | _BottomSheetState createState() => _BottomSheetState();
114 |
115 | /// Creates an [AnimationController] suitable for a
116 | /// [BottomSheet.animationController].
117 | ///
118 | /// This API available as a convenience for a Material compliant bottom sheet
119 | /// animation. If alternative animation durations are required, a different
120 | /// animation controller could be provided.
121 | static AnimationController createAnimationController(TickerProvider vsync) {
122 | return AnimationController(
123 | duration: _bottomSheetDuration,
124 | debugLabel: 'BottomSheet',
125 | vsync: vsync,
126 | );
127 | }
128 | }
129 |
130 | class _BottomSheetState extends State {
131 | final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child');
132 |
133 | double get _childHeight {
134 | final RenderBox renderBox = _childKey.currentContext.findRenderObject();
135 | return renderBox.size.height;
136 | }
137 |
138 | bool get _dismissUnderway =>
139 | widget.animationController.status == AnimationStatus.reverse;
140 |
141 | void _handleDragUpdate(DragUpdateDetails details) {
142 | assert(widget.enableDrag);
143 | if (_dismissUnderway) return;
144 | widget.animationController.value -=
145 | details.primaryDelta / (_childHeight ?? details.primaryDelta);
146 | }
147 |
148 | void _handleDragEnd(DragEndDetails details) {
149 | assert(widget.enableDrag);
150 | if (_dismissUnderway) return;
151 | if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) {
152 | final double flingVelocity =
153 | -details.velocity.pixelsPerSecond.dy / _childHeight;
154 | if (widget.animationController.value > 0.0) {
155 | widget.animationController.fling(velocity: flingVelocity);
156 | }
157 | if (flingVelocity < 0.0) {
158 | widget.onClosing();
159 | }
160 | } else if (widget.animationController.value < _closeProgressThreshold) {
161 | if (widget.animationController.value > 0.0)
162 | widget.animationController.fling(velocity: -1.0);
163 | widget.onClosing();
164 | } else {
165 | widget.animationController.forward();
166 | }
167 | }
168 |
169 | bool extentChanged(DraggableScrollableNotification notification) {
170 | if (notification.extent == notification.minExtent) {
171 | widget.onClosing();
172 | }
173 | return false;
174 | }
175 |
176 | @override
177 | Widget build(BuildContext context) {
178 | final BottomSheetThemeData bottomSheetTheme =
179 | Theme.of(context).bottomSheetTheme;
180 | final Color color =
181 | widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
182 | final double elevation =
183 | widget.elevation ?? bottomSheetTheme.elevation ?? 0;
184 | final ShapeBorder shape = widget.shape ?? bottomSheetTheme.shape;
185 |
186 | final Widget bottomSheet = Material(
187 | key: _childKey,
188 | color: color,
189 | elevation: elevation,
190 | shape: shape,
191 | child: NotificationListener(
192 | onNotification: extentChanged,
193 | child: widget.builder(context),
194 | ),
195 | );
196 | return !widget.enableDrag
197 | ? bottomSheet
198 | : GestureDetector(
199 | onVerticalDragUpdate: _handleDragUpdate,
200 | onVerticalDragEnd: _handleDragEnd,
201 | child: bottomSheet,
202 | excludeFromSemantics: true,
203 | );
204 | }
205 | }
206 |
207 | // PERSISTENT BOTTOM SHEETS
208 |
209 | // See scaffold.dart
210 |
211 | // MODAL BOTTOM SHEETS
212 | class _ModalBottomSheetLayout extends SingleChildLayoutDelegate {
213 | _ModalBottomSheetLayout(this.progress, this.isScrollControlled);
214 |
215 | final double progress;
216 | final bool isScrollControlled;
217 |
218 | @override
219 | BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
220 | return BoxConstraints(
221 | minWidth: constraints.maxWidth,
222 | maxWidth: constraints.maxWidth,
223 | minHeight: 0.0,
224 | // maxHeight: isScrollControlled
225 | // ? constraints.maxHeight
226 | // : constraints.maxHeight * 9.0 / 16.0,
227 | );
228 | }
229 |
230 | @override
231 | Offset getPositionForChild(Size size, Size childSize) {
232 | return Offset(0.0, size.height - childSize.height * progress);
233 | }
234 |
235 | @override
236 | bool shouldRelayout(_ModalBottomSheetLayout oldDelegate) {
237 | return progress != oldDelegate.progress;
238 | }
239 | }
240 |
241 | class _ModalBottomSheet extends StatefulWidget {
242 | const _ModalBottomSheet({
243 | Key key,
244 | this.route,
245 | this.backgroundColor,
246 | this.elevation,
247 | this.shape,
248 | this.isScrollControlled = false,
249 | }) : assert(isScrollControlled != null),
250 | super(key: key);
251 |
252 | final _ModalBottomSheetRoute route;
253 | final bool isScrollControlled;
254 | final Color backgroundColor;
255 | final double elevation;
256 | final ShapeBorder shape;
257 |
258 | @override
259 | _ModalBottomSheetState createState() => _ModalBottomSheetState();
260 | }
261 |
262 | class _ModalBottomSheetState extends State<_ModalBottomSheet> {
263 | String _getRouteLabel(MaterialLocalizations localizations) {
264 | switch (defaultTargetPlatform) {
265 | case TargetPlatform.iOS:
266 | return '';
267 | case TargetPlatform.android:
268 | case TargetPlatform.fuchsia:
269 | return localizations.dialogLabel;
270 | }
271 | return null;
272 | }
273 |
274 | @override
275 | Widget build(BuildContext context) {
276 | assert(debugCheckHasMediaQuery(context));
277 | assert(debugCheckHasMaterialLocalizations(context));
278 | final MediaQueryData mediaQuery = MediaQuery.of(context);
279 | final MaterialLocalizations localizations =
280 | MaterialLocalizations.of(context);
281 | final String routeLabel = _getRouteLabel(localizations);
282 |
283 | return AnimatedBuilder(
284 | animation: widget.route.animation,
285 | builder: (BuildContext context, Widget child) {
286 | // Disable the initial animation when accessible navigation is on so
287 | // that the semantics are added to the tree at the correct time.
288 | final double animationValue = mediaQuery.accessibleNavigation
289 | ? 1.0
290 | : widget.route.animation.value;
291 | return Semantics(
292 | scopesRoute: true,
293 | namesRoute: true,
294 | label: routeLabel,
295 | explicitChildNodes: true,
296 | child: ClipRect(
297 | child: CustomSingleChildLayout(
298 | delegate: _ModalBottomSheetLayout(
299 | animationValue, widget.isScrollControlled),
300 | child: BottomSheet(
301 | animationController: widget.route._animationController,
302 | onClosing: () {
303 | if (widget.route.isCurrent) {
304 | Navigator.pop(context);
305 | }
306 | },
307 | builder: widget.route.builder,
308 | backgroundColor: widget.backgroundColor,
309 | elevation: widget.elevation,
310 | shape: widget.shape,
311 | ),
312 | ),
313 | ),
314 | );
315 | },
316 | );
317 | }
318 | }
319 |
320 | class _ModalBottomSheetRoute extends PopupRoute {
321 | _ModalBottomSheetRoute({
322 | this.builder,
323 | this.theme,
324 | this.barrierLabel,
325 | this.backgroundColor,
326 | this.elevation,
327 | this.shape,
328 | @required this.isScrollControlled,
329 | RouteSettings settings,
330 | }) : assert(isScrollControlled != null),
331 | super(settings: settings);
332 |
333 | final WidgetBuilder builder;
334 | final ThemeData theme;
335 | final bool isScrollControlled;
336 | final Color backgroundColor;
337 | final double elevation;
338 | final ShapeBorder shape;
339 |
340 | @override
341 | Duration get transitionDuration => _bottomSheetDuration;
342 |
343 | @override
344 | bool get barrierDismissible => true;
345 |
346 | @override
347 | final String barrierLabel;
348 |
349 | @override
350 | Color get barrierColor => Colors.black54;
351 |
352 | AnimationController _animationController;
353 |
354 | @override
355 | AnimationController createAnimationController() {
356 | assert(_animationController == null);
357 | _animationController =
358 | BottomSheet.createAnimationController(navigator.overlay);
359 | return _animationController;
360 | }
361 |
362 | @override
363 | Widget buildPage(BuildContext context, Animation animation,
364 | Animation secondaryAnimation) {
365 | // By definition, the bottom sheet is aligned to the bottom of the page
366 | // and isn't exposed to the top padding of the MediaQuery.
367 | Widget bottomSheet = MediaQuery.removePadding(
368 | context: context,
369 | removeTop: true,
370 | child: _ModalBottomSheet(
371 | route: this,
372 | backgroundColor: backgroundColor,
373 | elevation: elevation,
374 | shape: shape,
375 | isScrollControlled: isScrollControlled),
376 | );
377 | if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet);
378 | return bottomSheet;
379 | }
380 | }
381 |
382 | /// Shows a modal material design bottom sheet.
383 | ///
384 | /// A modal bottom sheet is an alternative to a menu or a dialog and prevents
385 | /// the user from interacting with the rest of the app.
386 | ///
387 | /// A closely related widget is a persistent bottom sheet, which shows
388 | /// information that supplements the primary content of the app without
389 | /// preventing the use from interacting with the app. Persistent bottom sheets
390 | /// can be created and displayed with the [showBottomSheet] function or the
391 | /// [ScaffoldState.showBottomSheet] method.
392 | ///
393 | /// The `context` argument is used to look up the [Navigator] and [Theme] for
394 | /// the bottom sheet. It is only used when the method is called. Its
395 | /// corresponding widget can be safely removed from the tree before the bottom
396 | /// sheet is closed.
397 | ///
398 | /// The `isScrollControlled` parameter specifies whether this is a route for
399 | /// a bottom sheet that will utilize [DraggableScrollableSheet]. If you wish
400 | /// to have a bottom sheet that has a scrollable child such as a [ListView] or
401 | /// a [GridView] and have the bottom sheet be draggable, you should set this
402 | /// parameter to true.
403 | ///
404 | /// Returns a `Future` that resolves to the value (if any) that was passed to
405 | /// [Navigator.pop] when the modal bottom sheet was closed.
406 | ///
407 | /// See also:
408 | ///
409 | /// * [BottomSheet], which is the widget normally returned by the function
410 | /// passed as the `builder` argument to [showModalBottomSheet].
411 | /// * [showBottomSheet] and [ScaffoldState.showBottomSheet], for showing
412 | /// non-modal bottom sheets.
413 | /// *
414 | Future showModalBottomSheetOp({
415 | @required BuildContext context,
416 | @required WidgetBuilder builder,
417 | Color backgroundColor,
418 | double elevation,
419 | ShapeBorder shape,
420 | bool isScrollControlled = false,
421 | }) {
422 | assert(context != null);
423 | assert(builder != null);
424 | assert(isScrollControlled != null);
425 | assert(debugCheckHasMediaQuery(context));
426 | assert(debugCheckHasMaterialLocalizations(context));
427 |
428 | return Navigator.push(
429 | context,
430 | _ModalBottomSheetRoute(
431 | builder: builder,
432 | theme: Theme.of(context, shadowThemeOnly: true),
433 | isScrollControlled: isScrollControlled,
434 | barrierLabel:
435 | MaterialLocalizations.of(context).modalBarrierDismissLabel,
436 | backgroundColor: backgroundColor,
437 | elevation: elevation,
438 | shape: shape,
439 | ));
440 | }
441 |
442 | /// Shows a material design bottom sheet in the nearest [Scaffold] ancestor. If
443 | /// you wish to show a persistent bottom sheet, use [Scaffold.bottomSheet].
444 | ///
445 | /// Returns a controller that can be used to close and otherwise manipulate the
446 | /// bottom sheet.
447 | ///
448 | /// To rebuild the bottom sheet (e.g. if it is stateful), call
449 | /// [PersistentBottomSheetController.setState] on the controller returned by
450 | /// this method.
451 | ///
452 | /// The new bottom sheet becomes a [LocalHistoryEntry] for the enclosing
453 | /// [ModalRoute] and a back button is added to the appbar of the [Scaffold]
454 | /// that closes the bottom sheet.
455 | ///
456 | /// To create a persistent bottom sheet that is not a [LocalHistoryEntry] and
457 | /// does not add a back button to the enclosing Scaffold's appbar, use the
458 | /// [Scaffold.bottomSheet] constructor parameter.
459 | ///
460 | /// A closely related widget is a modal bottom sheet, which is an alternative
461 | /// to a menu or a dialog and prevents the user from interacting with the rest
462 | /// of the app. Modal bottom sheets can be created and displayed with the
463 | /// [showModalBottomSheet] function.
464 | ///
465 | /// The `context` argument is used to look up the [Scaffold] for the bottom
466 | /// sheet. It is only used when the method is called. Its corresponding widget
467 | /// can be safely removed from the tree before the bottom sheet is closed.
468 | ///
469 | /// See also:
470 | ///
471 | /// * [BottomSheet], which is the widget typically returned by the `builder`.
472 | /// * [showModalBottomSheet], which can be used to display a modal bottom
473 | /// sheet.
474 | /// * [Scaffold.of], for information about how to obtain the [BuildContext].
475 | /// *
476 | PersistentBottomSheetController showBottomSheet({
477 | @required BuildContext context,
478 | @required WidgetBuilder builder,
479 | Color backgroundColor,
480 | double elevation,
481 | ShapeBorder shape,
482 | }) {
483 | assert(context != null);
484 | assert(builder != null);
485 | assert(debugCheckHasScaffold(context));
486 |
487 | return Scaffold.of(context).showBottomSheet(
488 | builder,
489 | backgroundColor: backgroundColor,
490 | elevation: elevation,
491 | shape: shape,
492 | );
493 | }
494 |
--------------------------------------------------------------------------------
/lib/component/count.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:easy_market/utils/rem.dart';
3 |
4 | // Color borderColor = Color.fromARGB(255, 0, 191, 255);
5 | Color borderColor = Colors.grey;
6 |
7 | class Count extends StatelessWidget {
8 | Count({
9 | this.number,
10 | this.min,
11 | this.max,
12 | this.onChange,
13 | });
14 |
15 | final ValueChanged onChange;
16 | final int number;
17 | final int min;
18 | final int max;
19 |
20 | final int a = 1;
21 |
22 | onClickBtn(String type) {
23 | if (type == 'remove' && number > min) {
24 | onChange(number - 1);
25 | } else if (type == 'add' && number < max) {
26 | onChange(number + 1);
27 | }
28 | }
29 |
30 | // 相当于render
31 | Widget build(BuildContext context) {
32 | return Container(
33 | height: Rem.getPxToRem(70),
34 | width: Rem.getPxToRem(260),
35 | decoration: BoxDecoration(
36 | border: Border.all(
37 | color: borderColor,
38 | ),
39 | ),
40 | child: Row(
41 | children: [
42 | Container(
43 | width: Rem.getPxToRem(70),
44 | color: this.min >= this.number ? Colors.grey[200] : Colors.white,
45 | child: InkResponse(
46 | child: Center(
47 | child: Icon(
48 | Icons.remove,
49 | color:
50 | this.min >= this.number ? Colors.grey[500] : Colors.black,
51 | ),
52 | ),
53 | onTap: () {
54 | this.onClickBtn('remove');
55 | },
56 | ),
57 | ),
58 | Expanded(
59 | child: Container(
60 | decoration: BoxDecoration(
61 | border: Border(
62 | left: BorderSide(color: borderColor),
63 | right: BorderSide(color: borderColor),
64 | ),
65 | ),
66 | child: Center(
67 | child: Text(
68 | '${this.number}',
69 | style: TextStyle(fontSize: Rem.getPxToRem(32)),
70 | ),
71 | ),
72 | ),
73 | ),
74 | Container(
75 | width: Rem.getPxToRem(70),
76 | color: this.max <= this.number ? Colors.grey[200] : Colors.white,
77 | child: InkResponse(
78 | child: Center(
79 | child: Icon(
80 | Icons.add,
81 | color:
82 | this.max <= this.number ? Colors.grey[500] : Colors.black,
83 | ),
84 | ),
85 | onTap: () {
86 | this.onClickBtn('add');
87 | },
88 | ),
89 | ),
90 | ],
91 | ),
92 | );
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/lib/component/linearBar.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 滚动渐变的appBar组件
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-30 14:21:15
5 | */
6 | import 'package:flutter/material.dart';
7 | import 'package:easy_market/utils/rem.dart';
8 |
9 | const APPBAR_SCROLL_OFFSET = 150;
10 |
11 | class LinearBar extends StatefulWidget {
12 | LinearBar({this.removePadding, this.child, this.appBarColor, this.title});
13 |
14 | final bool removePadding;
15 | final Widget child;
16 | final Color appBarColor;
17 | final String title;
18 | _LinearBar createState() => _LinearBar();
19 | }
20 |
21 | class _LinearBar extends State {
22 | double appBarAlpha = 0;
23 |
24 | _onScroll(offset) {
25 | double alpha = offset / APPBAR_SCROLL_OFFSET;
26 | if (alpha < 0) {
27 | alpha = 0;
28 | } else if (alpha > 1) {
29 | alpha = 1;
30 | }
31 | setState(() {
32 | appBarAlpha = alpha;
33 | });
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | return Scaffold(
39 | body: Stack(
40 | children: [
41 | Padding(
42 | padding: EdgeInsets.only(
43 | top:
44 | widget.removePadding ? MediaQuery.of(context).padding.top : 0,
45 | ),
46 | child: MediaQuery.removePadding(
47 | removeTop: true,
48 | context: context,
49 | child: NotificationListener(
50 | onNotification: (scrollNotification) {
51 | if (scrollNotification is ScrollUpdateNotification &&
52 | scrollNotification.depth == 0) {
53 | _onScroll(scrollNotification.metrics.pixels);
54 | }
55 | return null;
56 | },
57 | child: widget.child,
58 | ),
59 | ),
60 | ),
61 | Opacity(
62 | //改变透明度都可以使用 Opacity 将其包裹
63 | opacity: appBarAlpha,
64 | child: Container(
65 | height:
66 | Rem.getPxToRem(100) + MediaQuery.of(context).padding.top,
67 | padding:
68 | EdgeInsets.only(top: MediaQuery.of(context).padding.top),
69 | decoration: BoxDecoration(color: widget.appBarColor),
70 | )),
71 | Container(
72 | height: Rem.getPxToRem(100) + MediaQuery.of(context).padding.top,
73 | padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
74 | decoration: BoxDecoration(color: Colors.transparent),
75 | child: Row(
76 | children: [
77 | InkResponse(
78 | child: Container(
79 | width: Rem.getPxToRem(100),
80 | child: Center(
81 | child: Icon(
82 | Icons.keyboard_arrow_left,
83 | color: Colors.white,
84 | ),
85 | ),
86 | ),
87 | onTap: () {
88 | Navigator.pop(context);
89 | },
90 | ),
91 | Expanded(
92 | child: Padding(
93 | child: Center(
94 | child: Text(
95 | widget.title,
96 | overflow: TextOverflow.ellipsis,
97 | style: TextStyle(
98 | color: Colors.white, fontSize: Rem.getPxToRem(38)),
99 | ),
100 | ),
101 | padding: EdgeInsets.symmetric(horizontal: 20),
102 | ),
103 | ),
104 | Container(
105 | width: Rem.getPxToRem(100),
106 | ),
107 | ],
108 | ),
109 | ),
110 | ],
111 | ),
112 | );
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/lib/component/swiper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_swiper/flutter_swiper.dart'; // 引入头文件
3 |
4 | class SwiperView extends StatefulWidget {
5 | final List bannerImg;
6 | SwiperView(this.bannerImg);
7 | @override
8 | _SwiperViewState createState() => _SwiperViewState();
9 | }
10 |
11 | class _SwiperViewState extends State {
12 | List imageList;
13 |
14 | @override
15 | void initState() {
16 | super.initState();
17 | setState(() {
18 | imageList = widget.bannerImg;
19 | });
20 | }
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Column(children: [firstSwiperView()]);
25 | }
26 |
27 | Widget firstSwiperView() {
28 | return Container(
29 | width: MediaQuery.of(context).size.width,
30 | height: 200,
31 | child: Swiper(
32 | itemCount: imageList.length,
33 | itemBuilder: _swiperBuilder,
34 | pagination: SwiperPagination(
35 | alignment: Alignment.bottomCenter,
36 | margin: const EdgeInsets.fromLTRB(0, 0, 0, 5),
37 | builder: DotSwiperPaginationBuilder(
38 | color: Colors.grey[200],
39 | size: 8,
40 | activeColor: Colors.red[400])),
41 | controller: SwiperController(),
42 | scrollDirection: Axis.horizontal,
43 | autoplay: true,
44 | autoplayDelay: 4000,
45 | onTap: (index) => print('点击了第$index'),
46 | ),
47 | );
48 | }
49 |
50 | Widget _swiperBuilder(BuildContext context, int index) {
51 | return (imageList[index]);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/component/tab.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 自定义Tab
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-15 10:08:01
5 | */
6 | import 'package:flutter/material.dart';
7 | import '../utils/rem.dart';
8 |
9 | class TabItem {
10 | final String name, defaultIcon, activeIcon;
11 | TabItem(this.name, this.defaultIcon, this.activeIcon);
12 | }
13 |
14 | class TabOp extends StatelessWidget {
15 | TabOp({Key key, this.currentIndex, this.onTabChange, this.items})
16 | : super(key: key);
17 | final int currentIndex;
18 | final ValueChanged onTabChange;
19 | final List items;
20 | _handleTap(index) {
21 | if (currentIndex != index) {
22 | onTabChange(index);
23 | }
24 | }
25 |
26 | Widget build(BuildContext context) {
27 | final List tabs = List(items.length);
28 | for (var i = 0; i < items.length; i++) {
29 | tabs[i] = Expanded(
30 | child: InkResponse(
31 | onTap: () {
32 | _handleTap(i);
33 | },
34 | child: Container(
35 | height: Rem.getPxToRem(110),
36 | child: new Column(
37 | children: [
38 | Expanded(
39 | child: currentIndex == i
40 | ? AnimateTab(icon: items[i].activeIcon)
41 | : Image.asset(
42 | currentIndex == i
43 | ? items[i].activeIcon
44 | : items[i].defaultIcon,
45 | height: Rem.getPxToRem(40),
46 | width: Rem.getPxToRem(40),
47 | ),
48 | flex: 8,
49 | ),
50 | Expanded(
51 | child: new Text(
52 | items[i].name,
53 | style: TextStyle(
54 | fontSize: Rem.getPxToRem(24),
55 | color: currentIndex == i
56 | ? Color.fromARGB(255, 33, 150, 243)
57 | : Colors.black),
58 | ),
59 | flex: 4,
60 | )
61 | ],
62 | ),
63 | )),
64 | );
65 | }
66 | return Container(
67 | decoration: new BoxDecoration(
68 | color: Colors.white,
69 | border: new Border(top: BorderSide(width: 1, color: Colors.grey[300])),
70 | ),
71 | child: Row(
72 | children: tabs,
73 | ),
74 | );
75 | }
76 | }
77 |
78 | class AnimateTab extends StatefulWidget {
79 | AnimateTab({Key key, this.icon}) : super(key: key);
80 | final String icon;
81 | @override
82 | _AnimateTab createState() => new _AnimateTab();
83 | }
84 |
85 | class _AnimateTab extends State
86 | with SingleTickerProviderStateMixin {
87 | Animation animation;
88 | AnimationController controller;
89 |
90 | initState() {
91 | super.initState();
92 | controller = new AnimationController(
93 | duration: const Duration(milliseconds: 500), vsync: this);
94 | animation = CurvedAnimation(parent: controller, curve: Cubic(0, -5, .5, 5));
95 | animation = new Tween(begin: Rem.getPxToRem(35), end: Rem.getPxToRem(40))
96 | .animate(animation)
97 | ..addListener(() {
98 | setState(() {});
99 | });
100 | controller.forward();
101 | }
102 |
103 | @override
104 | Widget build(BuildContext context) {
105 | return Image.asset(widget.icon,
106 | width: animation.value, height: animation.value);
107 | }
108 |
109 | dispose() {
110 | controller.dispose();
111 | super.dispose();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/lib/component/tabAppBar.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 自定义有tab切换的appBar
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-28 14:47:00
5 | */
6 | import 'package:flutter/material.dart';
7 | import 'package:easy_market/utils/rem.dart';
8 |
9 | class TabAppBar extends StatelessWidget {
10 | TabAppBar({this.tabs, this.controller, this.title});
11 |
12 | final List tabs;
13 |
14 | final TabController controller;
15 |
16 | final String title;
17 | Widget buildAppBar(BuildContext context) {
18 | return new Container(
19 | width: double.infinity,
20 | padding: new EdgeInsets.only(top: MediaQuery.of(context).padding.top),
21 | child: new Container(
22 | child: Row(
23 | children: [
24 | InkResponse(
25 | child: Container(
26 | width: Rem.getPxToRem(100),
27 | child: Center(
28 | child: Icon(
29 | Icons.keyboard_arrow_left,
30 | color: Colors.white,
31 | ),
32 | ),
33 | ),
34 | onTap: () {
35 | Navigator.pop(context);
36 | },
37 | ),
38 | Expanded(
39 | child: Center(
40 | child: Text(
41 | title,
42 | style: TextStyle(
43 | color: Colors.white, fontSize: Rem.getPxToRem(38)),
44 | ),
45 | ),
46 | ),
47 | Container(
48 | width: Rem.getPxToRem(100),
49 | ),
50 | ],
51 | ),
52 | height: Rem.getPxToRem(100),
53 | ),
54 | decoration: new BoxDecoration(
55 | gradient: new LinearGradient(colors: [Colors.teal, Colors.green]),
56 | ),
57 | );
58 | }
59 |
60 | Widget buildTabBar() {
61 | return Container(
62 | width: double.infinity,
63 | decoration: BoxDecoration(color: Colors.white, boxShadow: [
64 | new BoxShadow(
65 | color: Colors.grey[500],
66 | blurRadius: Rem.getPxToRem(1),
67 | spreadRadius: 0.8,
68 | )
69 | ]),
70 | child: TabBar(
71 | isScrollable: true,
72 | controller: this.controller,
73 | labelStyle: TextStyle(
74 | fontSize: Rem.getPxToRem(30), fontWeight: FontWeight.bold),
75 | labelColor: Colors.green,
76 | unselectedLabelColor: Colors.black45,
77 | indicatorColor: Colors.green,
78 | indicatorWeight: Rem.getPxToRem(2),
79 | tabs: tabs.map((item) {
80 | return Container(
81 | height: Rem.getPxToRem(60),
82 | child: Center(child: Text(item)),
83 | );
84 | }).toList(),
85 | ));
86 | }
87 |
88 | @override
89 | PreferredSize build(BuildContext context) {
90 | return new PreferredSize(
91 | child: Column(
92 | children: tabs.length > 0
93 | ? [buildAppBar(context), buildTabBar()]
94 | : [
95 | buildAppBar(context),
96 | ],
97 | ),
98 | preferredSize: new Size(
99 | MediaQuery.of(context).size.width,
100 | tabs.length > 0 ? Rem.getPxToRem(164) : Rem.getPxToRem(100),
101 | ),
102 | );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/lib/component/verticalTab.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 垂直切换的Tab
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-26 17:29:18
5 | */
6 | import 'package:flutter/material.dart';
7 |
8 | const double opWidth = 100.0;
9 |
10 | const tabItemHeight = 50.0;
11 |
12 | const indexColor = Colors.green;
13 |
14 | class VerticalTab extends StatefulWidget {
15 | VerticalTab({Key key, this.tabs, this.onTabChange, this.activeIndex});
16 | final List tabs;
17 |
18 | final ValueChanged onTabChange;
19 |
20 | final int activeIndex;
21 | @override
22 | State createState() {
23 | return _VerticalTab();
24 | }
25 | }
26 |
27 | class _VerticalTab extends State {
28 | double _scrollY = 0;
29 |
30 | int _currentIndex = 0;
31 | ScrollController _controller = new ScrollController();
32 |
33 | bool isTap = false;
34 | @override
35 | void initState() {
36 | super.initState();
37 | _controller.addListener(() {
38 | if (isTap) {
39 | setState(() {
40 | isTap = false;
41 | _scrollY = _controller.offset;
42 | });
43 | } else {
44 | setState(() {
45 | _scrollY = _controller.offset;
46 | });
47 | }
48 | });
49 | }
50 |
51 | @override
52 | void dispose() {
53 | _controller.dispose();
54 | super.dispose();
55 | }
56 |
57 | Widget buildTabItem(item, index) {
58 | return InkResponse(
59 | onTap: () {
60 | if (_currentIndex != index) {
61 | setState(() {
62 | _currentIndex = index;
63 | isTap = true;
64 | widget.onTabChange(index);
65 | });
66 | }
67 | },
68 | child: Container(
69 | width: opWidth,
70 | height: tabItemHeight,
71 | child: Center(
72 | child: Text(
73 | '$item',
74 | style: TextStyle(
75 | color: index == _currentIndex ? Colors.green : Colors.black87,
76 | letterSpacing: 2,
77 | fontSize: index == _currentIndex ? 16 : 14),
78 | ),
79 | ),
80 | ),
81 | );
82 | }
83 |
84 | @override
85 | Widget build(BuildContext context) {
86 | final List tabList = List(widget.tabs.length);
87 | for (var i = 0; i < widget.tabs.length; i++) {
88 | tabList[i] = buildTabItem(widget.tabs[i], i);
89 | }
90 | return Container(
91 | width: opWidth,
92 | height: double.infinity,
93 | color: Colors.white,
94 | child: tabList.isNotEmpty
95 | ? Stack(
96 | children: [
97 | Positioned(
98 | child: SingleChildScrollView(
99 | controller: _controller,
100 | child: Column(
101 | children: tabList,
102 | ),
103 | ),
104 | ),
105 | AnimatedPositioned(
106 | duration: Duration(milliseconds: isTap ? 100 : 0),
107 | top: -_scrollY + _currentIndex * 50,
108 | child: Container(
109 | height: tabItemHeight,
110 | width: 4,
111 | color: indexColor,
112 | ))
113 | ],
114 | )
115 | : null,
116 | );
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: main
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-15 10:08:01
5 | */
6 | import 'package:flutter/material.dart';
7 | import 'package:flutter/services.dart';
8 | import 'package:provider/provider.dart';
9 | import 'package:easy_market/utils/rem.dart';
10 | import 'package:easy_market/router/index.dart';
11 | import 'package:easy_market/model/index.dart';
12 | import 'package:easy_market/utils/cache.dart';
13 | import 'package:easy_market/page/index.dart';
14 |
15 | void main() async {
16 | // * https: //stackoverflow.com/questions/57689492/flutter-unhandled-exception-servicesbinding-defaultbinarymessenger-was-accesse
17 | // 异步获取SpUtil时,版本升级会有问题WidgetsFlutterBinding.ensureInitialized();
18 | WidgetsFlutterBinding.ensureInitialized();
19 | var sq = await SpUtil.getInstance();
20 | var token = sq.getString('token');
21 | var userName = sq.getString('userName');
22 | runApp(MyApp(token, userName));
23 |
24 | // if (Platform.isAndroid) {
25 | // //设置Android头部的导航栏透明
26 | // SystemUiOverlayStyle systemUiOverlayStyle =
27 | // SystemUiOverlayStyle(statusBarColor: Colors.transparent);
28 | // SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
29 | // }
30 | //白色
31 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light
32 | .copyWith(statusBarBrightness: Brightness.dark));
33 | }
34 |
35 | class MyApp extends StatelessWidget {
36 | MyApp(this.token, this.userName);
37 |
38 | final String token;
39 |
40 | final String userName;
41 |
42 | @override
43 | Widget build(BuildContext context) {
44 | // 设置设计稿的宽度
45 |
46 | Rem.setDesignWidth(750.0);
47 | return MultiProvider(
48 | providers: [
49 | ChangeNotifierProvider(builder: (_) => Model(token, userName)),
50 | ],
51 | child: Consumer(
52 | builder: (context, model, widget) {
53 | return RestartWidget(
54 | child: MaterialApp(
55 | theme: ThemeData(backgroundColor: Colors.transparent),
56 | // 监听路由跳转
57 | onGenerateRoute: (RouteSettings settings) {
58 | return Router.run(settings);
59 | },
60 | home: Scaffold(
61 | resizeToAvoidBottomPadding: false,
62 | body: TabPage(),
63 | ),
64 | ),
65 | );
66 | },
67 | ),
68 | );
69 | }
70 | }
71 |
72 | ///这个组件用来重新加载整个child Widget的。当我们需要重启APP的时候,可以使用这个方案
73 | ///https://stackoverflow.com/questions/50115311/flutter-how-to-force-an-application-restart-in-production-mode
74 | class RestartWidget extends StatefulWidget {
75 | final Widget child;
76 |
77 | RestartWidget({Key key, @required this.child})
78 | : assert(child != null),
79 | super(key: key);
80 |
81 | static restartApp(BuildContext context) {
82 | final _RestartWidgetState state =
83 | context.ancestorStateOfType(const TypeMatcher<_RestartWidgetState>());
84 | state.restartApp();
85 | }
86 |
87 | @override
88 | _RestartWidgetState createState() => _RestartWidgetState();
89 | }
90 |
91 | class _RestartWidgetState extends State {
92 | Key key = UniqueKey();
93 |
94 | void restartApp() {
95 | setState(() {
96 | key = UniqueKey();
97 | });
98 | }
99 |
100 | @override
101 | Widget build(BuildContext context) {
102 | return Container(
103 | key: key,
104 | child: widget.child,
105 | );
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/model/index.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: Provider数据管理
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-27 15:34:15
5 | */
6 | import 'package:flutter/material.dart';
7 |
8 | class Model with ChangeNotifier {
9 | Model(this._token, this._userName);
10 |
11 | String _token; // 用户token的值来区分是否登录(null?token)
12 |
13 | String _userName;
14 |
15 | String get token => _token;
16 |
17 | String get userName => _userName;
18 |
19 | void setToken(token) {
20 | _token = token;
21 | notifyListeners();
22 | }
23 |
24 | void setUserName(name) {
25 | _userName = name;
26 | notifyListeners();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/page/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:easy_market/page/home/index.dart';
3 | import 'package:easy_market/page/topic/index.dart';
4 | import 'package:easy_market/page/sort/index.dart';
5 | import 'package:easy_market/page/mine/index.dart';
6 | import 'package:easy_market/page/cart/index.dart';
7 | import 'package:easy_market/page/wrapper.dart';
8 |
9 | class App extends StatefulWidget {
10 | @override
11 | State createState() {
12 | return _ApplicationPageState();
13 | }
14 | }
15 |
16 | class _Item {
17 | String name, activeIcon, normalIcon;
18 |
19 | _Item(this.name, this.activeIcon, this.normalIcon);
20 | }
21 |
22 | class _ApplicationPageState extends State {
23 | int _currentPageIndex = 0;
24 |
25 | final pageList = [
26 | WrapKeepState(Home()),
27 | WrapKeepState(Topic()),
28 | WrapKeepState(Sort()),
29 | // WrapKeepState(Cart()),
30 | Cart(),
31 | WrapKeepState(Mine()),
32 | ];
33 |
34 | Widget getPage(_index) {
35 | return pageList[_index];
36 | }
37 |
38 | final itemNames = [
39 | _Item('首页', 'assets/images/ic_tab_home_active.png',
40 | 'assets/images/ic_tab_home_normal.png'),
41 | _Item('专题', 'assets/images/ic_tab_subject_active.png',
42 | 'assets/images/ic_tab_subject_normal.png'),
43 | _Item('分类', 'assets/images/ic_tab_group_active.png',
44 | 'assets/images/ic_tab_group_normal.png'),
45 | _Item('购物车', 'assets/images/ic_tab_shiji_active.png',
46 | 'assets/images/ic_tab_shiji_normal.png'),
47 | _Item('我的', 'assets/images/ic_tab_profile_active.png',
48 | 'assets/images/ic_tab_profile_normal.png')
49 | ];
50 | List itemList;
51 | @override
52 | void initState() {
53 | super.initState();
54 | if (itemList == null) {
55 | itemList = itemNames
56 | .map((item) => BottomNavigationBarItem(
57 | icon: Image.asset(
58 | item.normalIcon,
59 | width: 30.0,
60 | height: 30.0,
61 | ),
62 | title: Text(
63 | item.name,
64 | style: TextStyle(fontSize: 10.0),
65 | ),
66 | activeIcon:
67 | Image.asset(item.activeIcon, width: 30.0, height: 30.0)))
68 | .toList();
69 | }
70 | }
71 |
72 | final pageController = PageController();
73 |
74 | void onTap(int index) {
75 | pageController.jumpToPage(index);
76 | }
77 |
78 | void onPageChanged(int index) {
79 | setState(() {
80 | _currentPageIndex = index;
81 | });
82 | }
83 |
84 | @override
85 | Widget build(BuildContext context) {
86 | return new Scaffold(
87 | backgroundColor: Color.fromARGB(1, 200, 200, 200),
88 | // appBar: new PreferredSize(
89 | // child: new Container(
90 | // // decoration: new BoxDecoration(
91 | // // gradient:
92 | // // new LinearGradient(colors: [Colors.teal, Colors.lightGreen]),
93 | // // ),
94 | // color: Colors.green,
95 | // ),
96 | // preferredSize: new Size(MediaQuery.of(context).size.width, 0),
97 | // ),
98 | // PageView+wrapper封装保存页面状态
99 | body: PageView(
100 | children: pageList,
101 | controller: pageController,
102 | onPageChanged: onPageChanged,
103 | physics: NeverScrollableScrollPhysics(), // 禁止滑动
104 | ),
105 | bottomNavigationBar: BottomNavigationBar(
106 | items: itemList,
107 | onTap: (int index) {
108 | setState(() {
109 | _currentPageIndex = index;
110 | pageController.jumpToPage(index);
111 | });
112 | },
113 | iconSize: 24,
114 | currentIndex: _currentPageIndex,
115 | fixedColor: Color.fromARGB(255, 0, 188, 96),
116 | type: BottomNavigationBarType.fixed,
117 | ),
118 | );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/lib/page/cart/index.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
3 |
4 | class Cart extends StatefulWidget {
5 | @override
6 | State createState() {
7 | return _Cart();
8 | }
9 | }
10 |
11 | class _Cart extends State {
12 | final GlobalKey _scaffoldKey = GlobalKey();
13 | @override
14 | dispose() {
15 | super.dispose();
16 | }
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | // final model = Provider.of(context);
21 | // return Center(
22 | // child: model.token != null ? Text('${model.token}') : Text('未登录'),
23 | // );
24 | return Scaffold(
25 | key: _scaffoldKey,
26 | appBar: new PreferredSize(
27 | child: new Container(
28 | color: Colors.green,
29 | ),
30 | preferredSize: new Size(MediaQuery.of(context).size.width, 0),
31 | ),
32 | body: Container(
33 | child: WebviewScaffold(
34 | url: 'https://www.zhihu.com/',
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/page/home/index.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:cached_network_image/cached_network_image.dart';
3 | import 'package:dio/dio.dart';
4 | import 'package:easy_market/component/swiper.dart';
5 | import 'package:easy_market/api/index.dart';
6 | import 'package:easy_market/utils/rem.dart';
7 | import 'package:easy_market/router/index.dart';
8 | import './topic.dart';
9 |
10 | class Home extends StatefulWidget {
11 | @override
12 | State createState() {
13 | return _Home();
14 | }
15 | }
16 |
17 | class _Home extends State {
18 | bool isLoading = true;
19 |
20 | List banner, channel, brand, news, hot, topic, category = [];
21 |
22 | @override
23 | void initState() {
24 | super.initState();
25 | _getDio();
26 | }
27 |
28 | _getDio() async {
29 | Response data = await Api.getHomeData();
30 | // 轮播图数据
31 | var bannerData = data.data['banner'];
32 | List bannerList = List();
33 | bannerData.forEach((item) => bannerList.add(CachedNetworkImage(
34 | imageUrl: item['image_url'],
35 | errorWidget: (context, url, error) => new Icon(Icons.error),
36 | fit: BoxFit.fill,
37 | )));
38 | // channel数据
39 | var channelData = data.data['channel'];
40 | // 制造商数据
41 | var brandData = data.data['brandList'];
42 | // 新品推荐
43 | var newsData = data.data['newGoodsList'];
44 | // 人气推荐
45 | var hotData = data.data['hotGoodsList'];
46 | // 专题精选
47 | var topicList = data.data['topicList'];
48 | // 推荐商品
49 | var categoryList = data.data['categoryList'];
50 | setState(() {
51 | banner = bannerList;
52 | channel = channelData;
53 | brand = brandData;
54 | news = newsData;
55 | hot = hotData;
56 | topic = topicList;
57 | category = categoryList;
58 | isLoading = false;
59 | });
60 | }
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | if (isLoading) {
65 | return Center(
66 | child: SizedBox(
67 | width: 24.0,
68 | height: 24.0,
69 | child: CircularProgressIndicator(strokeWidth: 2.0)),
70 | );
71 | } else {
72 | var sliversList = [
73 | buildSwiper(),
74 | buildChannel(),
75 | buildTitle('品牌制造商直供', false),
76 | buildBrand(),
77 | buildTitle('新品首发'),
78 | buildNews(),
79 | buildTitle('人气推荐', false),
80 | buildHot(),
81 | buildTopic(),
82 | ];
83 | for (var i = 0; i < category.length; i++) {
84 | sliversList.add(buildTitle(category[i]['name']));
85 | sliversList.add(buildCategory(
86 | category[i]['goodsList'], category[i]['name'], category[i]['id']));
87 | }
88 | return new SafeArea(
89 | child: CustomScrollView(
90 | slivers: sliversList,
91 | ),
92 | );
93 | }
94 | }
95 |
96 | // 轮播图
97 | SliverList buildSwiper() {
98 | return SliverList(
99 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
100 | return SwiperView(banner);
101 | }, childCount: 1),
102 | );
103 | }
104 |
105 | // 渠道
106 | SliverGrid buildChannel() {
107 | return SliverGrid(
108 | gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
109 | crossAxisCount: 5,
110 | childAspectRatio: 1.3,
111 | ),
112 | delegate: new SliverChildBuilderDelegate(
113 | (BuildContext context, int index) {
114 | return Router.link(
115 | Column(
116 | children: [
117 | Expanded(
118 | flex: 2,
119 | child: new Container(
120 | color: Colors.white,
121 | padding: EdgeInsets.only(
122 | bottom: Rem.getPxToRem(4),
123 | left: Rem.getPxToRem(25),
124 | top: Rem.getPxToRem(25),
125 | right: Rem.getPxToRem(25)),
126 | child: Center(
127 | child: CachedNetworkImage(
128 | imageUrl: channel[index]['icon_url'],
129 | fit: BoxFit.fitWidth,
130 | ),
131 | ),
132 | ),
133 | ),
134 | Expanded(
135 | flex: 1,
136 | child: new Container(
137 | color: Colors.white,
138 | child: Center(
139 | child: new Text(
140 | channel[index]['name'],
141 | style: TextStyle(
142 | fontSize: Rem.getPxToRem(20),
143 | ),
144 | ),
145 | ),
146 | ),
147 | ),
148 | ],
149 | ),
150 | '/catalog',
151 | context,
152 | {
153 | 'id': channel[index]['id'],
154 | });
155 | },
156 | childCount: 5,
157 | ),
158 | );
159 | }
160 |
161 | // 製造商
162 | SliverGrid buildBrand() {
163 | return SliverGrid(
164 | gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
165 | crossAxisCount: 2,
166 | childAspectRatio: 1.6,
167 | ),
168 | delegate: new SliverChildBuilderDelegate(
169 | (BuildContext context, int index) {
170 | Widget widget = Container(
171 | child: Column(
172 | children: [
173 | Container(
174 | width: double.infinity,
175 | child: Text(
176 | brand[index]['name'],
177 | style: TextStyle(fontSize: Rem.getPxToRem(30)),
178 | ),
179 | ),
180 | Container(
181 | width: double.infinity,
182 | child: Text(
183 | '${brand[index]['floor_price']}元起',
184 | style: TextStyle(
185 | fontSize: Rem.getPxToRem(24), color: Colors.grey),
186 | ),
187 | ),
188 | ],
189 | ),
190 | padding: EdgeInsets.only(
191 | top: Rem.getPxToRem(10), left: Rem.getPxToRem(20)),
192 | decoration: BoxDecoration(
193 | image: DecorationImage(
194 | fit: BoxFit.fill,
195 | image: NetworkImage(brand[index]['new_pic_url']))),
196 | );
197 | return Router.link(widget, '/brand', context, {
198 | 'id': brand[index]['id'],
199 | });
200 | },
201 | childCount: brand.length,
202 | ),
203 | );
204 | }
205 |
206 | // 新品
207 | SliverGrid buildNews() {
208 | return SliverGrid(
209 | gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
210 | crossAxisCount: 2,
211 | mainAxisSpacing: 2.0,
212 | crossAxisSpacing: 2.0,
213 | childAspectRatio: .9,
214 | ),
215 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
216 | Widget widget = Container(
217 | color: Colors.white,
218 | child: Column(
219 | children: [
220 | Expanded(
221 | child: Padding(
222 | padding: EdgeInsets.symmetric(horizontal: Rem.getPxToRem(20)),
223 | child: CachedNetworkImage(
224 | imageUrl: news[index]['list_pic_url'],
225 | height: Rem.getPxToRem(250),
226 | width: double.infinity,
227 | ),
228 | ),
229 | flex: 300,
230 | ),
231 | Expanded(
232 | child: Container(
233 | child: Center(
234 | child: Text(
235 | '${news[index]['name']}',
236 | style: TextStyle(
237 | fontWeight: FontWeight.bold,
238 | fontSize: Rem.getPxToRem(30)),
239 | ),
240 | ),
241 | ),
242 | flex: 40,
243 | ),
244 | Expanded(
245 | child: Container(
246 | child: Center(
247 | child: Text(
248 | '¥${news[index]['retail_price']}',
249 | style: TextStyle(
250 | color: Colors.red, fontSize: Rem.getPxToRem(28)),
251 | ),
252 | ),
253 | ),
254 | flex: 40,
255 | ),
256 | ],
257 | ),
258 | );
259 | return Router.link(widget, '/goodsDetail', context, {
260 | 'id': news[index]['id'],
261 | });
262 | }, childCount: news.length),
263 | );
264 | }
265 |
266 | // 人气推荐
267 | SliverList buildHot() {
268 | return SliverList(
269 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
270 | Widget widget = Container(
271 | decoration: BoxDecoration(
272 | color: Colors.white,
273 | border:
274 | Border(top: BorderSide(color: Colors.grey[300], width: .5))),
275 | padding: EdgeInsets.fromLTRB(Rem.getPxToRem(30), Rem.getPxToRem(10),
276 | Rem.getPxToRem(30), Rem.getPxToRem(10)),
277 | child: Container(
278 | height: Rem.getPxToRem(220),
279 | child: Row(
280 | children: [
281 | Container(
282 | child: CachedNetworkImage(
283 | imageUrl: hot[index]['list_pic_url'],
284 | fit: BoxFit.cover,
285 | ),
286 | height: Rem.getPxToRem(220),
287 | width: Rem.getPxToRem(220),
288 | ),
289 | Expanded(
290 | child: Container(
291 | padding:
292 | EdgeInsets.symmetric(vertical: Rem.getPxToRem(20)),
293 | margin: EdgeInsets.only(left: Rem.getPxToRem(10)),
294 | child: Column(
295 | children: [
296 | Container(
297 | height: Rem.getPxToRem(60),
298 | width: double.infinity,
299 | child: Align(
300 | alignment: Alignment.centerLeft,
301 | child: Text(
302 | hot[index]['name'],
303 | overflow: TextOverflow.ellipsis,
304 | style: TextStyle(
305 | fontWeight: FontWeight.bold,
306 | fontSize: Rem.getPxToRem(28)),
307 | ),
308 | )),
309 | Container(
310 | height: Rem.getPxToRem(60),
311 | width: double.infinity,
312 | child: Align(
313 | alignment: Alignment.centerLeft,
314 | child: Text(
315 | hot[index]['goods_brief'],
316 | overflow: TextOverflow.ellipsis,
317 | style: TextStyle(
318 | fontSize: Rem.getPxToRem(24),
319 | color: Colors.grey),
320 | ),
321 | ),
322 | ),
323 | Container(
324 | height: Rem.getPxToRem(60),
325 | width: double.infinity,
326 | child: Align(
327 | alignment: Alignment.centerLeft,
328 | child: Text(
329 | '¥${hot[index]['retail_price']}',
330 | style: TextStyle(
331 | fontSize: Rem.getPxToRem(30),
332 | color: Colors.red),
333 | ),
334 | ),
335 | ),
336 | ],
337 | )),
338 | )
339 | ],
340 | ),
341 | ),
342 | );
343 | return Router.link(widget, '/goodsDetail', context, {
344 | 'id': hot[index]['id'],
345 | });
346 | }, childCount: hot.length),
347 | );
348 | }
349 |
350 | // 专题精选
351 | SliverList buildTopic() {
352 | return SliverList(
353 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
354 | return Topic(topic, context);
355 | }, childCount: 1),
356 | );
357 | }
358 |
359 | // 某类型的商品
360 | SliverGrid buildCategory(goods, typeName, id) {
361 | return SliverGrid(
362 | gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
363 | crossAxisCount: 2,
364 | mainAxisSpacing: 2.0,
365 | crossAxisSpacing: 2.0,
366 | childAspectRatio: .9,
367 | ),
368 | delegate: new SliverChildBuilderDelegate(
369 | (BuildContext context, int index) {
370 | if (goods.length == index) {
371 | Widget widget = Container(
372 | color: Colors.white,
373 | child: Center(
374 | child: Container(
375 | height: Rem.getPxToRem(140),
376 | child: Column(
377 | children: [
378 | Container(
379 | height: Rem.getPxToRem(80),
380 | child: Center(
381 | child: Text(
382 | '更多$typeName好物',
383 | style: TextStyle(fontSize: Rem.getPxToRem(26)),
384 | ),
385 | ),
386 | ),
387 | Image.asset(
388 | 'assets/images/more.png',
389 | height: Rem.getPxToRem(60),
390 | )
391 | ],
392 | ),
393 | ),
394 | ),
395 | );
396 | return Router.link(widget, '/catalog', context, {
397 | 'id': id,
398 | });
399 | }
400 | Widget widget = Container(
401 | color: Colors.white,
402 | child: Column(
403 | children: [
404 | Expanded(
405 | child: Container(
406 | padding: EdgeInsets.symmetric(horizontal: 20),
407 | child: CachedNetworkImage(
408 | imageUrl: goods[index]['list_pic_url'],
409 | fit: BoxFit.cover,
410 | ),
411 | ),
412 | flex: 350,
413 | ),
414 | Expanded(
415 | child: Container(
416 | padding: EdgeInsets.symmetric(horizontal: 20),
417 | child: Center(
418 | child: Text(
419 | goods[index]['name'],
420 | style: TextStyle(fontWeight: FontWeight.bold),
421 | overflow: TextOverflow.ellipsis,
422 | ),
423 | ),
424 | ),
425 | flex: 50,
426 | ),
427 | Expanded(
428 | child: Container(
429 | padding: EdgeInsets.only(bottom: 10),
430 | child: Center(
431 | child: Text(
432 | '¥${goods[index]['retail_price']}',
433 | style: TextStyle(
434 | color: Colors.red,
435 | ),
436 | ),
437 | ),
438 | ),
439 | flex: 60,
440 | ),
441 | ],
442 | ),
443 | );
444 | return Router.link(widget, '/goodsDetail', context, {
445 | 'id': goods[index]['id'],
446 | });
447 | },
448 | childCount: goods.length + 1,
449 | ));
450 | }
451 |
452 | // 标题
453 | SliverList buildTitle(String title, [bool isBorder = true]) {
454 | return SliverList(
455 | delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
456 | return Container(
457 | height: Rem.getPxToRem(100),
458 | decoration: BoxDecoration(
459 | color: Colors.white,
460 | border: isBorder
461 | ? Border(
462 | bottom: BorderSide(color: Colors.grey[200], width: .5))
463 | : null),
464 | margin: EdgeInsets.only(top: Rem.getPxToRem(20)),
465 | child: Center(
466 | child: Text(
467 | title,
468 | style: TextStyle(
469 | fontWeight: FontWeight.bold,
470 | wordSpacing: 2,
471 | fontSize: Rem.getPxToRem(30)),
472 | ),
473 | ),
474 | );
475 | }, childCount: 1),
476 | );
477 | }
478 | }
479 |
--------------------------------------------------------------------------------
/lib/page/home/topic.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:easy_market/utils/rem.dart';
3 | import 'package:flutter_swiper/flutter_swiper.dart';
4 | import 'package:cached_network_image/cached_network_image.dart';
5 |
6 | class Topic extends StatelessWidget {
7 | final List data;
8 | final BuildContext contexts;
9 | Topic(this.data, this.contexts);
10 | final String title = '专题精选';
11 | Widget swiper(List imgList) {
12 | return Container(
13 | width: double.infinity,
14 | height: Rem.getPxToRem(480),
15 | child: Swiper(
16 | itemCount: 3,
17 | itemBuilder: (BuildContext context, int index) {
18 | return Padding(
19 | padding: EdgeInsets.symmetric(horizontal: 10),
20 | child: Column(
21 | children: [
22 | Container(
23 | height: Rem.getPxToRem(400),
24 | width: double.infinity,
25 | child: CachedNetworkImage(
26 | imageUrl: imgList[index]['scene_pic_url'],
27 | fit: BoxFit.cover,
28 | ),
29 | ),
30 | Container(
31 | height: Rem.getPxToRem(40),
32 | child: Align(
33 | alignment: Alignment.centerLeft,
34 | child: Text.rich(TextSpan(children: [
35 | TextSpan(
36 | text: imgList[index]['title'],
37 | style: TextStyle(
38 | fontSize: Rem.getPxToRem(26),
39 | fontWeight: FontWeight.bold)),
40 | TextSpan(
41 | text: '¥${imgList[index]['price_info']}元起',
42 | style: TextStyle(
43 | color: Colors.red[600],
44 | fontSize: Rem.getPxToRem(26),
45 | fontWeight: FontWeight.bold,
46 | ),
47 | ),
48 | ]))),
49 | ),
50 | Container(
51 | height: Rem.getPxToRem(40),
52 | child: Align(
53 | alignment: Alignment.centerLeft,
54 | child: new Text(
55 | imgList[index]['subtitle'],
56 | overflow: TextOverflow.ellipsis,
57 | style: TextStyle(
58 | fontSize: Rem.getPxToRem(22), color: Colors.grey),
59 | ),
60 | ),
61 | ),
62 | ],
63 | ));
64 | },
65 | controller: SwiperController(),
66 | scrollDirection: Axis.horizontal,
67 | onTap: (index) {
68 | Navigator.pushNamed(
69 | contexts,
70 | '/topicDetail',
71 | arguments: {'id': imgList[index]['id']},
72 | );
73 | },
74 | viewportFraction: 0.8,
75 | ),
76 | );
77 | }
78 |
79 | @override
80 | Widget build(BuildContext context) {
81 | List imgUrl = [];
82 | data.forEach((item) => imgUrl.add(item));
83 | return Container(
84 | margin: EdgeInsets.only(top: Rem.getPxToRem(20)),
85 | color: Colors.white,
86 | child: Column(
87 | children: [
88 | Container(
89 | height: Rem.getPxToRem(100),
90 | child: Center(
91 | child: Text(
92 | title,
93 | style: TextStyle(
94 | fontWeight: FontWeight.bold,
95 | wordSpacing: 2,
96 | fontSize: Rem.getPxToRem(30)),
97 | ),
98 | ),
99 | ),
100 | swiper(imgUrl),
101 | ],
102 | ),
103 | );
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/page/index.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 | import 'package:easy_market/Advertisement/openAd.dart';
4 | import './app.dart';
5 | // import 'package:easy_market/utils/rem.dart';
6 |
7 | class TabPage extends StatefulWidget {
8 | _Page createState() => _Page();
9 | }
10 |
11 | class _Page extends State {
12 | // 是否启用广告
13 | bool showAd = true;
14 | // 广告展示时间
15 | int _seconds = 5;
16 |
17 | Timer _timer;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | _startTimer();
23 | }
24 |
25 | // 启动倒计时的计时器。
26 | void _startTimer() {
27 | if (showAd) {
28 | _timer = Timer.periodic(Duration(seconds: 1), (timer) {
29 | setState(() {});
30 | if (_seconds <= 1) {
31 | setState(() {
32 | showAd = false;
33 | });
34 | _cancelTimer();
35 | return;
36 | } else {
37 | setState(() {
38 | _seconds = _seconds - 1;
39 | });
40 | }
41 | });
42 | }
43 | }
44 |
45 | @override
46 | void dispose() {
47 | _cancelTimer();
48 | super.dispose();
49 | }
50 |
51 | // 清除倒计时的计时器。
52 | void _cancelTimer() {
53 | _timer?.cancel();
54 | }
55 |
56 | Widget build(BuildContext context) {
57 | return Stack(
58 | children: [
59 | // 显示app
60 | Offstage(
61 | child: App(),
62 | offstage: showAd,
63 | ),
64 | // 显示广告
65 | Offstage(
66 | child: OpenAd(_seconds),
67 | offstage: !showAd,
68 | ),
69 | ],
70 | );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/page/mine/index.dart:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: 我的页
3 | * @Author: luoguoxiong
4 | * @Date: 2019-08-15 10:08:01
5 | */
6 | import 'package:cached_network_image/cached_network_image.dart';
7 | import 'package:flutter/material.dart';
8 | import 'package:provider/provider.dart';
9 | import 'package:easy_market/model/index.dart';
10 | import 'package:easy_market/utils/rem.dart';
11 | import 'package:easy_market/router/index.dart';
12 | import 'package:easy_market/utils/cache.dart';
13 |
14 | class Mine extends StatelessWidget {
15 | final List