├── README.md └── shflutter ├── .gitignore ├── .metadata ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── fluttershop04 │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── ios ├── .gitignore ├── Flutter │ └── AppFrameworkInfo.plist ├── Podfile ├── Runner.xcodeproj │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h └── build │ └── XCBuildData │ ├── 08b36489fb55de50cd405553ab42b82e-buildRequest.json │ ├── 08b36489fb55de50cd405553ab42b82e-desc.xcbuild │ ├── 08b36489fb55de50cd405553ab42b82e-manifest.xcbuild │ ├── 08b36489fb55de50cd405553ab42b82e-targetGraph.txt │ ├── BuildDescriptionCacheIndex-16869db9749d0502558d79c3dd0ec38f │ ├── build.db │ ├── e9f2e267994c92ee25ec8a8afd875e3f-buildRequest.json │ ├── e9f2e267994c92ee25ec8a8afd875e3f-desc.xcbuild │ ├── e9f2e267994c92ee25ec8a8afd875e3f-manifest.xcbuild │ └── e9f2e267994c92ee25ec8a8afd875e3f-targetGraph.txt ├── lib ├── config │ └── service_url.dart ├── main.dart ├── model │ ├── cartInfo.dart │ ├── category.dart │ ├── categoryGoodList.dart │ └── details.dart ├── pages │ ├── cart_page.dart │ ├── cart_page │ │ ├── cart_bottom.dart │ │ ├── cart_count.dart │ │ └── cart_item.dart │ ├── category_page.dart │ ├── details_page │ │ ├── details_bottom.dart │ │ ├── details_explain.dart │ │ ├── details_page.dart │ │ ├── details_tabBar.dart │ │ ├── details_top_area.dart │ │ └── details_web.dart │ ├── home_page.dart │ ├── index_page.dart │ └── member_page.dart ├── provide │ ├── cart.dart │ ├── category_goods_list.dart │ ├── child_category.dart │ ├── counter.dart │ ├── current_index.dart │ └── details_info.dart ├── routers │ ├── application.dart │ ├── router_handler.dart │ └── routes.dart └── service │ └── service_method.dart ├── pubspec.yaml └── test └── widget_test.dart /README.md: -------------------------------------------------------------------------------- 1 | # Flutter 实现百姓生活 Lift+ 2 | 3 | 使用 flutter 仿写 百姓生活Lift+ ,内部涉及 flutter 常用组件的使用示例和规范。 4 | 主要模块有:商城首页、商品分类、商品详情、购物车、个人中心等, 5 | 主要用到的技术有:dio进行网络请求、fluro进行路由跳转、url_launcher进行打电话、shared_preferences进行数据存储、flutter_screenutil进行屏幕适配、Provide进行跨组件通信、flutter_html进行html的加载、flutter_easyrefresh进行列表的刷新等。 6 | 7 | ## 示例图 8 | 9 | ![FlutterProject](https://cdn.jsdelivr.net/gh/SunHui-Candy/Simg@tc/22img/FlutterProject.gif) 10 | 11 | 12 | ## Widget 13 | 14 | Flutter的理念是**万物皆Widget**(Everything is Widget), 15 | 这是为了实现Flutter的一个设计理念:**激进式组合(Aggressive composability)**。 16 | Widget由一系列的小的Widget组合而成,而这些进行组合的Widget,本身是由更基础的Widget构成。 17 | 18 | Widget的定义是:**描述一个UI元素的配置数据。它并不是表示最终绘制在设备上的显示元素,而只是描述显示元素的一个配置数据**。 19 | Widget主要分为三类:**Component Widget(*组合类Widget*)、Proxy Widget(*代理类Widget*)以及Render Widget(*渲染类Widget*)**, 20 | 其中只有Render Widget才会参与后面的布局(layout)和渲染(paint)流程。 21 | 22 | - **Widget是Element的配置数据,Element才真正代表屏幕显示元素;** 23 | - **一个Widget对象可以对应多个Element对象。** 24 | 25 | ## Element 26 | 27 | - 维护Element Tree,根据Widget Tree的变化来更新Element Tree, 28 | 包括:节点的插入、更新、删除、移动等; 29 | 并起到纽带的作用,**将Widget以及RenderObject关联到Element Tree上**。 30 | - Element分为**ComponentElement(组合类Element)和RenderObjectElement(渲染类Element)**, 31 | 前者负责组合子Element,后者负责渲染。 32 | 33 | **Element有4种状态:initial(*初始状态*),active(*激活状态*),inactive(*未激活状态*),defunct(*失效状态*)** 34 | 35 | ## RenderObject 36 | 37 | - RenderObject主要**负责绘制**`paint`,**布局**`layout`,**命中测试**`hitTest`等。 38 | - RenderObject**布局的原则是,Constraints向下,Sizes向上,父节点设置本节点的位置**。 39 | - RenderView是整个RenderObject Tree的根节点,其child是一个 **RenderBox 类型的RenderObject**。 40 | 41 | ## Platform Channel 42 | 43 | Flutter是通过Platform Channel同宿主平台进行通信的。 44 | 为了保证界面能够响应及时,消息的传递是异步的。 45 | Flutter定义了三种不同类型的Platform Channel,它们分别是: 46 | - **BasicMessageChannel:用于传递字符串和半结构化的信息。支持数据双向传递,有返回值**。 47 | - **MethodChannel:用于传递方法调用(method invocation)。支持数据双向传递,有返回值**。 48 | - **EventChannel: 用于数据流/(事件流)(event streams)的通信,仅支持数据单向传递(从Platform 平台 到Flutter),无返回值**。 49 | 50 | ## Provide进行跨组件通信 51 | 52 | 在使用Provider的时候,我们主要关心三个概念: 53 | >ChangeNotifier:真正数据(状态)存放的地方 54 | ChangeNotifierProvider:Widget树中提供数据(状态)的地方,会在其中创建对应的ChangeNotifier 55 | Consumer:Widget树中需要使用数据(状态)的地方 56 | 57 | ``` Swift 58 | void main() { 59 | //启动Flutter应用,runApp接受一个Widget参数,在本示例中它是一个MyApp对象,MyApp()是Flutter应用的根组件 60 | var currentIndexProvide = CurrentIndexProvider(); 61 | 62 | //flutter_provide 状态管理 63 | var providers = Providers(); 64 | providers 65 | ..provide(Provider.value(currentIndexProvide)) 66 | 67 | //ProviderNode封装了InheritWidget,并且提供了 一个providers容器用于放置状态。 68 | runApp(ProviderNode(child: MyApp(),providers: providers)); 69 | } 70 | 71 | @override 72 | Widget build(BuildContext context) { 73 | ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context); 74 | return Provide ( 75 | builder: (context,child,val) { 76 | //获取状态currentIndex 77 | // int currentIndex = val.currentIndex; 或者使用以下方式获取 currentIndex 78 | int currentIndex = Provide.value(context).currentIndex; 79 | //Scaffold 是 Material 库中提供的页面脚手架, 80 | //它提供了默认的导航栏、标题和包含主屏幕widget树(后同“组件树”或“部件树”)的body属性,组件树可以很复杂 81 | return Scaffold( 82 | backgroundColor: Color.fromRGBO(244, 245, 245 ,1.0), 83 | bottomNavigationBar: BottomNavigationBar( 84 | type: BottomNavigationBarType.fixed, 85 | currentIndex: currentIndex, 86 | items: bottomTabs, 87 | onTap: (index) { 88 | //更改状态currentIndex 89 | Provide.value(context).changeIndex(index); 90 | }, 91 | ), 92 | //body的组件树中包含了一个Center 组件,Center 可以将其子组件树对齐到屏幕中心 93 | body: IndexedStack( 94 | index: currentIndex, 95 | children: tabBodies, 96 | ), 97 | ); 98 | } 99 | ); 100 | } 101 | 102 | /* 作用:监听点击tabbar时,下标的改变*/ 103 | //ChangeNotifier,意思是可以不用管理听众 104 | class CurrentIndexProvider with ChangeNotifier { 105 | int currentIndex = 0; 106 | changeIndex(int newIndex) { 107 | currentIndex = newIndex; 108 | print('点击的值'); 109 | print(newIndex); 110 | //通过notifyListeners可以通知听众刷新。 111 | notifyListeners(); 112 | } 113 | 114 | } 115 | 116 | ``` 117 | 118 | ## Flutter 进行网络请求实现 119 | 120 | ``` Swift 121 | 122 | Future request(url,{formData})async 123 | { 124 | try{ 125 | Response response; 126 | Dio dio = new Dio(); 127 | dio.options.contentType = Headers.formUrlEncodedContentType; 128 | if(formData == null) { 129 | response = await dio.post(servicePath[url]); 130 | } else { 131 | response = await dio.post(servicePath[url],data:formData); 132 | } 133 | print("查看响应数据请求url:${servicePath[url]},\n返回数据:${response.data}"); 134 | if (response.statusCode == 200) { 135 | return response.data; 136 | } else { 137 | throw Exception('有异常。。。'); 138 | } 139 | 140 | }catch(e){ 141 | return print('ERROR:======>$e'); 142 | } 143 | 144 | } 145 | 146 | ``` -------------------------------------------------------------------------------- /shflutter/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | -------------------------------------------------------------------------------- /shflutter/.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: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /shflutter/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "spades.vs-picgo" 4 | ] 5 | } -------------------------------------------------------------------------------- /shflutter/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "shflutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /shflutter/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.minimap.enabled": false 3 | } -------------------------------------------------------------------------------- /shflutter/README.md: -------------------------------------------------------------------------------- 1 | # shflutter 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /shflutter/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /shflutter/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 29 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.shflutter" 42 | minSdkVersion 16 43 | targetSdkVersion 29 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /shflutter/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /shflutter/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /shflutter/android/app/src/main/kotlin/com/example/fluttershop04/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.shflutter 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /shflutter/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /shflutter/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /shflutter/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /shflutter/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /shflutter/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /shflutter/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /shflutter/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /shflutter/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. -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/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 | -------------------------------------------------------------------------------- /shflutter/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | shflutter 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /shflutter/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/08b36489fb55de50cd405553ab42b82e-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "_buildCommand2" : { 3 | "command" : "prepareForIndexing", 4 | "enableIndexBuildArena" : false, 5 | "targets" : null 6 | }, 7 | "buildCommand" : "build", 8 | "configuredTargets" : [ 9 | { 10 | "guid" : "18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49" 11 | } 12 | ], 13 | "containerPath" : "/Users/jmm/Documents/SH_FlutterDemo/shflutter/ios/Runner.xcodeproj", 14 | "continueBuildingAfterErrors" : true, 15 | "enableIndexBuildArena" : false, 16 | "hideShellScriptEnvironment" : false, 17 | "parameters" : { 18 | "action" : "build", 19 | "activeArchitecture" : "arm64", 20 | "activeRunDestination" : { 21 | "disableOnlyActiveArch" : false, 22 | "platform" : "iphonesimulator", 23 | "sdk" : "iphonesimulator15.2", 24 | "sdkVariant" : "iphonesimulator", 25 | "supportedArchitectures" : [ 26 | "arm64", 27 | "x86_64" 28 | ], 29 | "targetArchitecture" : "arm64" 30 | }, 31 | "arenaInfo" : { 32 | "buildIntermediatesPath" : "", 33 | "buildProductsPath" : "", 34 | "derivedDataPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData", 35 | "indexDataStoreFolderPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData/Runner-gkfkfaqqcxoikmbgwtjqexjffypy/Index/DataStore", 36 | "indexEnableDataStore" : true, 37 | "indexPCHPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData/Runner-gkfkfaqqcxoikmbgwtjqexjffypy/Index/PrecompiledHeaders", 38 | "pchPath" : "" 39 | }, 40 | "configurationName" : "Debug", 41 | "overrides" : { 42 | "synthesized" : { 43 | "table" : { 44 | "ASSETCATALOG_FILTER_FOR_DEVICE_MODEL" : "iPod9,1", 45 | "ASSETCATALOG_FILTER_FOR_DEVICE_OS_VERSION" : "15.2", 46 | "BUILD_ACTIVE_RESOURCES_ONLY" : "YES", 47 | "ENABLE_PREVIEWS" : "NO", 48 | "TARGET_DEVICE_IDENTIFIER" : "51589F72-3FAC-4973-9F0B-C18F6E9D2415", 49 | "TARGET_DEVICE_MODEL" : "iPod9,1", 50 | "TARGET_DEVICE_OS_VERSION" : "15.2", 51 | "TARGET_DEVICE_PLATFORM_NAME" : "iphonesimulator" 52 | } 53 | } 54 | } 55 | }, 56 | "schemeCommand" : "launch", 57 | "schemeCommand2" : "launch", 58 | "shouldCollectMetrics" : false, 59 | "showNonLoggedProgress" : true, 60 | "useDryRun" : false, 61 | "useImplicitDependencies" : true, 62 | "useLegacyBuildLocations" : false, 63 | "useParallelTargets" : true 64 | } -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/08b36489fb55de50cd405553ab42b82e-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/build/XCBuildData/08b36489fb55de50cd405553ab42b82e-desc.xcbuild -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/08b36489fb55de50cd405553ab42b82e-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner, no dependencies -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/BuildDescriptionCacheIndex-16869db9749d0502558d79c3dd0ec38f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/build/XCBuildData/BuildDescriptionCacheIndex-16869db9749d0502558d79c3dd0ec38f -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/build.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/build/XCBuildData/build.db -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/e9f2e267994c92ee25ec8a8afd875e3f-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "_buildCommand2" : { 3 | "command" : "prepareForIndexing", 4 | "enableIndexBuildArena" : false, 5 | "targets" : null 6 | }, 7 | "buildCommand" : "build", 8 | "configuredTargets" : [ 9 | { 10 | "guid" : "18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49" 11 | } 12 | ], 13 | "containerPath" : "/Users/jmm/Documents/SH_FlutterDemo/shflutter/ios/Runner.xcodeproj", 14 | "continueBuildingAfterErrors" : true, 15 | "enableIndexBuildArena" : false, 16 | "hideShellScriptEnvironment" : false, 17 | "parameters" : { 18 | "action" : "build", 19 | "activeArchitecture" : "arm64", 20 | "activeRunDestination" : { 21 | "disableOnlyActiveArch" : false, 22 | "platform" : "iphonesimulator", 23 | "sdk" : "iphonesimulator15.2", 24 | "sdkVariant" : "iphonesimulator", 25 | "supportedArchitectures" : [ 26 | "arm64", 27 | "x86_64" 28 | ], 29 | "targetArchitecture" : "arm64" 30 | }, 31 | "arenaInfo" : { 32 | "buildIntermediatesPath" : "", 33 | "buildProductsPath" : "", 34 | "derivedDataPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData", 35 | "indexDataStoreFolderPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData/Runner-gkfkfaqqcxoikmbgwtjqexjffypy/Index/DataStore", 36 | "indexEnableDataStore" : true, 37 | "indexPCHPath" : "/Users/jmm/Library/Developer/Xcode/DerivedData/Runner-gkfkfaqqcxoikmbgwtjqexjffypy/Index/PrecompiledHeaders", 38 | "pchPath" : "" 39 | }, 40 | "configurationName" : "Debug", 41 | "overrides" : { 42 | "synthesized" : { 43 | "table" : { 44 | "ASSETCATALOG_FILTER_FOR_DEVICE_MODEL" : "iPod9,1", 45 | "ASSETCATALOG_FILTER_FOR_DEVICE_OS_VERSION" : "15.2", 46 | "BUILD_ACTIVE_RESOURCES_ONLY" : "YES", 47 | "ENABLE_PREVIEWS" : "NO", 48 | "TARGET_DEVICE_IDENTIFIER" : "51589F72-3FAC-4973-9F0B-C18F6E9D2415", 49 | "TARGET_DEVICE_MODEL" : "iPod9,1", 50 | "TARGET_DEVICE_OS_VERSION" : "15.2", 51 | "TARGET_DEVICE_PLATFORM_NAME" : "iphonesimulator" 52 | } 53 | } 54 | } 55 | }, 56 | "qos" : "default", 57 | "schemeCommand" : "launch", 58 | "schemeCommand2" : "launch", 59 | "shouldCollectMetrics" : false, 60 | "showNonLoggedProgress" : true, 61 | "useDryRun" : true, 62 | "useImplicitDependencies" : true, 63 | "useLegacyBuildLocations" : false, 64 | "useParallelTargets" : true 65 | } -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/e9f2e267994c92ee25ec8a8afd875e3f-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderLNHui/FlutterProject/ffb91bf86434c1d79c2524a81f0284f87249e9a7/shflutter/ios/build/XCBuildData/e9f2e267994c92ee25ec8a8afd875e3f-desc.xcbuild -------------------------------------------------------------------------------- /shflutter/ios/build/XCBuildData/e9f2e267994c92ee25ec8a8afd875e3f-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner, no dependencies -------------------------------------------------------------------------------- /shflutter/lib/config/service_url.dart: -------------------------------------------------------------------------------- 1 | const serviceUrl = 'https://wxmini.baixingliangfan.cn/baixing/'; 2 | const servicePath = { 3 | 'homePageContext': serviceUrl+'wxmini/homePageContent', // 商家首页信息 4 | 'getGoodDetailById':serviceUrl+'wxmini/getGoodDetailById', //商品详细信息列表 5 | 'getCategory': serviceUrl+'wxmini/getCategory', //商品类别信息 6 | 'getMallGoods': serviceUrl+'wxmini/getMallGoods', //商品分类的商品列表 7 | 'homePageBelowConten': serviceUrl+'wxmini/homePageBelowConten', //商城首页热卖商品拉取 8 | 9 | 10 | }; -------------------------------------------------------------------------------- /shflutter/lib/main.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; //导入了Material UI组件库,Material是一种标准的移动端和web端的视觉设计语言 3 | import 'package:shflutter/provide/cart.dart'; 4 | import 'package:shflutter/provide/counter.dart'; 5 | import './pages/index_page.dart'; 6 | import 'package:provide/provide.dart'; 7 | import './provide/current_index.dart'; 8 | import './routers/application.dart'; 9 | import 'package:fluro/fluro.dart'; 10 | import './provide/details_info.dart'; 11 | import './routers/routes.dart'; 12 | import './provide/child_category.dart'; 13 | import './provide/category_goods_list.dart'; 14 | 15 | void main() { 16 | //启动Flutter应用,runApp接受一个Widget参数,在本示例中它是一个MyApp对象,MyApp()是Flutter应用的根组件 17 | // runApp(MyApp()); 18 | var childCategory = ChildCategory(); 19 | var categoryGoodsListProvide= CategoryGoodsListProvide(); 20 | var detailsInfoProvide = DetailsInfoProvide(); 21 | var cartProvide = CartProvide(); 22 | var currentIndexProvide = CurrentIndexProvider(); 23 | var counter =Counter(); 24 | 25 | //flutter_provide 状态管理 26 | var providers = Providers(); 27 | providers 28 | ..provide(Provider.value(childCategory)) 29 | ..provide(Provider.value(categoryGoodsListProvide)) 30 | ..provide(Provider.value(detailsInfoProvide)) 31 | ..provide(Provider.value(cartProvide)) 32 | ..provide(Provider.value(currentIndexProvide)) 33 | ..provide(Provider.value(counter)); 34 | 35 | 36 | //ProviderNode封装了InheritWidget,并且提供了 一个providers容器用于放置状态。 37 | runApp(ProviderNode(child: MyApp(),providers: providers)); 38 | } 39 | 40 | //MyApp类代表Flutter应用,它继承了 StatelessWidget类,这也就意味着应用本身也是一个widge 41 | class MyApp extends StatelessWidget { 42 | @override 43 | //Flutter在构建页面时,会调用组件的build方法, 44 | //widget的主要工作是提供一个build()方法来描述如何构建UI界面(通常是通过组合、拼装其它基础widget)。 45 | Widget build(BuildContext context) { 46 | 47 | final router = FluroRouter(); 48 | Routes.configureRoutes(router); 49 | Application.router = router; 50 | 51 | 52 | return Container( 53 | //MaterialApp 是Material库中提供的Flutter APP框架, 54 | //通过它可以设置应用的名称、主题、语言、首页及路由列表等。MaterialApp也是一个widget。 55 | child: MaterialApp( 56 | title: 'sh', 57 | debugShowCheckedModeBanner: false, 58 | theme: ThemeData( 59 | primarySwatch:Colors.blue, 60 | ), 61 | //home 为Flutter应用的首页,它也是一个widget 62 | home: IndexPage(), 63 | ), 64 | ); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /shflutter/lib/model/cartInfo.dart: -------------------------------------------------------------------------------- 1 | class CartInfoMode { 2 | String goodsId; 3 | String goodsName; 4 | int count; 5 | double price; 6 | String images; 7 | bool isCheck; 8 | 9 | CartInfoMode( 10 | {this.goodsId, this.goodsName, this.count, this.price, this.images,this.isCheck}); 11 | 12 | CartInfoMode.fromJson(Map json) { 13 | goodsId = json['goodsId']; 14 | goodsName = json['goodsName']; 15 | count = json['count']; 16 | price = json['price']; 17 | images = json['images']; 18 | isCheck = json['isCheck']; 19 | } 20 | 21 | Map toJson() { 22 | final Map data = new Map(); 23 | data['goodsId'] = this.goodsId; 24 | data['goodsName'] = this.goodsName; 25 | data['count'] = this.count; 26 | data['price'] = this.price; 27 | data['images'] = this.images; 28 | data['isCheck']= this.isCheck; 29 | return data; 30 | } 31 | } -------------------------------------------------------------------------------- /shflutter/lib/model/category.dart: -------------------------------------------------------------------------------- 1 | class CategoryModel { 2 | String code; 3 | String message; 4 | List data; 5 | 6 | CategoryModel({this.code, this.message, this.data}); 7 | 8 | CategoryModel.fromJson(Map json) { 9 | code = json['code']; 10 | message = json['message']; 11 | if (json['data'] != null) { 12 | data = new List(); 13 | json['data'].forEach((v) { 14 | data.add(new Data.fromJson(v)); 15 | }); 16 | } 17 | } 18 | 19 | Map toJson() { 20 | final Map data = new Map(); 21 | data['code'] = this.code; 22 | data['message'] = this.message; 23 | if (this.data != null) { 24 | data['data'] = this.data.map((v) => v.toJson()).toList(); 25 | } 26 | return data; 27 | } 28 | } 29 | 30 | class Data { 31 | String mallCategoryId; 32 | String mallCategoryName; 33 | List bxMallSubDto; 34 | Null comments; 35 | String image; 36 | 37 | Data( 38 | {this.mallCategoryId, 39 | this.mallCategoryName, 40 | this.bxMallSubDto, 41 | this.comments, 42 | this.image}); 43 | 44 | Data.fromJson(Map json) { 45 | mallCategoryId = json['mallCategoryId']; 46 | mallCategoryName = json['mallCategoryName']; 47 | if (json['bxMallSubDto'] != null) { 48 | bxMallSubDto = new List(); 49 | json['bxMallSubDto'].forEach((v) { 50 | bxMallSubDto.add(new BxMallSubDto.fromJson(v)); 51 | }); 52 | } 53 | comments = json['comments']; 54 | image = json['image']; 55 | } 56 | 57 | Map toJson() { 58 | final Map data = new Map(); 59 | data['mallCategoryId'] = this.mallCategoryId; 60 | data['mallCategoryName'] = this.mallCategoryName; 61 | if (this.bxMallSubDto != null) { 62 | data['bxMallSubDto'] = this.bxMallSubDto.map((v) => v.toJson()).toList(); 63 | } 64 | data['comments'] = this.comments; 65 | data['image'] = this.image; 66 | return data; 67 | } 68 | } 69 | 70 | class BxMallSubDto { 71 | String mallSubId; 72 | String mallCategoryId; 73 | String mallSubName; 74 | String comments; 75 | 76 | BxMallSubDto( 77 | {this.mallSubId, this.mallCategoryId, this.mallSubName, this.comments}); 78 | 79 | BxMallSubDto.fromJson(Map json) { 80 | mallSubId = json['mallSubId']; 81 | mallCategoryId = json['mallCategoryId']; 82 | mallSubName = json['mallSubName']; 83 | comments = json['comments']; 84 | } 85 | 86 | Map toJson() { 87 | final Map data = new Map(); 88 | data['mallSubId'] = this.mallSubId; 89 | data['mallCategoryId'] = this.mallCategoryId; 90 | data['mallSubName'] = this.mallSubName; 91 | data['comments'] = this.comments; 92 | return data; 93 | } 94 | } -------------------------------------------------------------------------------- /shflutter/lib/model/categoryGoodList.dart: -------------------------------------------------------------------------------- 1 | class CategoryGoodsListModel { 2 | String code; 3 | String message; 4 | List data; 5 | 6 | CategoryGoodsListModel({this.code, this.message, this.data}); 7 | 8 | CategoryGoodsListModel.fromJson(Map json) { 9 | code = json['code']; 10 | message = json['message']; 11 | if (json['data'] != null) { 12 | data = new List(); 13 | json['data'].forEach((v) { 14 | data.add(new CategoryListData.fromJson(v)); 15 | }); 16 | } 17 | } 18 | 19 | Map toJson() { 20 | final Map data = new Map(); 21 | data['code'] = this.code; 22 | data['message'] = this.message; 23 | if (this.data != null) { 24 | data['data'] = this.data.map((v) => v.toJson()).toList(); 25 | } 26 | return data; 27 | } 28 | } 29 | 30 | class CategoryListData { 31 | String image; 32 | double oriPrice; 33 | double presentPrice; 34 | String goodsName; 35 | String goodsId; 36 | 37 | CategoryListData( 38 | {this.image, 39 | this.oriPrice, 40 | this.presentPrice, 41 | this.goodsName, 42 | this.goodsId}); 43 | 44 | CategoryListData.fromJson(Map json) { 45 | image = json['image']; 46 | oriPrice = json['oriPrice']; 47 | presentPrice = json['presentPrice']; 48 | goodsName = json['goodsName']; 49 | goodsId = json['goodsId']; 50 | } 51 | 52 | Map toJson() { 53 | final Map data = new Map(); 54 | data['image'] = this.image; 55 | data['oriPrice'] = this.oriPrice; 56 | data['presentPrice'] = this.presentPrice; 57 | data['goodsName'] = this.goodsName; 58 | data['goodsId'] = this.goodsId; 59 | return data; 60 | } 61 | } -------------------------------------------------------------------------------- /shflutter/lib/model/details.dart: -------------------------------------------------------------------------------- 1 | class DetailsModel { 2 | String code; 3 | String message; 4 | DetailsGoodsData data; 5 | 6 | DetailsModel({this.code, this.message, this.data}); 7 | 8 | DetailsModel.fromJson(Map json) { 9 | code = json['code']; 10 | message = json['message']; 11 | data = json['data'] != null ? new DetailsGoodsData.fromJson(json['data']) : null; 12 | } 13 | 14 | Map toJson() { 15 | final Map data = new Map(); 16 | data['code'] = this.code; 17 | data['message'] = this.message; 18 | if (this.data != null) { 19 | data['data'] = this.data.toJson(); 20 | } 21 | return data; 22 | } 23 | } 24 | 25 | class DetailsGoodsData { 26 | GoodInfo goodInfo; 27 | List goodComments; 28 | AdvertesPicture advertesPicture; 29 | 30 | DetailsGoodsData({this.goodInfo, this.goodComments, this.advertesPicture}); 31 | 32 | DetailsGoodsData.fromJson(Map json) { 33 | goodInfo = json['goodInfo'] != null 34 | ? new GoodInfo.fromJson(json['goodInfo']) 35 | : null; 36 | if (json['goodComments'] != null) { 37 | goodComments = new List(); 38 | json['goodComments'].forEach((v) { 39 | goodComments.add(new GoodComments.fromJson(v)); 40 | }); 41 | } 42 | advertesPicture = json['advertesPicture'] != null 43 | ? new AdvertesPicture.fromJson(json['advertesPicture']) 44 | : null; 45 | } 46 | 47 | Map toJson() { 48 | final Map data = new Map(); 49 | if (this.goodInfo != null) { 50 | data['goodInfo'] = this.goodInfo.toJson(); 51 | } 52 | if (this.goodComments != null) { 53 | data['goodComments'] = this.goodComments.map((v) => v.toJson()).toList(); 54 | } 55 | if (this.advertesPicture != null) { 56 | data['advertesPicture'] = this.advertesPicture.toJson(); 57 | } 58 | return data; 59 | } 60 | } 61 | 62 | class GoodInfo { 63 | String image5; 64 | int amount; 65 | String image3; 66 | String image4; 67 | String goodsId; 68 | String isOnline; 69 | String image1; 70 | String image2; 71 | String goodsSerialNumber; 72 | double oriPrice; 73 | double presentPrice; 74 | String comPic; 75 | int state; 76 | String shopId; 77 | String goodsName; 78 | String goodsDetail; 79 | 80 | GoodInfo( 81 | {this.image5, 82 | this.amount, 83 | this.image3, 84 | this.image4, 85 | this.goodsId, 86 | this.isOnline, 87 | this.image1, 88 | this.image2, 89 | this.goodsSerialNumber, 90 | this.oriPrice, 91 | this.presentPrice, 92 | this.comPic, 93 | this.state, 94 | this.shopId, 95 | this.goodsName, 96 | this.goodsDetail}); 97 | 98 | GoodInfo.fromJson(Map json) { 99 | image5 = json['image5']; 100 | amount = json['amount']; 101 | image3 = json['image3']; 102 | image4 = json['image4']; 103 | goodsId = json['goodsId']; 104 | isOnline = json['isOnline']; 105 | image1 = json['image1']; 106 | image2 = json['image2']; 107 | goodsSerialNumber = json['goodsSerialNumber']; 108 | oriPrice = json['oriPrice']; 109 | presentPrice = json['presentPrice']; 110 | comPic = json['comPic']; 111 | state = json['state']; 112 | shopId = json['shopId']; 113 | goodsName = json['goodsName']; 114 | goodsDetail = json['goodsDetail']; 115 | } 116 | 117 | Map toJson() { 118 | final Map data = new Map(); 119 | data['image5'] = this.image5; 120 | data['amount'] = this.amount; 121 | data['image3'] = this.image3; 122 | data['image4'] = this.image4; 123 | data['goodsId'] = this.goodsId; 124 | data['isOnline'] = this.isOnline; 125 | data['image1'] = this.image1; 126 | data['image2'] = this.image2; 127 | data['goodsSerialNumber'] = this.goodsSerialNumber; 128 | data['oriPrice'] = this.oriPrice; 129 | data['presentPrice'] = this.presentPrice; 130 | data['comPic'] = this.comPic; 131 | data['state'] = this.state; 132 | data['shopId'] = this.shopId; 133 | data['goodsName'] = this.goodsName; 134 | data['goodsDetail'] = this.goodsDetail; 135 | return data; 136 | } 137 | } 138 | 139 | class GoodComments { 140 | int sCORE; 141 | String comments; 142 | String userName; 143 | int discussTime; 144 | 145 | GoodComments({this.sCORE, this.comments, this.userName, this.discussTime}); 146 | 147 | GoodComments.fromJson(Map json) { 148 | sCORE = json['SCORE']; 149 | comments = json['comments']; 150 | userName = json['userName']; 151 | discussTime = json['discussTime']; 152 | } 153 | 154 | Map toJson() { 155 | final Map data = new Map(); 156 | data['SCORE'] = this.sCORE; 157 | data['comments'] = this.comments; 158 | data['userName'] = this.userName; 159 | data['discussTime'] = this.discussTime; 160 | return data; 161 | } 162 | } 163 | 164 | class AdvertesPicture { 165 | String pICTUREADDRESS; 166 | String tOPLACE; 167 | 168 | AdvertesPicture({this.pICTUREADDRESS, this.tOPLACE}); 169 | 170 | AdvertesPicture.fromJson(Map json) { 171 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 172 | tOPLACE = json['TO_PLACE']; 173 | } 174 | 175 | Map toJson() { 176 | final Map data = new Map(); 177 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 178 | data['TO_PLACE'] = this.tOPLACE; 179 | return data; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /shflutter/lib/pages/cart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shflutter/pages/cart_page/cart_bottom.dart'; 3 | import 'package:shflutter/pages/cart_page/cart_item.dart'; 4 | import 'package:shflutter/provide/cart.dart'; 5 | import 'package:provide/provide.dart'; 6 | 7 | 8 | 9 | class CartPage extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar(title: Text('cartPage')), 14 | body: FutureBuilder( 15 | future: _getCartInfo(context), 16 | builder: (context,snapshot){ 17 | List cartList = Provide.value(context).cartList; 18 | if (snapshot.hasData && cartList != null) { 19 | return Stack( 20 | children: [ 21 | Provide( 22 | builder: (context,child,childCategory){ 23 | cartList = Provide.value(context).cartList; 24 | print(cartList); 25 | return ListView.builder( 26 | itemCount: cartList.length, 27 | itemBuilder: (context,index){ 28 | return CartItem(cartList[index]); 29 | }, 30 | ); 31 | }, 32 | ), 33 | Positioned( 34 | bottom:0, 35 | left:0, 36 | child: CartBottom(), 37 | ) 38 | ], 39 | ); 40 | } else { 41 | return Text('正在加载'); 42 | } 43 | }, 44 | ) 45 | ); 46 | } 47 | 48 | Future _getCartInfo(BuildContext context) async { 49 | await Provide.value(context).getCartInfo(); 50 | return 'end'; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/cart_page/cart_bottom.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:shflutter/provide/cart.dart'; 4 | import 'package:provide/provide.dart'; 5 | 6 | class CartBottom extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | margin: EdgeInsets.all(5.0), 11 | color: Colors.white, 12 | width: ScreenUtil().setWidth(750), 13 | child: Provide( 14 | builder: (context,child,childCategory){ 15 | return Row( 16 | children: [ 17 | selectAllBtn(context), 18 | allPriceArea(context), 19 | goButton(context) 20 | ], 21 | ); 22 | }, 23 | ) 24 | 25 | ); 26 | } 27 | //全选按钮 28 | Widget selectAllBtn(context){ 29 | bool isAllCheck = Provide.value(context).isAllCheck; 30 | return Container( 31 | child: Row( 32 | children: [ 33 | Checkbox( 34 | value: isAllCheck, 35 | activeColor: Colors.pink, 36 | onChanged: (bool val){ 37 | Provide.value(context).changeAllCheckBtnState(val); 38 | }, 39 | ), 40 | Text('全选') 41 | ], 42 | ), 43 | ); 44 | } 45 | 46 | // 合计区域 47 | Widget allPriceArea(context){ 48 | double allPrice = Provide.value(context).allPrice; 49 | return Container( 50 | width: ScreenUtil().setWidth(430), 51 | alignment: Alignment.centerRight, 52 | child: Column( 53 | children: [ 54 | Row( 55 | children: [ 56 | Container( 57 | alignment: Alignment.centerRight, 58 | width: ScreenUtil().setWidth(280), 59 | child: Text( 60 | '合计:', 61 | style: TextStyle( 62 | fontSize: ScreenUtil().setSp(36) 63 | ), 64 | ), 65 | ), 66 | Container( 67 | alignment: Alignment.centerLeft, 68 | width: ScreenUtil().setWidth(150), 69 | child: Text( 70 | '¥${allPrice}', 71 | style: TextStyle( 72 | fontSize: ScreenUtil().setSp(36), 73 | color: Colors.red, 74 | ), 75 | ), 76 | ) 77 | ], 78 | ), 79 | Container( 80 | width: ScreenUtil().setWidth(430), 81 | alignment: Alignment.centerRight, 82 | child: Text( 83 | '满10元免配送费,预购免配送费', 84 | style: TextStyle( 85 | color: Colors.black38, 86 | fontSize: ScreenUtil().setSp(22) 87 | ), 88 | ), 89 | ) 90 | ], 91 | ), 92 | ); 93 | } 94 | 95 | //结算按钮 96 | Widget goButton(context){ 97 | int allGoodsCount = Provide.value(context).allGoodsCount; 98 | return Container( 99 | width: ScreenUtil().setWidth(160), 100 | padding: EdgeInsets.only(left: 10), 101 | child:InkWell( 102 | onTap: (){}, 103 | child: Container( 104 | padding: EdgeInsets.all(10.0), 105 | alignment: Alignment.center, 106 | decoration: BoxDecoration( 107 | color: Colors.red, 108 | borderRadius: BorderRadius.circular(3.0) 109 | ), 110 | child: Text( 111 | '结算(${allGoodsCount})', 112 | style: TextStyle( 113 | color: Colors.white 114 | ), 115 | ), 116 | ), 117 | ) , 118 | ); 119 | } 120 | 121 | 122 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/cart_page/cart_count.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:shflutter/provide/cart.dart'; 4 | import 'package:provide/provide.dart'; 5 | 6 | class CartCount extends StatelessWidget { 7 | var item; 8 | CartCount(this.item); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Container( 13 | width: ScreenUtil().setWidth(165), 14 | margin: EdgeInsets.only(top:5.0), 15 | decoration: BoxDecoration( 16 | border:Border.all(width: 1 , color:Colors.black12) 17 | ), 18 | child: Row( 19 | children: [ 20 | _reduceBtn(context), 21 | _countArea(), 22 | _addBtn(context), 23 | ], 24 | ), 25 | ); 26 | } 27 | // 减少按钮 28 | Widget _reduceBtn(context){ 29 | return InkWell( 30 | onTap: (){ 31 | Provide.value(context).addOrReduceAction(item,'reduce'); 32 | }, 33 | child: Container( 34 | width: ScreenUtil().setWidth(45), 35 | height: ScreenUtil().setHeight(45), 36 | alignment: Alignment.center, 37 | 38 | decoration: BoxDecoration( 39 | color: item.count>1?Colors.white:Colors.black12, 40 | border:Border( 41 | right:BorderSide(width:1,color:Colors.black12) 42 | ) 43 | ), 44 | child:item.count>1? Text('-'):Text(' '), 45 | ), 46 | ); 47 | } 48 | 49 | //添加按钮 50 | Widget _addBtn(context){ 51 | return InkWell( 52 | onTap: (){ 53 | Provide.value(context).addOrReduceAction(item,'add'); 54 | }, 55 | child: Container( 56 | width: ScreenUtil().setWidth(45), 57 | height: ScreenUtil().setHeight(45), 58 | alignment: Alignment.center, 59 | 60 | decoration: BoxDecoration( 61 | color: Colors.white, 62 | border:Border( 63 | left:BorderSide(width:1,color:Colors.black12) 64 | ) 65 | ), 66 | child: Text('+'), 67 | ), 68 | ); 69 | } 70 | 71 | //中间数量显示区域 72 | Widget _countArea(){ 73 | return Container( 74 | width: ScreenUtil().setWidth(70), 75 | height: ScreenUtil().setHeight(45), 76 | alignment: Alignment.center, 77 | color: Colors.white, 78 | child: Text('${item.count}'), 79 | ); 80 | } 81 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/cart_page/cart_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:shflutter/model/cartInfo.dart'; 4 | import 'package:shflutter/pages/cart_page/cart_count.dart'; 5 | import 'package:shflutter/provide/cart.dart'; 6 | import 'package:provide/provide.dart'; 7 | 8 | class CartItem extends StatelessWidget { 9 | final CartInfoMode item; 10 | CartItem(this.item); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | print(item); 15 | 16 | return Container( 17 | margin: EdgeInsets.fromLTRB(5.0,2.0,5.0,2.0), 18 | padding: EdgeInsets.fromLTRB(5.0,10.0,5.0,10.0), 19 | decoration: BoxDecoration( 20 | color: Colors.white, 21 | border: Border( 22 | bottom: BorderSide(width:1,color:Colors.black12) 23 | ) 24 | ), 25 | child: Row( 26 | children: [ 27 | _cartCheckBt(context,item), 28 | _cartImage(item), 29 | _cartGoodsName(item), 30 | _cartPrice(context,item) 31 | ], 32 | ), 33 | 34 | ); 35 | } 36 | 37 | 38 | //多选按钮 39 | Widget _cartCheckBt(context,item){ 40 | return Container( 41 | child: Checkbox( 42 | value: item.isCheck, 43 | activeColor:Colors.pink, 44 | onChanged: (bool val){ 45 | item.isCheck=val; 46 | Provide.value(context).changeCheckState(item); 47 | }, 48 | ), 49 | ); 50 | } 51 | 52 | //商品图片 53 | Widget _cartImage(item){ 54 | 55 | return Container( 56 | width: ScreenUtil().setWidth(150), 57 | padding: EdgeInsets.all(3.0), 58 | decoration: BoxDecoration( 59 | border: Border.all(width: 1,color:Colors.black12) 60 | ), 61 | child: Image.network(item.images), 62 | ); 63 | } 64 | 65 | //商品名称 66 | Widget _cartGoodsName(item){ 67 | return Container( 68 | width: ScreenUtil().setWidth(300), 69 | padding: EdgeInsets.all(10), 70 | alignment: Alignment.topLeft, 71 | child: Column( 72 | children: [ 73 | Text(item.goodsName), 74 | CartCount(item) 75 | ], 76 | ), 77 | ); 78 | } 79 | 80 | 81 | //商品价格 82 | Widget _cartPrice(context,item){ 83 | 84 | return Container( 85 | width:ScreenUtil().setWidth(150) , 86 | alignment: Alignment.centerRight, 87 | 88 | child: Column( 89 | children: [ 90 | Text('¥${item.price}'), 91 | Container( 92 | child: InkWell( 93 | onTap: (){ 94 | Provide.value(context).deleteOneGoods(item.goodsId); 95 | }, 96 | child: Icon( 97 | Icons.delete_forever, 98 | color: Colors.black26, 99 | size: 30, 100 | ), 101 | ), 102 | ) 103 | ], 104 | ), 105 | ); 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/category_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 5 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 6 | import 'package:shflutter/model/category.dart'; 7 | import 'package:shflutter/model/categoryGoodList.dart'; 8 | import 'package:shflutter/provide/child_category.dart'; 9 | import 'package:shflutter/routers/application.dart'; 10 | import 'package:shflutter/service/service_method.dart'; 11 | import 'package:provide/provide.dart'; 12 | import '../provide/category_goods_list.dart'; 13 | import 'package:fluttertoast/fluttertoast.dart'; 14 | 15 | 16 | class CategoryPage extends StatefulWidget { 17 | @override 18 | _CategoryPageState createState() => _CategoryPageState(); 19 | } 20 | 21 | class _CategoryPageState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | appBar: AppBar( 26 | title: Text('Category'), 27 | ), 28 | body: Container( 29 | child: Row( 30 | children: [ 31 | LeftCategoryNav(), 32 | Column( 33 | children: [ 34 | RightCategoryNav(), 35 | CategoryGoodsList() 36 | ], 37 | ) 38 | ], 39 | ), 40 | ), 41 | ); 42 | } 43 | } 44 | 45 | //商品列表,可以上拉加载 46 | class CategoryGoodsList extends StatefulWidget { 47 | @override 48 | _CategoryGoodsListState createState() => _CategoryGoodsListState(); 49 | } 50 | 51 | class _CategoryGoodsListState extends State { 52 | 53 | var scrollController = new ScrollController(); 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return Provide( 58 | builder: (context,child,data){ 59 | try{ 60 | if(Provide.value(context).page==1){ 61 | scrollController.jumpTo(0.0); 62 | } 63 | }catch(e){ 64 | print('进入页面第一次初始化:${e}'); 65 | } 66 | 67 | if (data.goodsList.length > 0) { 68 | return Expanded( 69 | child: Container( 70 | width: ScreenUtil().setWidth(570), 71 | child: EasyRefresh( 72 | footer: ClassicalFooter( 73 | bgColor: Colors.white, 74 | textColor: Colors.pink, 75 | showInfo: true, 76 | noMoreText: Provide.value(context).noMoreText, 77 | infoText: '加载中', 78 | loadReadyText: '上拉加载', 79 | ), 80 | 81 | child: ListView.builder( 82 | controller: scrollController, 83 | itemCount: data.goodsList.length, 84 | itemBuilder: (context,index){ 85 | return _listWidge(data.goodsList,index); 86 | }, 87 | ), 88 | onLoad: ()async{ 89 | if (Provide.value(context).noMoreText == '没有更多了') { 90 | Fluttertoast.showToast( 91 | msg: "已经到底了", 92 | toastLength: Toast.LENGTH_SHORT, 93 | gravity: ToastGravity.CENTER, 94 | timeInSecForIosWeb: 1, 95 | backgroundColor: Colors.pink, 96 | textColor: Colors.white, 97 | fontSize: 16.0 98 | ); 99 | } else { 100 | _getMoreList(); 101 | } 102 | }, 103 | ), 104 | ), 105 | ); 106 | }else { 107 | return Text('暂时没有数据'); 108 | } 109 | 110 | }, 111 | ); 112 | } 113 | 114 | Widget _listWidge(List newList, int index){ 115 | return InkWell( 116 | onTap: (){ 117 | Application.router.navigateTo(context,"/detail?id=${newList[index].goodsId}"); 118 | }, 119 | child: Container( 120 | padding: EdgeInsets.only(top: 5.0,bottom: 5.0), 121 | decoration: BoxDecoration( 122 | color: Colors.white, 123 | border: Border( 124 | bottom: BorderSide(width: 1.0,color: Colors.black12) 125 | ) 126 | ), 127 | child: Row( 128 | children: [ 129 | _goodsImage(newList,index), 130 | Column( 131 | children: [ 132 | _goodsName(newList,index), 133 | _goodsPrice(newList,index) 134 | ], 135 | ) 136 | ], 137 | ), 138 | ), 139 | ); 140 | } 141 | //商品图片 142 | Widget _goodsImage(List newList, int index){ 143 | return Container( 144 | width: ScreenUtil().setWidth(200), 145 | child: Image.network(newList[index].image), 146 | ); 147 | } 148 | 149 | //商品名称方法 150 | Widget _goodsName(List newList, int index){ 151 | return Container( 152 | padding: EdgeInsets.all(5.0), 153 | width: ScreenUtil().setWidth(370), 154 | child: Text( 155 | newList[index].goodsName, 156 | maxLines: 2, 157 | overflow: TextOverflow.ellipsis, 158 | style: TextStyle(fontSize: ScreenUtil().setSp(28)), 159 | ), 160 | ); 161 | } 162 | 163 | //商品价格方法 164 | Widget _goodsPrice(List newList, int index){ 165 | return Container( 166 | margin: EdgeInsets.only(top:20.0), 167 | width: ScreenUtil().setWidth(370), 168 | child: Row( 169 | children: [ 170 | Text( 171 | '价格:¥${newList[index].presentPrice}', 172 | style: TextStyle( 173 | color:Colors.pink, 174 | fontSize:ScreenUtil().setSp(30) 175 | ), 176 | ), 177 | Text( 178 | '¥${newList[index].oriPrice}', 179 | style: TextStyle( 180 | color:Colors.pink, 181 | fontSize:ScreenUtil().setSp(30) 182 | ), 183 | ), 184 | ], 185 | ), 186 | ); 187 | } 188 | 189 | //上拉加载更多的方法 190 | void _getMoreList(){ 191 | Provide.value(context).addPage(); 192 | var data = { 193 | 'categoryId':Provide.value(context).categoryId, 194 | 'categorySubId':Provide.value(context).subId, 195 | 'page':Provide.value(context).page 196 | }; 197 | 198 | request('getMallGoods',formData:data).then((val){ 199 | var data = json.decode(val.toString()); 200 | CategoryGoodsListModel goodsList = CategoryGoodsListModel.fromJson(data); 201 | if (goodsList.data == null) { 202 | Provide.value(context).changeNoMore('没有更多了'); 203 | } else { 204 | Provide.value(context).addGoodsList(goodsList.data); 205 | } 206 | }); 207 | } 208 | 209 | } 210 | //右侧小类类别 211 | class RightCategoryNav extends StatefulWidget { 212 | @override 213 | _RightCategoryNavState createState() => _RightCategoryNavState(); 214 | } 215 | 216 | class _RightCategoryNavState extends State { 217 | @override 218 | Widget build(BuildContext context) { 219 | return Container( 220 | child: Provide( 221 | builder: (context,child,childCategory){ 222 | return Container( 223 | height: ScreenUtil().setHeight(80), 224 | width: ScreenUtil().setWidth(570), 225 | decoration: BoxDecoration( 226 | color: Colors.white, 227 | border: Border( 228 | bottom: BorderSide(width: 1,color: Colors.black12) 229 | ) 230 | ), 231 | child: ListView.builder( 232 | scrollDirection: Axis.horizontal, 233 | itemCount: childCategory.childCategoryList.length, 234 | itemBuilder: (context,index){ 235 | return _rightInkWell(index,childCategory.childCategoryList[index]); 236 | }, 237 | ), 238 | ); 239 | }, 240 | ) 241 | ); 242 | } 243 | 244 | Widget _rightInkWell(int index,BxMallSubDto item){ 245 | bool isCheck = false; 246 | isCheck = (index == Provide.value(context).childIndex)?true:false; 247 | return InkWell( 248 | onTap: (){ 249 | print ('_RightCategoryNavState_rightInkWell'); 250 | Provide.value(context).changeChildIndex(index,item.mallSubId); 251 | _getGoodList(context,item.mallSubId); 252 | }, 253 | child: Container( 254 | padding: EdgeInsets.fromLTRB(5.0,10.0,5.0,10.0), 255 | child: Text( 256 | item.mallSubName, 257 | style: TextStyle( 258 | fontSize: ScreenUtil().setSp(28), 259 | color: isCheck?Colors.pink:Colors.black 260 | ), 261 | ), 262 | ), 263 | ); 264 | } 265 | 266 | //得到商品列表数据 267 | void _getGoodList(context,String categorySubId){ 268 | var data = { 269 | 'categoryId':Provide.value(context).categoryId, 270 | 'categorySubId':categorySubId, 271 | 'page':1 272 | }; 273 | 274 | request('getMallGoods',formData:data ).then((val){ 275 | var data = json.decode(val.toString()); 276 | CategoryGoodsListModel goodsList= CategoryGoodsListModel.fromJson(data); 277 | if(goodsList.data==null){ 278 | Provide.value(context).getGoodsList([]); 279 | }else{ 280 | Provide.value(context).getGoodsList(goodsList.data); 281 | 282 | } 283 | }); 284 | 285 | } 286 | 287 | } 288 | 289 | //左侧导航菜单 290 | class LeftCategoryNav extends StatefulWidget { 291 | @override 292 | _LeftCategoryNavState createState() => _LeftCategoryNavState(); 293 | } 294 | 295 | class _LeftCategoryNavState extends State { 296 | List list = []; 297 | var listIndex = 0;//索引 298 | 299 | @override 300 | void initState() { 301 | _getCategory(); 302 | // TODO: implement initState 303 | super.initState(); 304 | } 305 | @override 306 | Widget build(BuildContext context) { 307 | return Provide( 308 | builder: (context,child,val){ 309 | _getGoodList(context); 310 | listIndex = val.categoryIndex; 311 | return Container( 312 | width: ScreenUtil().setWidth(180), 313 | decoration: BoxDecoration( 314 | border: Border(right: BorderSide(width: 1,color: Colors.black12)), 315 | ), 316 | child: ListView.builder( 317 | itemCount: list.length, 318 | itemBuilder: (context,index){ 319 | return _leftInkWell(index); 320 | }, 321 | ), 322 | ); 323 | }, 324 | ); 325 | } 326 | 327 | 328 | Widget _leftInkWell(int index ){ 329 | bool isClick = false; 330 | isClick = (index == listIndex)?true:false; 331 | 332 | return InkWell( 333 | onTap: (){ 334 | var childList = list[index].bxMallSubDto; 335 | var categoryId = list[index].mallCategoryId; 336 | Provide.value(context).changeCategory(categoryId,index); 337 | Provide.value(context).getChildCategory(childList,categoryId); 338 | _getGoodList(context,categoryId: categoryId); 339 | }, 340 | child: Container( 341 | height: ScreenUtil().setHeight(100), 342 | padding: EdgeInsets.only(left: 10,top: 20), 343 | decoration: BoxDecoration( 344 | color: isClick?Color.fromRGBO(236,238,239,1.0):Colors.white, 345 | border: Border(bottom: BorderSide(width: 1,color: Colors.black12)) 346 | ), 347 | child: Text( 348 | list[index].mallCategoryName, 349 | style: TextStyle(fontSize: ScreenUtil().setSp(28)), 350 | ), 351 | ), 352 | ); 353 | } 354 | 355 | 356 | 357 | //得到后台大类数据 358 | void _getCategory()async { 359 | await request('getCategory').then((val){ 360 | var data = json.decode(val.toString()); 361 | 362 | CategoryModel category = CategoryModel.fromJson(data); 363 | setState(() { 364 | list = category.data; 365 | }); 366 | Provide.value(context).getChildCategory(list[0].bxMallSubDto,'4'); 367 | 368 | }); 369 | } 370 | 371 | //得到商品列表数据 372 | 373 | void _getGoodList(context, {String categoryId}) { 374 | var data = { 375 | 'categoryId':categoryId==null?Provide.value(context).categoryId:categoryId, 376 | 'categorySubId':Provide.value(context).subId, 377 | 'page':1 378 | }; 379 | 380 | request('getMallGoods',formData:data).then((val){ 381 | var data = json.decode(val.toString()); 382 | CategoryGoodsListModel goodsList= CategoryGoodsListModel.fromJson(data); 383 | Provide.value(context).getGoodsList(goodsList.data); 384 | }); 385 | } 386 | 387 | 388 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_bottom.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:shflutter/provide/cart.dart'; 4 | import 'package:shflutter/provide/current_index.dart'; 5 | import 'package:shflutter/provide/details_info.dart'; 6 | import 'package:provide/provide.dart'; 7 | 8 | class DetailsBottom extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | var goodsInfo = Provide.value(context).goodsInfo.data.goodInfo; 12 | var goodsId = goodsInfo.goodsId; 13 | var goodsName =goodsInfo.goodsName; 14 | var count =1; 15 | var price =goodsInfo.presentPrice; 16 | var images= goodsInfo.image1; 17 | 18 | return Container( 19 | width: ScreenUtil().setWidth(750), 20 | color: Colors.white, 21 | height: ScreenUtil().setHeight(80), 22 | child: Row( 23 | children: [ 24 | Stack( 25 | children: [ 26 | InkWell( 27 | onTap: (){ 28 | Provide.value(context).changeIndex(2); 29 | Navigator.pop(context); 30 | }, 31 | child: Container( 32 | width: ScreenUtil().setWidth(110), 33 | alignment: Alignment.center, 34 | child: Icon( 35 | Icons.shopping_cart, 36 | size: 35, 37 | color: Colors.red, 38 | ), 39 | ), 40 | ), 41 | Provide( 42 | builder: (context,child,val){ 43 | int goodsCount = Provide.value(context).allGoodsCount; 44 | return Positioned( 45 | top: 0, 46 | right: 10, 47 | child: Container( 48 | padding: EdgeInsets.fromLTRB(6,3,6,3), 49 | decoration: BoxDecoration( 50 | color: Colors.pink, 51 | border: Border.all(width: 2,color: Colors.white), 52 | borderRadius: BorderRadius.circular(12.0) 53 | ), 54 | child: Text( 55 | '${goodsCount}', 56 | style: TextStyle( 57 | color: Colors.white, 58 | fontSize: ScreenUtil().setSp(22) 59 | ), 60 | ), 61 | ), 62 | ); 63 | }, 64 | ) 65 | ], 66 | ), 67 | InkWell( 68 | onTap: ()async { 69 | await Provide.value(context).save(goodsId,goodsName,count,price,images); 70 | }, 71 | child: Container( 72 | alignment: Alignment.center, 73 | width: ScreenUtil().setWidth(320), 74 | height: ScreenUtil().setHeight(80), 75 | color: Colors.green, 76 | child: Text( 77 | '加入购物车', 78 | style: TextStyle( 79 | color: Colors.white, 80 | fontSize: ScreenUtil().setSp(28) 81 | ), 82 | ), 83 | ), 84 | ), 85 | InkWell( 86 | onTap: ()async{ 87 | await Provide.value(context).remove(); 88 | }, 89 | child: Container( 90 | alignment: Alignment.center, 91 | width: ScreenUtil().setWidth(320), 92 | height: ScreenUtil().setHeight(80), 93 | color: Colors.red, 94 | child: Text( 95 | '马上购买', 96 | style: TextStyle(color: Colors.white,fontSize: ScreenUtil().setSp(28)), 97 | ), 98 | ) 99 | ) 100 | 101 | ], 102 | ), 103 | ); 104 | } 105 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_explain.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | class DetailsExplain extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Container( 8 | color: Colors.white, 9 | margin: EdgeInsets.only(top: 10), 10 | width: ScreenUtil().setWidth(750), 11 | padding: EdgeInsets.all(10.0), 12 | child: Text( 13 | '说明:> 急速送达 > 正品保证', 14 | style: TextStyle( 15 | color:Colors.red, 16 | fontSize:ScreenUtil().setSp(30) 17 | ), 18 | ), 19 | ); 20 | } 21 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_page.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:shflutter/pages/details_page/details_bottom.dart'; 4 | import 'package:shflutter/pages/details_page/details_tabBar.dart'; 5 | import 'package:shflutter/pages/details_page/details_web.dart'; 6 | import './details_explain.dart'; 7 | import './details_top_area.dart'; 8 | import 'package:provide/provide.dart'; 9 | import '../../provide/details_info.dart'; 10 | 11 | 12 | 13 | class DetailsPage extends StatelessWidget { 14 | final String goodsId; 15 | DetailsPage(this.goodsId); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | 20 | return Scaffold( 21 | appBar: AppBar( 22 | leading:IconButton( 23 | icon: Icon(Icons.arrow_back), 24 | onPressed: (){ 25 | print('back'); 26 | Navigator.pop(context); 27 | }, 28 | ), 29 | title: Text('Detail'), 30 | ), 31 | //异步UI更新FutureBuilder,依赖一个Future通常是一个异步耗时任务,它会根据所依赖的Future的状态来动态构建自身 32 | body: FutureBuilder( 33 | future: _getBackInfo(context), 34 | builder: (context,snapshot) { 35 | if(snapshot.hasData) { 36 | return Stack( 37 | children: [ 38 | ListView( 39 | children: [ 40 | DetailsTopArea(), 41 | DetailsExplain(), 42 | DetailsTabBar(), 43 | DetailsWeb() 44 | ], 45 | ), 46 | 47 | Positioned( 48 | bottom: 0, 49 | left: 0, 50 | child: DetailsBottom() 51 | ) 52 | ], 53 | ); 54 | }else { 55 | return Text('loading...'); 56 | } 57 | } 58 | ) 59 | 60 | ); 61 | } 62 | 63 | Future _getBackInfo(BuildContext context)async { 64 | await Provide.value(context).getGoodInfo(goodsId); 65 | return '完成加载'; 66 | } 67 | 68 | 69 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_tabBar.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:shflutter/provide/details_info.dart'; 5 | import 'package:provide/provide.dart'; 6 | 7 | class DetailsTabBar extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return Provide( 11 | builder: (context,child,val){ 12 | var isLeft = Provide.value(context).isLeft; 13 | var isRight = Provide.value(context).isRight; 14 | return Container( 15 | margin: EdgeInsets.only(top: 15.0), 16 | child: Column( 17 | children: [ 18 | Row( 19 | children: [ 20 | _myTabBarLeft(context,isLeft), 21 | _myTabBarRight(context,isRight) 22 | ], 23 | ), 24 | ], 25 | ), 26 | ); 27 | } 28 | ); 29 | } 30 | 31 | Widget _myTabBarLeft(BuildContext context, bool isLeft){ 32 | return InkWell( 33 | onTap: (){ 34 | print('click_tabBar_Left'); 35 | Provide.value(context).changeLeftAndRight('left'); 36 | }, 37 | child: Container( 38 | padding: EdgeInsets.all(10.0), 39 | alignment: Alignment.center, 40 | width: ScreenUtil().setWidth(375), 41 | decoration: BoxDecoration( 42 | color: Colors.white, 43 | border: Border( 44 | bottom: BorderSide( 45 | width: 1.0, 46 | color: isLeft ? Colors.pink: Colors.black12 47 | ) 48 | ) 49 | ), 50 | child: Text( 51 | '详细', 52 | style: TextStyle( 53 | color: isLeft?Colors.pink:Colors.black 54 | ), 55 | ), 56 | ), 57 | ); 58 | } 59 | 60 | Widget _myTabBarRight(BuildContext context, bool isRight){ 61 | return InkWell( 62 | onTap: (){ 63 | print('click_tabBar_right'); 64 | Provide.value(context).changeLeftAndRight('right'); 65 | }, 66 | child: Container( 67 | padding: EdgeInsets.all(10.0), 68 | alignment: Alignment.center, 69 | width: ScreenUtil().setWidth(375), 70 | decoration: BoxDecoration( 71 | color: Colors.white, 72 | border: Border( 73 | bottom: BorderSide( 74 | width: 1.0, 75 | color: isRight?Colors.pink:Colors.black12 76 | ) 77 | ) 78 | ), 79 | 80 | child: Text( 81 | '评论', 82 | style: TextStyle( 83 | color: isRight?Colors.pink:Colors.black 84 | ), 85 | ), 86 | 87 | ), 88 | ); 89 | } 90 | 91 | 92 | 93 | 94 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_top_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:provide/provide.dart'; 4 | import '../../provide/details_info.dart'; 5 | 6 | class DetailsTopArea extends StatelessWidget { 7 | //商品图片 8 | Widget _goodsImage(url){ 9 | return Image.network( 10 | url, 11 | width: ScreenUtil().setWidth(740) 12 | ); 13 | } 14 | 15 | //商品编号 16 | Widget _goodsNum(num) { 17 | return Container( 18 | width: ScreenUtil().setWidth(730), 19 | padding: EdgeInsets.only(left: 15.0), 20 | margin: EdgeInsets.only(top: 8.0), 21 | child: Text( 22 | '编号:${num}', 23 | style: TextStyle( 24 | color: Colors.black26 25 | ), 26 | ), 27 | ); 28 | } 29 | 30 | //商品名称 31 | Widget _goodsName(name){ 32 | 33 | return Container( 34 | 35 | width: ScreenUtil().setWidth(730), 36 | padding: EdgeInsets.only(left:15.0), 37 | child: Text( 38 | name, 39 | maxLines: 1, 40 | style: TextStyle( 41 | fontSize: ScreenUtil().setSp(30) 42 | ), 43 | ), 44 | ); 45 | } 46 | 47 | //商品价格方法 48 | Widget _goodsPrice(presentPrice,oriPrice){ 49 | 50 | return Container( 51 | 52 | width: ScreenUtil().setWidth(730), 53 | padding: EdgeInsets.only(left:15.0), 54 | margin: EdgeInsets.only(top:8.0), 55 | child: Row( 56 | children: [ 57 | Text( 58 | '¥${presentPrice}', 59 | style: TextStyle( 60 | color:Colors.pinkAccent, 61 | fontSize: ScreenUtil().setSp(40), 62 | 63 | ), 64 | 65 | ), 66 | Text( 67 | '市场价:¥${oriPrice}', 68 | style: TextStyle( 69 | color: Colors.black26, 70 | decoration: TextDecoration.lineThrough 71 | ), 72 | ) 73 | ], 74 | ), 75 | ); 76 | 77 | } 78 | 79 | @override 80 | Widget build(BuildContext context) { 81 | return Provide( 82 | builder: (context,child,val){ 83 | var goodsInfo = Provide.value(context).goodsInfo.data.goodInfo; 84 | if (goodsInfo != null) { 85 | return Container( 86 | color: Colors.white, 87 | padding: EdgeInsets.all(2.0), 88 | child: Column( 89 | children: [ 90 | _goodsImage(goodsInfo.image1), 91 | _goodsName( goodsInfo.goodsName ), 92 | _goodsNum(goodsInfo.goodsSerialNumber), 93 | _goodsPrice(goodsInfo.presentPrice,goodsInfo.oriPrice), 94 | ], 95 | ), 96 | ); 97 | } else { 98 | return Text('loading...'); 99 | } 100 | }, 101 | ); 102 | } 103 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/details_page/details_web.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:shflutter/provide/details_info.dart'; 5 | import 'package:provide/provide.dart'; 6 | import 'package:flutter_html/flutter_html.dart'; 7 | 8 | 9 | class DetailsWeb extends StatelessWidget { 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | var goodsDetail=Provide.value(context).goodsInfo.data.goodInfo.goodsDetail; 14 | 15 | return Provide( 16 | builder: (context,child,val){ 17 | var isLeft = Provide.value(context).isLeft; 18 | if (isLeft) { 19 | return Container( 20 | child: Html( 21 | data:goodsDetail 22 | ), 23 | ); 24 | } else { 25 | return Container( 26 | width: ScreenUtil().setWidth(750), 27 | padding: EdgeInsets.all(10), 28 | alignment: Alignment.center, 29 | child: Text('暂无数据') 30 | ); 31 | } 32 | } 33 | ); 34 | } 35 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:flutter_swiper/flutter_swiper.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | import '../service/service_method.dart'; 7 | import 'dart:convert'; //json解析用 8 | import '../routers/application.dart'; 9 | import '../model/category.dart'; 10 | import 'package:provide/provide.dart'; 11 | import '../provide/child_category.dart'; 12 | import '../provide/current_index.dart'; 13 | 14 | class HomePage extends StatefulWidget { 15 | @override 16 | _HomePageState createState() => _HomePageState(); 17 | } 18 | 19 | class _HomePageState extends State { 20 | int page = 1; 21 | List hotGoodsList=[]; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | 26 | var formData = {'lon':'115.02932','lat':'35.76189'}; 27 | return Scaffold( 28 | backgroundColor: Color.fromRGBO(244, 245, 245, 1.0), 29 | appBar: AppBar(title: Text('Lift+'),), 30 | body: FutureBuilder( 31 | future: request('homePageContext',formData: formData), 32 | builder: (context, snapshot) { 33 | if(snapshot.hasData) { 34 | var data = json.decode(snapshot.data.toString()); 35 | List swiperDataList = (data['data']['slides'] as List).cast();// 顶部轮播组件数 36 | List navigatorList = (data['data']['category'] as List).cast();//类别列表 37 | String advertesPicture = data['data']['advertesPicture']['PICTURE_ADDRESS']; //广告图片 38 | String leaderImage= data['data']['shopInfo']['leaderImage']; //店长图片 39 | String leaderPhone = data['data']['shopInfo']['leaderPhone']; //店长电话 40 | List recommendList = (data['data']['recommend'] as List).cast(); // 商品推荐 41 | String floor1Title =data['data']['floor1Pic']['PICTURE_ADDRESS'];//楼层1的标题图片 42 | String floor2Title =data['data']['floor2Pic']['PICTURE_ADDRESS'];//楼层1的标题图片 43 | String floor3Title =data['data']['floor3Pic']['PICTURE_ADDRESS'];//楼层1的标题图片 44 | List floor1 = (data['data']['floor1'] as List).cast(); //楼层1商品和图片 45 | List floor2 = (data['data']['floor2'] as List).cast(); //楼层1商品和图片 46 | List floor3 = (data['data']['floor3'] as List).cast(); //楼层1商品和图片 47 | 48 | 49 | return EasyRefresh( 50 | footer: MaterialFooter( 51 | 52 | ), 53 | child: ListView( 54 | children: [ 55 | HomeSwiperDiy(swiperDataList: swiperDataList), 56 | HomeTopNavigator(navigatorList: navigatorList), 57 | HomeAdBanner(advertesPicture: advertesPicture), 58 | HomeLeaderPhone(leaderImage: leaderImage,leaderPhone: leaderPhone), 59 | HomeRecommend(recommendList: recommendList), 60 | HomeFloorTitle(picture_address:floor1Title), 61 | HomeFloorContent(floorGoodsList:floor1), 62 | HomeFloorTitle(picture_address:floor2Title), 63 | HomeFloorContent(floorGoodsList:floor2), 64 | HomeFloorTitle(picture_address:floor3Title), 65 | HomeFloorContent(floorGoodsList:floor3), 66 | _hotGoods(), 67 | ], 68 | ), 69 | onLoad:() async { 70 | print('开始加载更多'); 71 | var formPage = {'page':page}; 72 | await request('homePageBelowConten',formData:formPage).then((val){ 73 | var data = json.decode(val.toString()); 74 | List newGoodsList = (data['data']as List).cast(); 75 | setState(() { 76 | hotGoodsList.addAll(newGoodsList); 77 | page++; 78 | }); 79 | }); 80 | }, 81 | 82 | ); 83 | } else { 84 | return Center( 85 | child:Text('加载中'), 86 | ); 87 | } 88 | }, 89 | 90 | ), 91 | ); 92 | } 93 | 94 | //火爆专区标题 95 | Widget hotTitle = Container( 96 | margin: EdgeInsets.only(top: 10.0), 97 | padding: EdgeInsets.all(5.0), 98 | alignment: Alignment.center, 99 | decoration: BoxDecoration( 100 | color: Colors.white, 101 | border: Border( 102 | bottom: BorderSide(width: 0.5,color: Colors.black12) 103 | ) 104 | ), 105 | child: Text('火爆专区'), 106 | ); 107 | 108 | //火爆专区子项 109 | Widget _wrapList(){ 110 | if (hotGoodsList.length != 0) { 111 | List listWidget = hotGoodsList.map((val){ 112 | return InkWell( 113 | onTap: (){ 114 | Application.router.navigateTo(context,"/detail?id=${val['goodsId']}"); 115 | }, 116 | child: Container( 117 | width: ScreenUtil().setWidth(372), 118 | color:Colors.white, 119 | padding: EdgeInsets.all(5.0), 120 | margin:EdgeInsets.only(bottom:3.0), 121 | child: Column( 122 | children: [ 123 | Image.network(val['image'],width: ScreenUtil().setWidth(3775)), 124 | Text( 125 | val['name'], 126 | maxLines: 1, 127 | overflow: TextOverflow.ellipsis, 128 | style: TextStyle( 129 | color: Colors.pink, 130 | fontSize: ScreenUtil().setSp(26) 131 | ) 132 | ), 133 | Row( 134 | children: [ 135 | Text('¥${val['mallPrice']}'), 136 | Text( 137 | '¥${val['price']}', 138 | style: TextStyle(color:Colors.black26,decoration: TextDecoration.lineThrough), 139 | ) 140 | ], 141 | ) 142 | ], 143 | ), 144 | ) 145 | ); 146 | }).toList(); 147 | return Wrap( 148 | spacing: 2, 149 | children: listWidget, 150 | ); 151 | } else { 152 | return Text('无数据'); 153 | } 154 | } 155 | 156 | //火爆专区组合 157 | Widget _hotGoods(){ 158 | 159 | return Container( 160 | child: Column( 161 | children: [ 162 | hotTitle, 163 | _wrapList(), 164 | ], 165 | ), 166 | ); 167 | 168 | } 169 | } 170 | 171 | 172 | //楼层商品组件 173 | class HomeFloorContent extends StatelessWidget { 174 | final List floorGoodsList; 175 | HomeFloorContent({Key key, this.floorGoodsList}) : super(key: key); 176 | 177 | @override 178 | Widget build(BuildContext context) { 179 | return Container( 180 | child: Column( 181 | children: [ 182 | _firstRow(context), 183 | _otherGoods(context) 184 | ], 185 | ), 186 | ); 187 | } 188 | Widget _firstRow(context){ 189 | return Row( 190 | children: [ 191 | _goodsItem(context,floorGoodsList[0]), 192 | Column( 193 | children: [ 194 | _goodsItem(context,floorGoodsList[1]), 195 | _goodsItem(context,floorGoodsList[2]), 196 | ], 197 | ) 198 | ], 199 | ); 200 | } 201 | 202 | Widget _otherGoods(context){ 203 | return Row( 204 | children: [ 205 | _goodsItem(context,floorGoodsList[3]), 206 | _goodsItem(context,floorGoodsList[4]) 207 | ], 208 | ); 209 | } 210 | 211 | Widget _goodsItem(context,Map goods){ 212 | return Container( 213 | width: ScreenUtil().setWidth(375), 214 | child: InkWell( 215 | onTap: (){ 216 | Application.router.navigateTo(context, "/detail?id=${goods['goodsId']}"); 217 | }, 218 | child: Image.network(goods['image']), 219 | ), 220 | ); 221 | } 222 | 223 | 224 | } 225 | 226 | //楼层标题 227 | class HomeFloorTitle extends StatelessWidget { 228 | final String picture_address;// 图片地址 229 | HomeFloorTitle({Key key, this.picture_address}) : super(key: key); 230 | 231 | @override 232 | Widget build(BuildContext context) { 233 | return Container( 234 | padding: EdgeInsets.all(8.0), 235 | child: Image.network(picture_address), 236 | ); 237 | } 238 | } 239 | 240 | //商品推荐 241 | class HomeRecommend extends StatelessWidget { 242 | final List recommendList; 243 | HomeRecommend({Key key,this.recommendList}):super(key: key); 244 | 245 | @override 246 | Widget build(BuildContext context) { 247 | return Container( 248 | margin: EdgeInsets.only(top: 10.0), 249 | child: Column( 250 | children: [ 251 | _titleWidget(), 252 | _recommedList(context) 253 | ], 254 | ), 255 | ); 256 | } 257 | 258 | 259 | //推荐商品标题 260 | Widget _titleWidget(){ 261 | return Container( 262 | alignment: Alignment.centerLeft, 263 | padding: EdgeInsets.fromLTRB(10.0,2.0,0.5,0), 264 | decoration: BoxDecoration( 265 | color: Colors.white, 266 | border: Border( 267 | bottom:BorderSide(width: 0.5,color: Colors.black12) 268 | ) 269 | ), 270 | child: Text( 271 | '商品推荐', 272 | style: TextStyle(color: Colors.pink) 273 | ), 274 | ); 275 | } 276 | 277 | //列表 278 | Widget _recommedList(BuildContext context) { 279 | return Container( 280 | height: ScreenUtil().setHeight(380), 281 | child: ListView.builder( 282 | scrollDirection: Axis.horizontal, 283 | itemCount: recommendList.length, 284 | itemBuilder: (context,index){ 285 | return _item(index,context); 286 | }, 287 | ), 288 | ); 289 | } 290 | 291 | Widget _item(index,context){ 292 | return InkWell( 293 | onTap: (){ 294 | Application.router.navigateTo(context,"/detail?id=${recommendList[index]['goodsId']}"); 295 | }, 296 | child: Container( 297 | width: ScreenUtil().setWidth(280), 298 | padding: EdgeInsets.all(8.0), 299 | decoration: BoxDecoration( 300 | color: Colors.white, 301 | border: Border( 302 | left: BorderSide(width: 0.5,color: Colors.black12), 303 | ), 304 | ), 305 | child: Column( 306 | children: [ 307 | Image.network(recommendList[index]['image']), 308 | Text('¥${recommendList[index]['mallPrice']}'), 309 | Text( 310 | '¥${recommendList[index]['price']}', 311 | style: TextStyle( 312 | decoration: TextDecoration.lineThrough, //下划线 313 | color:Colors.grey 314 | ), 315 | ) 316 | ], 317 | ), 318 | ), 319 | 320 | ); 321 | } 322 | 323 | } 324 | //手机相关 325 | class HomeLeaderPhone extends StatelessWidget { 326 | final String leaderImage;//店长图片 327 | final String leaderPhone;//店长电话 328 | HomeLeaderPhone({Key key,this.leaderImage,this.leaderPhone}) : super(key: key); 329 | @override 330 | Widget build(BuildContext context) { 331 | return Container( 332 | child: InkWell( 333 | onTap: _launchUrl, 334 | child: Image.network(leaderImage), 335 | ), 336 | ); 337 | } 338 | void _launchUrl() async { 339 | String url = 'tel:'+leaderPhone; 340 | if (await canLaunch(url)) { 341 | await launch(url); 342 | } else { 343 | throw 'Could not launch $url'; 344 | } 345 | } 346 | } 347 | 348 | //广告图片 349 | class HomeAdBanner extends StatelessWidget { 350 | final String advertesPicture; 351 | HomeAdBanner({Key key, this.advertesPicture}) : super (key: key); 352 | 353 | @override 354 | Widget build(BuildContext context) { 355 | return Container( 356 | margin: EdgeInsets.only(top: 5.0), 357 | color: Colors.white, 358 | child: Image.network(advertesPicture), 359 | ); 360 | } 361 | } 362 | 363 | //首页导航组件 364 | class HomeTopNavigator extends StatelessWidget { 365 | final List navigatorList; 366 | HomeTopNavigator({Key key, this.navigatorList}) : super(key: key); 367 | @override 368 | Widget build(BuildContext context) { 369 | if (navigatorList.length > 10) { 370 | navigatorList.removeRange(10,navigatorList.length); 371 | } 372 | var tempIndex = -1; 373 | return Container( 374 | color: Colors.green, 375 | margin: EdgeInsets.only(top:5.0), 376 | height: ScreenUtil().setHeight(320), 377 | padding: EdgeInsets.all(3.0), 378 | child: GridView.count( 379 | physics: NeverScrollableScrollPhysics(), 380 | crossAxisCount: 5, 381 | padding: EdgeInsets.all(4.0), 382 | children: navigatorList.map((item){ 383 | tempIndex++; 384 | return _gridViewItemUI(context,item,tempIndex); 385 | }).toList(), 386 | 387 | ), 388 | ); 389 | } 390 | 391 | Widget _gridViewItemUI(BuildContext context, item, index){ 392 | print('点击了-------${item}'); 393 | return InkWell( 394 | onTap: (){ 395 | _goCategory(context,index,item['mallCategoryId']); 396 | }, 397 | child: Column( 398 | children: [ 399 | Image.network(item['image'],width:ScreenUtil().setWidth(95)), 400 | Text(item['mallCategoryName']) 401 | ], 402 | ), 403 | ); 404 | } 405 | 406 | void _goCategory(context,int index, String categroyId)async { 407 | await request('getCategory').then((val){ 408 | var data = json.decode(val.toString()); 409 | CategoryModel category = CategoryModel.fromJson(data); 410 | List list = category.data; 411 | Provide.value(context).changeCategory(categroyId,index); 412 | Provide.value(context).getChildCategory(list[index].bxMallSubDto,categroyId); 413 | Provide.value(context).changeIndex(1); 414 | }); 415 | 416 | } 417 | 418 | 419 | 420 | } 421 | 422 | //首页轮播组件编写 423 | class HomeSwiperDiy extends StatelessWidget { 424 | 425 | final List swiperDataList; 426 | HomeSwiperDiy({Key key,this.swiperDataList}):super(key: key); 427 | 428 | @override 429 | Widget build(BuildContext context) { 430 | 431 | return Container( 432 | color: Colors.white, 433 | width: ScreenUtil().setWidth(750), 434 | height: ScreenUtil().setHeight(333), 435 | child: Swiper( 436 | itemBuilder: (BuildContext context, int index){ 437 | return InkWell( 438 | onTap: (){ 439 | Application.router.navigateTo(context,"/detail?id=${swiperDataList[index]['goodsId']}"); 440 | }, 441 | child: Image.network("${swiperDataList[index]['image']}",fit: BoxFit.fill), 442 | ); 443 | }, 444 | itemCount: swiperDataList.length, 445 | autoplay: true, 446 | pagination: new SwiperPagination(), 447 | ), 448 | ); 449 | } 450 | } 451 | 452 | -------------------------------------------------------------------------------- /shflutter/lib/pages/index_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provide/provide.dart'; 4 | import '../provide/current_index.dart'; 5 | import 'home_page.dart'; 6 | import 'category_page.dart'; 7 | import 'cart_page.dart'; 8 | import 'member_page.dart'; 9 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 10 | 11 | class IndexPage extends StatelessWidget { 12 | final List bottomTabs = [ 13 | BottomNavigationBarItem( 14 | icon:Icon(CupertinoIcons.home), 15 | label: 'Home' 16 | ), 17 | BottomNavigationBarItem( 18 | icon:Icon(CupertinoIcons.search), 19 | label: 'Classes' 20 | ), 21 | BottomNavigationBarItem( 22 | icon: Icon(CupertinoIcons.shopping_cart), 23 | label: 'Car' 24 | ), 25 | BottomNavigationBarItem( 26 | icon: Icon(CupertinoIcons.profile_circled), 27 | label: 'Member' 28 | ) 29 | ]; 30 | 31 | final List tabBodies = [ 32 | HomePage(), 33 | CategoryPage(), 34 | CartPage(), 35 | MemberPage() 36 | ]; 37 | 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context); 42 | 43 | return Provide ( 44 | 45 | builder: (context,child,val) { 46 | //获取状态currentIndex 47 | // int currentIndex = val.currentIndex; 或者使用以下方式获取 currentIndex 48 | int currentIndex = Provide.value(context).currentIndex; 49 | //Scaffold 是 Material 库中提供的页面脚手架, 50 | //它提供了默认的导航栏、标题和包含主屏幕widget树(后同“组件树”或“部件树”)的body属性,组件树可以很复杂 51 | return Scaffold( 52 | // appBar: AppBar(title: Text('life+'),), 53 | backgroundColor: Color.fromRGBO(244, 245, 245 ,1.0), 54 | bottomNavigationBar: BottomNavigationBar( 55 | type: BottomNavigationBarType.fixed, 56 | currentIndex: currentIndex, 57 | items: bottomTabs, 58 | onTap: (index) { 59 | //更改状态currentIndex 60 | Provide.value(context).changeIndex(index); 61 | }, 62 | ), 63 | //body的组件树中包含了一个Center 组件,Center 可以将其子组件树对齐到屏幕中心 64 | body: IndexedStack( 65 | index: currentIndex, 66 | children: tabBodies, 67 | ), 68 | ); 69 | } 70 | 71 | ); 72 | 73 | } 74 | 75 | 76 | 77 | } -------------------------------------------------------------------------------- /shflutter/lib/pages/member_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | class MemberPage extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar(title: Text('memberPage')), 9 | body: ListView( 10 | children: [ 11 | _topHeader(), 12 | _orderTitle(), 13 | _orderType(), 14 | _actionList() 15 | ], 16 | ) 17 | ); 18 | } 19 | 20 | //头像区域 21 | Widget _topHeader(){ 22 | return Container( 23 | width: ScreenUtil().setWidth(750), 24 | padding: EdgeInsets.all(20), 25 | color: Colors.pinkAccent, 26 | child: Column( 27 | children: [ 28 | Container( 29 | margin: EdgeInsets.only(top: 30), 30 | child: ClipOval( 31 | child:Image.network('http://blogimages.jspang.com/blogtouxiang1.jpg') 32 | ), 33 | ), 34 | Container( 35 | margin: EdgeInsets.only(top: 10), 36 | child: Text( 37 | 'syh', 38 | style: TextStyle( 39 | fontSize: ScreenUtil().setSp(36), 40 | color:Colors.white, 41 | ), 42 | ) 43 | ), 44 | ], 45 | ), 46 | ); 47 | } 48 | //我的订单顶部 49 | Widget _orderTitle(){ 50 | 51 | return Container( 52 | margin: EdgeInsets.only(top:10), 53 | decoration: BoxDecoration( 54 | color: Colors.white, 55 | border: Border( 56 | bottom:BorderSide(width: 1,color:Colors.black12) 57 | ) 58 | ), 59 | child: ListTile( 60 | leading: Icon(Icons.list), 61 | title:Text('我的订单'), 62 | trailing: Icon(Icons.arrow_right), 63 | ), 64 | ); 65 | 66 | } 67 | 68 | Widget _orderType(){ 69 | return Container( 70 | margin: EdgeInsets.only(top:5), 71 | width: ScreenUtil().setWidth(750), 72 | height: ScreenUtil().setHeight(150), 73 | padding: EdgeInsets.only(top:20), 74 | color: Colors.white, 75 | child: Row( 76 | children: [ 77 | _myOrderTypeSub('待付款',Icons.party_mode), 78 | _myOrderTypeSub('待发货',Icons.query_builder), 79 | _myOrderTypeSub('待收货',Icons.directions_car), 80 | _myOrderTypeSub('待评价',Icons.content_paste), 81 | 82 | // Container( 83 | // width: ScreenUtil().setWidth(187), 84 | // child: Column( 85 | // children: [ 86 | // Icon( 87 | // Icons.party_mode, 88 | // size: 30, 89 | // ), 90 | // Text('待付款'), 91 | // ], 92 | // ), 93 | // ), 94 | // Container( 95 | // width: ScreenUtil().setWidth(187), 96 | // child: Column( 97 | // children: [ 98 | // Icon( 99 | // Icons.query_builder, 100 | // size: 30, 101 | // ), 102 | // Text('待发货'), 103 | // ], 104 | // ), 105 | // ), 106 | // Container( 107 | // width: ScreenUtil().setWidth(187), 108 | // child: Column( 109 | // children: [ 110 | // Icon( 111 | // Icons.directions_car, 112 | // size: 30, 113 | // ), 114 | // Text('待收货'), 115 | // ], 116 | // ), 117 | // ), 118 | // Container( 119 | // width: ScreenUtil().setWidth(187), 120 | // child: Column( 121 | // children: [ 122 | // Icon( 123 | // Icons.content_paste, 124 | // size: 30, 125 | // ), 126 | // Text('待评价'), 127 | // ], 128 | // ), 129 | // ), 130 | ], 131 | ), 132 | ); 133 | } 134 | 135 | Widget _myOrderTypeSub(String title,IconData subIcon){ 136 | 137 | return Container( 138 | width: ScreenUtil().setWidth(187), 139 | child: Column( 140 | children: [ 141 | Icon( 142 | subIcon, 143 | size: 30, 144 | ), 145 | Text(title), 146 | ], 147 | ), 148 | ); 149 | } 150 | 151 | Widget _myListTile(String title){ 152 | 153 | return Container( 154 | decoration: BoxDecoration( 155 | color: Colors.white, 156 | border: Border( 157 | bottom:BorderSide(width: 1,color:Colors.black12) 158 | ) 159 | ), 160 | child: ListTile( 161 | leading: Icon(Icons.blur_circular), 162 | title: Text(title), 163 | trailing: Icon(Icons.arrow_right), 164 | ), 165 | ); 166 | } 167 | 168 | Widget _actionList(){ 169 | return Container( 170 | margin: EdgeInsets.only(top: 10), 171 | child: Column( 172 | children: [ 173 | _myListTile('领取优惠券'), 174 | _myListTile('已领取优惠券'), 175 | _myListTile('地址管理'), 176 | _myListTile('客服电话'), 177 | _myListTile('关于我们'), 178 | ], 179 | ), 180 | ); 181 | } 182 | 183 | 184 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/cart.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:shflutter/model/cartInfo.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | 8 | class CartProvide with ChangeNotifier{ 9 | 10 | String cartString="[]"; 11 | List cartList=[]; //商品列表对象 12 | 13 | 14 | double allPrice =0 ; //总价格 15 | int allGoodsCount =0; //商品总数量 16 | bool isAllCheck= true; //是否全选 17 | 18 | save(goodsId,goodsName,count,price,images) async{ 19 | //初始化SharedPreferences 20 | SharedPreferences prefs = await SharedPreferences.getInstance(); 21 | cartString=prefs.getString('cartInfo'); //获取持久化存储的值 22 | var temp=cartString==null?[]:json.decode(cartString.toString()); 23 | //把获得值转变成List 24 | List tempList= (temp as List).cast(); 25 | //声明变量,用于判断购物车中是否已经存在此商品ID 26 | var isHave= false; //默认为没有 27 | int ival=0; //用于进行循环的索引使用 28 | allPrice=0; 29 | allGoodsCount=0; //把商品总数量设置为0 30 | tempList.forEach((item){//进行循环,找出是否已经存在该商品 31 | //如果存在,数量进行+1操作 32 | if(item['goodsId']==goodsId){ 33 | tempList[ival]['count']=item['count']+1; 34 | cartList[ival].count++; 35 | isHave=true; 36 | } 37 | if(item['isCheck']){ 38 | allPrice+= (cartList[ival].price* cartList[ival].count); 39 | allGoodsCount+= cartList[ival].count; 40 | } 41 | ival++; 42 | }); 43 | // 如果没有,进行增加 44 | if(!isHave){ 45 | Map newGoods={ 46 | 'goodsId':goodsId, 47 | 'goodsName':goodsName, 48 | 'count':count, 49 | 'price':price, 50 | 'images':images, 51 | 'isCheck': true //是否已经选择 52 | }; 53 | tempList.add(newGoods); 54 | cartList.add(new CartInfoMode.fromJson(newGoods)); 55 | allPrice+= (count * price); 56 | allGoodsCount+=count; 57 | } 58 | //把字符串进行encode操作, 59 | cartString= json.encode(tempList).toString(); 60 | prefs.setString('cartInfo', cartString);//进行持久化 61 | notifyListeners(); 62 | } 63 | 64 | //删除购物车中的商品 65 | remove() async{ 66 | SharedPreferences prefs = await SharedPreferences.getInstance(); 67 | //prefs.clear();//清空键值对 68 | prefs.remove('cartInfo'); 69 | cartList=[]; 70 | allPrice =0 ; 71 | allGoodsCount=0; 72 | print('清空完成-----------------'); 73 | notifyListeners(); 74 | } 75 | 76 | //删除单个购物车商品 77 | deleteOneGoods(String goodsId) async{ 78 | SharedPreferences prefs = await SharedPreferences.getInstance(); 79 | cartString=prefs.getString('cartInfo'); 80 | List tempList= (json.decode(cartString.toString()) as List).cast(); 81 | 82 | int tempIndex =0; 83 | int delIndex=0; 84 | tempList.forEach((item){ 85 | if(item['goodsId']==goodsId){ 86 | delIndex=tempIndex; 87 | } 88 | tempIndex++; 89 | }); 90 | tempList.removeAt(delIndex); 91 | cartString= json.encode(tempList).toString(); 92 | prefs.setString('cartInfo', cartString);// 93 | await getCartInfo(); 94 | } 95 | 96 | //得到购物车中的商品 97 | getCartInfo() async { 98 | SharedPreferences prefs = await SharedPreferences.getInstance(); 99 | //获得购物车中的商品,这时候是一个字符串 100 | cartString=prefs.getString('cartInfo'); 101 | //把cartList进行初始化,防止数据混乱 102 | cartList=[]; 103 | //判断得到的字符串是否有值,如果不判断会报错 104 | if (cartString == null) { 105 | cartList=[]; 106 | } else { 107 | List tempList = (json.decode(cartString.toString()) as List).cast(); 108 | allPrice=0; 109 | allGoodsCount=0; 110 | isAllCheck=true; 111 | tempList.forEach((item){ 112 | if (item['isCheck']) { 113 | allPrice+=(item['count']*item['price']); 114 | allGoodsCount+=item['count']; 115 | } else { 116 | isAllCheck=false; 117 | } 118 | cartList.add(new CartInfoMode.fromJson(item)); 119 | }); 120 | } 121 | notifyListeners(); 122 | } 123 | 124 | //修改选中状态 125 | changeCheckState(CartInfoMode cartItem) async{ 126 | SharedPreferences prefs = await SharedPreferences.getInstance(); 127 | cartString = prefs.getString('cartInfo'); 128 | List tempList = (json.decode(cartString.toString()) as List).cast(); 129 | int tempIndex =0; 130 | int changeIndex=0; 131 | tempList.forEach((item){ 132 | if(item['goodsId']==cartItem.goodsId){ 133 | changeIndex=tempIndex; 134 | } 135 | tempIndex++; 136 | }); 137 | tempList[changeIndex] = cartItem.toJson(); 138 | cartString = json.encode(tempList).toString(); 139 | prefs.setString('cartInfo',cartString); 140 | await getCartInfo(); 141 | } 142 | 143 | //增加减少数量的操作 144 | addOrReduceAction(var cartItem, String todo )async{ 145 | SharedPreferences prefs = await SharedPreferences.getInstance(); 146 | cartString=prefs.getString('cartInfo'); 147 | List tempList= (json.decode(cartString.toString()) as List).cast(); 148 | int tempIndex =0; 149 | int changeIndex=0; 150 | tempList.forEach((item){ 151 | if(item['goodsId']==cartItem.goodsId){ 152 | changeIndex=tempIndex; 153 | } 154 | tempIndex++; 155 | }); 156 | if(todo=='add'){ 157 | cartItem.count++; 158 | }else if(cartItem.count>1){ 159 | cartItem.count--; 160 | } 161 | tempList[changeIndex]=cartItem.toJson(); 162 | cartString= json.encode(tempList).toString(); 163 | prefs.setString('cartInfo', cartString);// 164 | await getCartInfo(); 165 | 166 | } 167 | 168 | //点击全选按钮操作 169 | changeAllCheckBtnState(bool isCheck) async{ 170 | SharedPreferences prefs = await SharedPreferences.getInstance(); 171 | cartString = prefs.getString('cartInfo'); 172 | List tempList = (json.decode(cartString.toString()) as List).cast(); 173 | List newList = []; 174 | for (var item in tempList) { 175 | var newItem = item; 176 | newItem['isCheck'] = isCheck; 177 | newList.add(newItem); 178 | } 179 | 180 | cartString = json.encode(newList).toString(); 181 | prefs.setString('cartInfo',cartString); 182 | await getCartInfo(); 183 | } 184 | 185 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/category_goods_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/categoryGoodList.dart'; 3 | 4 | class CategoryGoodsListProvide with ChangeNotifier { 5 | ListgoodsList = []; 6 | 7 | getGoodsList(Listlist){ 8 | goodsList = list; 9 | notifyListeners(); 10 | } 11 | 12 | addGoodsList(Listlist){ 13 | goodsList.addAll(list); 14 | notifyListeners(); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/child_category.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/category.dart'; 3 | 4 | //ChangeNotifier的混入是不用管理听众 5 | class ChildCategory with ChangeNotifier { 6 | 7 | List childCategoryList = []; //商品列表 8 | int childIndex = 0; //子类索引值 9 | int categoryIndex=0; //大类索引 10 | String categoryId = '4'; //大类ID 11 | String subId =''; //小类ID 12 | int page=1; //列表页数,当改变大类或者小类时进行改变 13 | String noMoreText = ''; //显示更多的表示 14 | bool isNewCategory= true; 15 | 16 | changeCategory(String id ,int index){ 17 | categoryId = id; 18 | categoryIndex = index; 19 | subId = ''; 20 | notifyListeners(); 21 | } 22 | //点击大类时更换 23 | getChildCategory(List list,String id){ 24 | isNewCategory=true; 25 | categoryId=id; 26 | childIndex=0; 27 | page=1; 28 | subId=''; //点击大类时,把子类ID清空 29 | noMoreText=''; 30 | BxMallSubDto all= BxMallSubDto(); 31 | all.mallSubId=''; 32 | all.mallCategoryId='00'; 33 | all.mallSubName = '全部'; 34 | all.comments = 'null'; 35 | childCategoryList=[all]; 36 | childCategoryList.addAll(list); 37 | notifyListeners(); 38 | } 39 | 40 | //改变子类索引 , 41 | changeChildIndex(int index,String id){ 42 | isNewCategory=true; 43 | //传递两个参数,使用新传递的参数给状态赋值 44 | childIndex=index; 45 | subId=id; 46 | page=1; 47 | noMoreText=''; 48 | notifyListeners(); 49 | } 50 | 51 | //增加Page的方法f 52 | addPage(){ 53 | page++; 54 | } 55 | 56 | //改变noMoreText数据 57 | changeNoMore(String text){ 58 | noMoreText=text; 59 | notifyListeners(); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/counter.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class Counter with ChangeNotifier { 7 | int value = 0; 8 | increment(){ 9 | value++; 10 | notifyListeners(); 11 | } 12 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/current_index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /* 作用:监听点击tabbar时,下标的改变 4 | */ 5 | //ChangeNotifier,意思是可以不用管理听众 6 | class CurrentIndexProvider with ChangeNotifier { 7 | int currentIndex = 0; 8 | changeIndex(int newIndex) { 9 | currentIndex = newIndex; 10 | print('点击的值'); 11 | print(newIndex); 12 | //通过notifyListeners可以通知听众刷新。 13 | notifyListeners(); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /shflutter/lib/provide/details_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../service/service_method.dart'; 3 | import 'dart:convert'; 4 | import '../model/details.dart'; 5 | 6 | /* 作用:监听详情页数据 7 | */ 8 | class DetailsInfoProvide with ChangeNotifier 9 | { 10 | DetailsModel goodsInfo =null; 11 | bool isLeft = true; 12 | bool isRight = false; 13 | 14 | //从后台获取商品信息 15 | getGoodInfo(String id)async { 16 | var formData = {'goodId':id}; 17 | await request('getGoodDetailById',formData:formData).then((val){ 18 | var responseData = json.decode(val.toString()); 19 | goodsInfo = DetailsModel.fromJson(responseData); 20 | // ignore: unnecessary_brace_in_string_interps 21 | print("查看详情数据:${responseData}"); 22 | notifyListeners(); 23 | }); 24 | } 25 | 26 | //改变tabBar的状态 27 | changeLeftAndRight(String changeState){ 28 | 29 | if (changeState == 'left') { 30 | isLeft = true; 31 | isRight = false; 32 | } else { 33 | isLeft = false; 34 | isRight = true; 35 | } 36 | 37 | notifyListeners(); 38 | } 39 | 40 | 41 | } -------------------------------------------------------------------------------- /shflutter/lib/routers/application.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | 3 | /*跳转路由 */ 4 | class Application { 5 | static FluroRouter router; 6 | } -------------------------------------------------------------------------------- /shflutter/lib/routers/router_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluro/fluro.dart'; 3 | import '../pages/details_page/details_page.dart'; 4 | 5 | ///跳转到详情 6 | Handler detailsHandler = Handler( 7 | handlerFunc: (BuildContext context,Map> params){ 8 | String goodsId = params['id'].first; 9 | print('index>details goodsID is ${goodsId}'); 10 | return DetailsPage(goodsId); 11 | } 12 | ); -------------------------------------------------------------------------------- /shflutter/lib/routers/routes.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluro/fluro.dart'; 4 | import './router_handler.dart'; 5 | 6 | class Routes { 7 | static String root = '/'; 8 | static String detailsPage = '/detail'; 9 | static void configureRoutes(FluroRouter router){ 10 | router.notFoundHandler = new Handler ( 11 | handlerFunc:(BuildContext context, Map> params){ 12 | print('ERROR====>ROUTE WAS NOT FONUND!!!'); 13 | } 14 | ); 15 | 16 | router.define(detailsPage,handler:detailsHandler); 17 | } 18 | } -------------------------------------------------------------------------------- /shflutter/lib/service/service_method.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import '../config/service_url.dart'; 3 | 4 | Future request(url,{formData})async 5 | { 6 | try{ 7 | print('开始请求数据'); 8 | Response response; 9 | Dio dio = new Dio(); 10 | dio.options.contentType = Headers.formUrlEncodedContentType; 11 | if(formData == null) { 12 | response = await dio.post(servicePath[url]); 13 | } else { 14 | response = await dio.post(servicePath[url],data:formData); 15 | } 16 | print("查看响应数据请求url:${servicePath[url]},\n返回数据:${response.data}"); 17 | if (response.statusCode == 200) { 18 | return response.data; 19 | } else { 20 | throw Exception('有异常。。。'); 21 | } 22 | 23 | }catch(e){ 24 | return print('ERROR:======>$e'); 25 | } 26 | } -------------------------------------------------------------------------------- /shflutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: shflutter 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.7.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.0 31 | provide: ^1.0.2 32 | flutter_screenutil: ^0.5.1 33 | flutter_swiper: ^1.1.4 34 | flutter_easyrefresh: ^2.1.8 35 | dio: ^3.0.10 #网络请求框架 36 | fluro: ^1.7.8 #页面跳转 2.0.3 37 | fluttertoast: ^7.1.8 #提示语 38 | url_launcher: ^5.5.0 #打电话 39 | flutter_html: ^1.2.0 #html 40 | shared_preferences: ^0.5.1 #存储 41 | 42 | dev_dependencies: 43 | flutter_test: 44 | sdk: flutter 45 | 46 | # For information on the generic Dart part of this file, see the 47 | # following page: https://dart.dev/tools/pub/pubspec 48 | 49 | # The following section is specific to Flutter. 50 | flutter: 51 | 52 | # The following line ensures that the Material Icons font is 53 | # included with your application, so that you can use the icons in 54 | # the material Icons class. 55 | uses-material-design: true 56 | 57 | # To add assets to your application, add an assets section, like this: 58 | # assets: 59 | # - images/a_dot_burr.jpeg 60 | # - images/a_dot_ham.jpeg 61 | 62 | # An image asset can refer to one or more resolution-specific "variants", see 63 | # https://flutter.dev/assets-and-images/#resolution-aware. 64 | 65 | # For details regarding adding assets from package dependencies, see 66 | # https://flutter.dev/assets-and-images/#from-packages 67 | 68 | # To add custom fonts to your application, add a fonts section here, 69 | # in this "flutter" section. Each entry in this list should have a 70 | # "family" key with the font family name, and a "fonts" key with a 71 | # list giving the asset and other descriptors for the font. For 72 | # example: 73 | # fonts: 74 | # - family: Schyler 75 | # fonts: 76 | # - asset: fonts/Schyler-Regular.ttf 77 | # - asset: fonts/Schyler-Italic.ttf 78 | # style: italic 79 | # - family: Trajan Pro 80 | # fonts: 81 | # - asset: fonts/TrajanPro.ttf 82 | # - asset: fonts/TrajanPro_Bold.ttf 83 | # weight: 700 84 | # 85 | # For details regarding fonts from package dependencies, 86 | # see https://flutter.dev/custom-fonts/#from-packages 87 | -------------------------------------------------------------------------------- /shflutter/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:shflutter/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------