├── README.md ├── flutter_demo ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── huan │ │ │ │ └── io │ │ │ │ └── flutterdemo │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── key.properties │ └── settings.gradle ├── images │ ├── fiction_1.png │ ├── fiction_2.png │ ├── fiction_3.png │ ├── fiction_4.png │ ├── fiction_author.png │ ├── fiction_header_icon.png │ ├── icon_add_comment.png │ ├── icon_back.png │ ├── icon_back_pressed.png │ ├── icon_coin.png │ ├── icon_coin_bg.png │ ├── icon_function_search.png │ ├── icon_history_time.png │ ├── icon_logo.png │ ├── icon_main_tab_fiction_normal.png │ ├── icon_main_tab_fiction_selected.png │ ├── icon_main_tab_micro_normal.png │ ├── icon_main_tab_micro_select.png │ ├── icon_main_tab_news_normal.png │ ├── icon_main_tab_news_selected.png │ ├── icon_main_tab_person_normal.png │ ├── icon_main_tab_person_selected.png │ ├── icon_replace.png │ ├── icon_right.png │ ├── icon_share.png │ ├── mine_apprentice_icon.png │ ├── mine_cash_icon.png │ ├── mine_code_icon.png │ ├── mine_guess_icon.png │ ├── mine_message_icon.png │ ├── mine_read_icon.png │ ├── mine_riddle_icon.png │ ├── mine_wallet_icon.png │ ├── mine_withdraw_icon.png │ ├── personal_ava_default.png │ ├── personal_heart_bg.png │ └── setting.png ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ ├── FictionDetailPage.dart │ ├── FictionManFeatured.dart │ ├── ImagePickerPage.dart │ ├── NewsDetailPageView.dart │ ├── PersonalPage.dart │ ├── ScannerPage.dart │ ├── SearchPage.dart │ ├── bean │ │ ├── BannerInfoResponse.dart │ │ ├── ChannelResponse.dart │ │ ├── FictionDetailResponse.dart │ │ ├── FictionHomeInfoResponse.dart │ │ ├── HotSearchResponse.dart │ │ ├── NewsDetailResponse.dart │ │ ├── NewsResData.dart │ │ └── RelativeInfoResponse.dart │ ├── channelView.dart │ ├── controller │ │ └── HttpController.dart │ ├── fiction │ │ └── mainFiction.dart │ ├── homePage.dart │ ├── main.dart │ ├── news_detail_page.dart │ ├── utils │ │ ├── SpUtil.dart │ │ └── functions.dart │ ├── videoListPage.dart │ └── view │ │ ├── NewDetailWebview.dart │ │ ├── SearchView.dart │ │ └── StaticRatingBar.dart ├── pubspec.yaml └── test │ └── widget_test.dart └── images ├── 1550481959(1).jpg ├── 1550481996(1).jpg ├── 1550482021(1).jpg ├── 1550482063(1).jpg ├── 1550482086(1).jpg ├── 1550482109(1).jpg ├── 1553766601(1).jpg └── 1553766652(1).jpg /README.md: -------------------------------------------------------------------------------- 1 | # Flutter_bwkd 2 | 本项目主要是用Flutter去实现“百万看点”app 3 | 4 | 自flutter发布正式版到现在已经过去两个多月了,当我看到它正式发布的消息时,简直就像是个拿到了玩具的小学鸡一样兴奋,迫不及待的想去玩玩。正好最近项目迭代完成比较闲游遍了各大论坛,最后决定试做一下资讯类的应用,选择了“百万看点”这个app试手,事不宜迟,马上开干。 5 | 6 | 预览:看看用flutter写的百万看点的界面,鉴于工程问题,我们只做主要的界面。 7 | 8 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550481959(1).jpg) 9 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550481996(1).jpg) 10 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550482021(1).jpg) 11 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550482063(1).jpg) 12 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550482086(1).jpg) 13 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1550482109(1).jpg) 14 | 15 | 用到的开源库: 16 | 17 | cupertino_icons: ^0.1.2 18 | 19 | english_words: ^3.1.0 20 | 21 | dio: ^1.0.13 22 | 23 | webview_flutter: ^0.1.2 24 | 25 | flutter_webview_plugin: ^0.3.0+2 26 | 27 | chewie: ^0.8.0 28 | 29 | flutter_swiper: ^1.1.4 30 | 31 | pointycastle: ^1.0.0 32 | 33 | APK下载: 34 | 链接:https://pan.baidu.com/s/1OZQRT29eZWxbFmXl3ce50Q 35 | 提取码:2osd 36 | 37 | 心得体会: 38 | 39 | 可能一开始上手的话有点懵,但是玩过之后就是酸爽,谁用谁知道。有一点诟病就是嵌套太深了,所以一定要理清思路,尽量做到整洁,我这个项目其实也做得不好,大家以学习的态度去学就好了,正好可以看看哪些地方值得完善修改。 40 | 41 | 个人觉得Flutter既然都出来了,学客户端的同学还是有必要去学习研究一下的,或许flutter会成为下一代客户端的主流呢,谁也说不好,提前准备就好。 42 | 43 | 项目中关于网络的封装不是很好,后面完善再更新。 44 | 45 | 46 | 2019-03-28 47 | 新增了搜索页面,可保存删除搜索历史和获取当前热门搜索 48 | 49 | 增加的插件有: 50 | 51 | shared_preferences: ^0.5.1+2 52 | 53 | synchronized: ^2.1.0 54 | 55 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1553766652(1).jpg) 56 | ![image](https://github.com/HWHUAN/Flutter_bwkd/blob/master/images/1553766601(1).jpg) 57 | 58 | 59 | 说明: 60 | 61 | 本项目只做的百万看点的一些主要界面,鉴于百万看点api对用户信息的加密做得太好,还需要一点时间去研究,所以登录验证的相关信息就没做了。 62 | api 来自网络 ,【百万看点】是一款资讯类应用的app,非官方版本,仅作学习交流之用,数据来源于百万看点,数据接口均属于非正常渠道获取,请勿用于商业用途,一切解释权归百万看点官方所有。 63 | -------------------------------------------------------------------------------- /flutter_demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | 40 | # iOS/XCode related 41 | **/ios/**/*.mode1v3 42 | **/ios/**/*.mode2v3 43 | **/ios/**/*.moved-aside 44 | **/ios/**/*.pbxuser 45 | **/ios/**/*.perspectivev3 46 | **/ios/**/*sync/ 47 | **/ios/**/.sconsign.dblite 48 | **/ios/**/.tags* 49 | **/ios/**/.vagrant/ 50 | **/ios/**/DerivedData/ 51 | **/ios/**/Icon? 52 | **/ios/**/Pods/ 53 | **/ios/**/.symlinks/ 54 | **/ios/**/profile 55 | **/ios/**/xcuserdata 56 | **/ios/.generated/ 57 | **/ios/Flutter/App.framework 58 | **/ios/Flutter/Flutter.framework 59 | **/ios/Flutter/Generated.xcconfig 60 | **/ios/Flutter/app.flx 61 | **/ios/Flutter/app.zip 62 | **/ios/Flutter/flutter_assets/ 63 | **/ios/ServiceDefinitions.json 64 | **/ios/Runner/GeneratedPluginRegistrant.* 65 | 66 | # Exceptions to above rules. 67 | !**/ios/**/default.mode1v3 68 | !**/ios/**/default.mode2v3 69 | !**/ios/**/default.pbxuser 70 | !**/ios/**/default.perspectivev3 71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 72 | -------------------------------------------------------------------------------- /flutter_demo/.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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /flutter_demo/README.md: -------------------------------------------------------------------------------- 1 | # flutter_demo 2 | 3 | A new Flutter application. 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.io/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.io/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /flutter_demo/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | def keystorePropertiesFile = rootProject.file("key.properties") 28 | def keystoreProperties = new Properties() 29 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 30 | 31 | android { 32 | compileSdkVersion 27 33 | 34 | lintOptions { 35 | disable 'InvalidPackage' 36 | } 37 | 38 | defaultConfig { 39 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 40 | applicationId "com.huan.io.flutterdemo" 41 | minSdkVersion 16 42 | targetSdkVersion 27 43 | versionCode flutterVersionCode.toInteger() 44 | versionName flutterVersionName 45 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 46 | } 47 | 48 | signingConfigs { 49 | release { 50 | keyAlias keystoreProperties['keyAlias'] 51 | keyPassword keystoreProperties['keyPassword'] 52 | storeFile file(keystoreProperties['storeFile']) 53 | storePassword keystoreProperties['storePassword'] 54 | } 55 | } 56 | 57 | buildTypes { 58 | release { 59 | // TODO: Add your own signing config for the release build. 60 | // Signing with the debug keys for now, so `flutter run --release` works. 61 | signingConfig signingConfigs.release 62 | } 63 | } 64 | } 65 | 66 | flutter { 67 | source '../..' 68 | } 69 | 70 | dependencies { 71 | testImplementation 'junit:junit:4.12' 72 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 73 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 74 | } 75 | -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/java/com/huan/io/flutterdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.huan.io.flutterdemo; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import io.flutter.app.FlutterActivity; 6 | import io.flutter.plugins.GeneratedPluginRegistrant; 7 | 8 | public class MainActivity extends FlutterActivity { 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | //fultter 默认的状态栏是半透明的,所以要判断5.0以上后要设置成透明才能让标题栏颜色和状态栏颜色一致 13 | if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) 14 | {//API>21,设置状态栏颜色透明 15 | getWindow().setStatusBarColor(0); 16 | } 17 | GeneratedPluginRegistrant.registerWith(this); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_demo/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_demo/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | /* google() 4 | jcenter()*/ 5 | maven { url 'https://maven.aliyun.com/repository/google' } 6 | maven { url 'https://maven.aliyun.com/repository/jcenter' } 7 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.2.1' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | /* google() 18 | jcenter()*/ 19 | maven { url 'https://maven.aliyun.com/repository/google' } 20 | maven { url 'https://maven.aliyun.com/repository/jcenter' } 21 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } 22 | } 23 | } 24 | 25 | rootProject.buildDir = '../build' 26 | subprojects { 27 | project.buildDir = "${rootProject.buildDir}/${project.name}" 28 | } 29 | subprojects { 30 | project.evaluationDependsOn(':app') 31 | } 32 | 33 | task clean(type: Delete) { 34 | delete rootProject.buildDir 35 | } 36 | -------------------------------------------------------------------------------- /flutter_demo/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /flutter_demo/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /flutter_demo/android/key.properties: -------------------------------------------------------------------------------- 1 | storePassword=toutiao601 2 | keyPassword=123456 3 | keyAlias=toutiao 4 | storeFile=C:/Users/Administrator/Desktop/commonkey/toutiao.keystore 5 | flutter -------------------------------------------------------------------------------- /flutter_demo/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /flutter_demo/images/fiction_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_1.png -------------------------------------------------------------------------------- /flutter_demo/images/fiction_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_2.png -------------------------------------------------------------------------------- /flutter_demo/images/fiction_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_3.png -------------------------------------------------------------------------------- /flutter_demo/images/fiction_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_4.png -------------------------------------------------------------------------------- /flutter_demo/images/fiction_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_author.png -------------------------------------------------------------------------------- /flutter_demo/images/fiction_header_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/fiction_header_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_add_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_add_comment.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_back.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_back_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_back_pressed.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_coin.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_coin_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_coin_bg.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_function_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_function_search.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_history_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_history_time.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_logo.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_fiction_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_fiction_normal.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_fiction_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_fiction_selected.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_micro_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_micro_normal.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_micro_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_micro_select.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_news_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_news_normal.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_news_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_news_selected.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_person_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_person_normal.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_main_tab_person_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_main_tab_person_selected.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_replace.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_right.png -------------------------------------------------------------------------------- /flutter_demo/images/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/icon_share.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_apprentice_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_apprentice_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_cash_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_cash_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_code_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_code_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_guess_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_guess_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_message_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_message_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_read_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_read_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_riddle_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_riddle_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_wallet_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_wallet_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/mine_withdraw_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/mine_withdraw_icon.png -------------------------------------------------------------------------------- /flutter_demo/images/personal_ava_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/personal_ava_default.png -------------------------------------------------------------------------------- /flutter_demo/images/personal_heart_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/personal_heart_bg.png -------------------------------------------------------------------------------- /flutter_demo/images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/images/setting.png -------------------------------------------------------------------------------- /flutter_demo/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_demo/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /flutter_demo/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /flutter_demo/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 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /flutter_demo/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 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/flutter_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /flutter_demo/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. -------------------------------------------------------------------------------- /flutter_demo/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 | -------------------------------------------------------------------------------- /flutter_demo/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 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_demo 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 | -------------------------------------------------------------------------------- /flutter_demo/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /flutter_demo/lib/FictionDetailPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'controller/HttpController.dart'; 3 | import 'bean/FictionDetailResponse.dart'; 4 | import 'view/StaticRatingBar.dart'; 5 | 6 | class FictionDetailPage extends StatefulWidget{ 7 | final int fictionId; 8 | 9 | FictionDetailPage({this.fictionId}); 10 | 11 | @override 12 | State createState() { 13 | // TODO: implement createState 14 | return new FictionDetailPageState(); 15 | } 16 | 17 | } 18 | 19 | class FictionDetailPageState extends State{ 20 | HttpController mHttpController; 21 | @override 22 | void initState() { 23 | // TODO: implement initState 24 | super.initState(); 25 | assert(widget.fictionId!=null); 26 | mHttpController=new HttpController(); 27 | 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | // TODO: implement build 33 | return Theme( 34 | data: ThemeData( 35 | primaryColor: Color(0xFFF5F5F5) 36 | ), 37 | child: Scaffold( 38 | body: Stack( 39 | children: [ 40 | Positioned( 41 | top: 0.0, 42 | left: 0.0, 43 | child: Container( 44 | height: MediaQuery.of(context).padding.top, 45 | width: MediaQuery.of(context).size.width, 46 | ) 47 | ), 48 | Positioned( 49 | left: 0.0, 50 | top: MediaQuery.of(context).padding.top, 51 | width: MediaQuery.of(context).size.width, 52 | height: 45.0, 53 | child: Container( 54 | color: Color(0xFFF5F5F5), 55 | padding: EdgeInsets.all(10.0), 56 | child: Row( 57 | crossAxisAlignment: CrossAxisAlignment.center, 58 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 59 | children: [ 60 | InkWell( 61 | onTap: (){ 62 | Navigator.pop(context); 63 | }, 64 | child: Image.asset('images/icon_back.png',width: 24.0,height: 24.0,), 65 | ), 66 | InkWell( 67 | onTap: (){ 68 | Navigator.pop(context); 69 | }, 70 | child: Image.asset('images/icon_share.png',width: 20.0,height: 20.0,) 71 | ), 72 | ], 73 | ), 74 | ) 75 | ), 76 | Positioned( 77 | left: 0.0, 78 | top: MediaQuery.of(context).padding.top+45.0, 79 | width: MediaQuery.of(context).size.width, 80 | height:MediaQuery.of(context).size.height- MediaQuery.of(context).padding.top-45.0-48.0, 81 | child: ListView( 82 | padding: EdgeInsets.only(top: 0.0), //ListView 的paddingTop 默认是有会有30左右的高度,所以这里一定要记得设置为0,一开始不知道的时候搞了好久都没明白 83 | children: [ 84 | FutureBuilder( 85 | future: mHttpController.getFictionDetail(widget.fictionId), 86 | // future: mHttpController.getFictionDetail(434), 87 | builder: (BuildContext context, AsyncSnapshot snapshot){ 88 | switch (snapshot.connectionState) { 89 | case ConnectionState.waiting: 90 | return Center( 91 | child: CircularProgressIndicator(), 92 | ); 93 | case ConnectionState.done: 94 | if (snapshot.hasError) return Text('Error: ${snapshot.error}'); 95 | return getFictionHomeContent(snapshot.data,context); 96 | default: 97 | return null; 98 | } 99 | } 100 | ), 101 | ], 102 | ), 103 | ), 104 | Positioned( 105 | left: 0.0, 106 | top: MediaQuery.of(context).size.height-48.0, 107 | width: MediaQuery.of(context).size.width, 108 | height: 48.0, 109 | child: Row( 110 | children: [ 111 | Expanded( 112 | flex: 1, 113 | child: Container( 114 | color: Color(0xFFF5F5F5), 115 | child: Center( 116 | child: Text('加入书架',style: TextStyle(fontSize: 18.0,color: Color(0xFFFFB30A)),), 117 | ), 118 | ) 119 | ), 120 | Expanded( 121 | flex: 1, 122 | child: Container( 123 | color: Color(0xFFFFB30A), 124 | /*child: Center( 125 | child: Text('开始阅读',style: TextStyle(fontSize: 18.0,color: Colors.white),), 126 | ),*/ 127 | child: InkWell( 128 | onTap: (){ 129 | 130 | }, 131 | child: Center( 132 | child: Text('开始阅读',style: TextStyle(fontSize: 18.0,color: Colors.white),), 133 | ), 134 | ), 135 | ) 136 | ), 137 | ], 138 | ) 139 | ) 140 | ], 141 | ), 142 | ) 143 | ); 144 | } 145 | 146 | void editComment(BuildContext context){ 147 | showModalBottomSheet( 148 | context: context, 149 | builder: (BuildContext context){ 150 | return Container( 151 | color: Color(0xFFF5F5F5), 152 | padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), 153 | child: Column( 154 | mainAxisSize: MainAxisSize.min, 155 | crossAxisAlignment: CrossAxisAlignment.center, 156 | children: [ 157 | Container( 158 | padding: EdgeInsets.only(left: 18.0,top: 18.0,right: 18.0,bottom: 12.0), 159 | child: TextField( 160 | autofocus: true, 161 | keyboardType: TextInputType.text, 162 | maxLines: 1, 163 | decoration: InputDecoration( 164 | hintText: "请文明发言,遵守评论规则", 165 | hintStyle: TextStyle( 166 | color: Color(0xFF999999), 167 | fontSize: 16.0, 168 | ), 169 | contentPadding: EdgeInsets.all(10.0), 170 | filled: true, 171 | fillColor: Colors.white, 172 | enabledBorder: OutlineInputBorder( 173 | borderRadius: BorderRadius.circular(5.0), 174 | borderSide: BorderSide( 175 | width: 0.0, 176 | color: Colors.white 177 | ) 178 | ), 179 | focusedBorder: OutlineInputBorder( 180 | borderRadius: BorderRadius.circular(5.0), 181 | borderSide: BorderSide( 182 | width: 0.0, 183 | color: Colors.white 184 | ) 185 | ) 186 | ), 187 | ), 188 | ), 189 | Container( 190 | padding: EdgeInsets.only(left: 18.0,right: 18.0,bottom: 18.0), 191 | child: Row( 192 | children: [ 193 | Container( 194 | child: Icon( 195 | Icons.sentiment_satisfied, 196 | ) 197 | ), 198 | Container( 199 | margin: EdgeInsets.only(left: 20.0), 200 | child: Icon( 201 | Icons.copyright, 202 | ) 203 | ), 204 | 205 | Expanded( 206 | flex: 1, 207 | child:Container() , 208 | ), 209 | 210 | Container( 211 | width: 65.0, 212 | height: 30.0, 213 | decoration: BoxDecoration( 214 | borderRadius: BorderRadius.circular(5.0), 215 | color: Color(0xFFFFB30A) 216 | ), 217 | child: Center( 218 | child: Text("发送",style: TextStyle( 219 | fontSize: 14.0,color: Colors.white 220 | ),), 221 | ), 222 | ) 223 | 224 | ], 225 | ), 226 | ) 227 | 228 | ], 229 | ), 230 | ); 231 | } 232 | ); 233 | } 234 | 235 | Widget getFictionHomeContent(FictionDetailResponse fictionDetailResponse,BuildContext context){ 236 | return Column( 237 | mainAxisAlignment: MainAxisAlignment.start, 238 | children: [ 239 | getCoverWidget(fictionDetailResponse.data), 240 | getDescView(fictionDetailResponse.data), 241 | getCommentView(fictionDetailResponse.data,context), 242 | getHotPushWidgets(fictionDetailResponse.data.pushBookList), 243 | ], 244 | ); 245 | } 246 | 247 | Widget getCoverWidget(FictionDetailBean fictionDetailBean) { 248 | return Container( 249 | padding: EdgeInsets.only(top: 10.0, bottom: 15.0), 250 | child: Row( 251 | mainAxisAlignment: MainAxisAlignment.center, 252 | children: [ 253 | Image.network( 254 | fictionDetailBean.picture, width: 90.0, height: 120.0,), 255 | Container( 256 | padding: EdgeInsets.only(left: 10.0), 257 | child: Column( 258 | mainAxisAlignment: MainAxisAlignment.center, 259 | crossAxisAlignment: CrossAxisAlignment.start, 260 | children: [ 261 | Text(fictionDetailBean.name, style: TextStyle(fontSize: 16.0, 262 | fontWeight: FontWeight.bold, 263 | color: Color(0xFF333333)),), 264 | Container( 265 | margin: EdgeInsets.only(top: 7.0), 266 | child: StaticRatingBar( 267 | size: 12.0, 268 | rate: fictionDetailBean.score.toDouble(), 269 | ), 270 | ), 271 | Container( 272 | margin: EdgeInsets.only(top: 7.0), 273 | child: Text(fictionDetailBean.author,style: TextStyle(fontSize: 12.0,color: Color(0xFF999999)),), 274 | ), 275 | Container( 276 | margin: EdgeInsets.only(top: 7.0), 277 | child: Row( 278 | mainAxisAlignment: MainAxisAlignment.start, 279 | children: [ 280 | Text(fictionDetailBean.state,style: TextStyle(fontSize: 12.0,color: Color(0xFF999999)),), 281 | Container( 282 | padding: EdgeInsets.only(left: 10.0), 283 | child: Text(fictionDetailBean.wordCount.toString()+'万字',style: TextStyle(fontSize: 12.0,color: Color(0xFF999999)),), 284 | ) 285 | ], 286 | ) 287 | ), 288 | Container( 289 | margin: EdgeInsets.only(top: 7.0), 290 | child: Row( 291 | mainAxisAlignment: MainAxisAlignment.start, 292 | children: fictionDetailBean.tags.map((String table){ 293 | return getTableView(table); 294 | }).toList(), 295 | ), 296 | ), 297 | ], 298 | ), 299 | ), 300 | ], 301 | ) 302 | ); 303 | } 304 | 305 | Widget getCommentView(FictionDetailBean fictionDetailBean,BuildContext context){ 306 | if(fictionDetailBean.lastComment!=null){ 307 | return Column( 308 | children: [ 309 | Container( 310 | padding: EdgeInsets.all(12.0), 311 | color: Colors.white, 312 | child: Row( 313 | children: [ 314 | Text('书友互动',style: TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold,color: Color(0xFF333333)),), 315 | Container( 316 | margin: EdgeInsets.only(left: 5.0), 317 | child: Text(fictionDetailBean.commentCount.toString()+'评',style: TextStyle(fontSize: 12.0,color: Color(0xFF999999)),), 318 | ), 319 | Container( 320 | margin: EdgeInsets.only(left: 153.0), 321 | child: InkWell( 322 | onTap: (){ 323 | editComment(context); 324 | }, 325 | child: Image.asset('images/icon_add_comment.png',width: 87.0,height: 32.0,), 326 | ) 327 | ) 328 | ], 329 | ), 330 | ), 331 | Container( 332 | padding: EdgeInsets.only(left: 12.0,right: 12.0,bottom: 12.0), 333 | color: Colors.white, 334 | child: Row( 335 | crossAxisAlignment: CrossAxisAlignment.start, 336 | children: [ 337 | ClipOval( 338 | child: Image.network(fictionDetailBean.lastComment.userAvatar,width: 36.0,height: 36.0,), 339 | ), 340 | Expanded( 341 | child: Container( 342 | margin: EdgeInsets.only(left: 10.0), 343 | child: Column( 344 | crossAxisAlignment: CrossAxisAlignment.start, 345 | mainAxisAlignment: MainAxisAlignment.start, 346 | children: [ 347 | Text(fictionDetailBean.lastComment.userName,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 348 | Container( 349 | margin: EdgeInsets.only(top: 3.0), 350 | child: StaticRatingBar( 351 | size: 12.0, 352 | rate: fictionDetailBean.lastComment.level.toDouble(), 353 | ), 354 | ), 355 | Container( 356 | margin: EdgeInsets.only(top: 10.0), 357 | child: Text(fictionDetailBean.lastComment.comment,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),maxLines: 2,overflow: TextOverflow.ellipsis,), 358 | ) 359 | ], 360 | ), 361 | ) 362 | ) 363 | 364 | ], 365 | ), 366 | ), 367 | Container( 368 | margin: EdgeInsets.only(top: 1.0), 369 | color: Colors.white, 370 | padding: EdgeInsets.all(12.0), 371 | child: Row( 372 | mainAxisAlignment: MainAxisAlignment.center, 373 | children: [ 374 | Text('查看更多',style: TextStyle(fontSize: 14.0,color: Color(0xFFFFB30A)),), 375 | Container( 376 | margin: EdgeInsets.only(left: 5.0), 377 | child: Image.asset('images/icon_right.png',width: 6.0,height: 12.0,), 378 | ) 379 | ], 380 | ), 381 | ) 382 | ], 383 | ); 384 | }else{ 385 | return Container( 386 | color: Colors.white, 387 | child: Column( 388 | crossAxisAlignment: CrossAxisAlignment.center, 389 | children: [ 390 | Container( 391 | padding: EdgeInsets.all(12.0), 392 | child: Row( 393 | children: [ 394 | Text('书友互动',style: TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold,color: Color(0xFF333333)),), 395 | ], 396 | ), 397 | ), 398 | Container( 399 | margin: EdgeInsets.only(top: 40.0,bottom: 10.0), 400 | child: Text('暂时还没有评论',style: TextStyle(fontSize: 12.0,color: Color(0xFF999999)),), 401 | ), 402 | Container( 403 | margin: EdgeInsets.only(bottom: 40.0), 404 | child: InkWell( 405 | onTap: (){ 406 | editComment(context); 407 | }, 408 | child: Image.asset('images/icon_add_comment.png',width: 87.0,height: 32.0,), 409 | ) 410 | ), 411 | ], 412 | ), 413 | ); 414 | } 415 | } 416 | 417 | Widget getDescView(FictionDetailBean fictionDetailBean){ 418 | return Column( 419 | children: [ 420 | Container( 421 | color: Colors.white, 422 | padding: EdgeInsets.all(12.0), 423 | child: Text(fictionDetailBean.description,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),maxLines: 3,overflow: TextOverflow.ellipsis,), 424 | ), 425 | Container( 426 | height: 1.0, 427 | color: Color(0xFFF5F5F5), 428 | ), 429 | Container( 430 | padding: EdgeInsets.all(12.0), 431 | width: MediaQuery.of(context).size.width, 432 | color: Colors.white, 433 | child: Stack( 434 | alignment: AlignmentDirectional.center, 435 | children: [ 436 | Row( 437 | crossAxisAlignment: CrossAxisAlignment.center, 438 | children: [ 439 | Text('目录',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333),fontWeight: FontWeight.bold),), 440 | Container( 441 | margin: EdgeInsets.only(left: 17.0), 442 | child: Text('连载至'+fictionDetailBean.chapterCount.toString()+'章',style: TextStyle(fontSize: 14.0,color: Color(0xFF666666)),), 443 | ), 444 | 445 | ], 446 | ), 447 | Row( 448 | textDirection: TextDirection.rtl, 449 | mainAxisAlignment: MainAxisAlignment.start, 450 | crossAxisAlignment: CrossAxisAlignment.center, 451 | children: [ 452 | Image.asset('images/icon_right.png',width: 6.0,height: 12.0,) 453 | ], 454 | ) 455 | ], 456 | ), 457 | ), 458 | Container( 459 | height: 12.0, 460 | color: Color(0xFFF5F5F5), 461 | ), 462 | ], 463 | ); 464 | } 465 | 466 | Widget getTableView(String table){ 467 | return Container( 468 | margin: EdgeInsets.only(right: 10.0), 469 | child: DecoratedBox( 470 | decoration: BoxDecoration( 471 | borderRadius: BorderRadius.circular(20.0), 472 | border: Border.all( 473 | color: Color(0xFFFFB30A), 474 | width: 1.0 475 | ) 476 | ), 477 | child: Container( 478 | padding: EdgeInsets.fromLTRB(10.0, 2.0, 10.0, 2.0), 479 | child: Center( 480 | child: Text(table,style: TextStyle(fontSize: 12.0,color: Color(0xFFFFB30A)),), 481 | ), 482 | ) 483 | ), 484 | ); 485 | } 486 | 487 | //获取热门推荐 488 | Widget getHotPushWidgets(List hotPushLists){ 489 | return Container( 490 | margin: EdgeInsets.only(top: 12.0,bottom: 12.0), 491 | padding: EdgeInsets.all(12.0), 492 | color: Colors.white, 493 | child: Column( 494 | crossAxisAlignment: CrossAxisAlignment.start, 495 | children: [ 496 | Text('同类热门推荐',style: TextStyle(fontSize: 16.0,color: Colors.black,fontWeight: FontWeight.bold),), 497 | Container( 498 | padding: EdgeInsets.only(top: 10.0), 499 | child: Row( 500 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 501 | children: hotPushLists.map((FictionPushBook fictionPushBook){ 502 | return getFictionNormalStyle(fictionPushBook); 503 | }).toList(), 504 | ), 505 | ), 506 | ], 507 | ), 508 | ); 509 | } 510 | 511 | Widget getFictionNormalStyle(FictionPushBook fictionPushBook){ 512 | return InkWell( 513 | onTap: (){ 514 | Navigator.push(context, 515 | MaterialPageRoute(builder: (context){ 516 | 517 | })); 518 | }, 519 | child: Column( 520 | mainAxisSize: MainAxisSize.min, 521 | mainAxisAlignment: MainAxisAlignment.start, 522 | crossAxisAlignment: CrossAxisAlignment.start, 523 | children: [ 524 | Image.network(fictionPushBook.picture,width: 90.0,height: 120.0,), 525 | Container( 526 | width: 90.0, 527 | margin: EdgeInsets.only(top: 5.0,bottom: 3.0), 528 | child: Text(fictionPushBook.name,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),softWrap: false,overflow: TextOverflow.ellipsis,), 529 | ), 530 | Container( 531 | width: 90.0, 532 | child: Text(fictionPushBook.author,style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),softWrap: false,overflow: TextOverflow.ellipsis,), 533 | ), 534 | ], 535 | ), 536 | ); 537 | } 538 | 539 | } 540 | -------------------------------------------------------------------------------- /flutter_demo/lib/FictionManFeatured.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'bean/FictionHomeInfoResponse.dart'; 3 | import 'controller/HttpController.dart'; 4 | 5 | class FictionManFeatured extends StatefulWidget{ 6 | List manLists; 7 | bool isMan; 8 | 9 | FictionManFeatured({this.manLists,this.isMan}); 10 | 11 | 12 | @override 13 | State createState() { 14 | // TODO: implement createState 15 | return new FictionManFeaturedState(); 16 | } 17 | 18 | } 19 | 20 | class FictionManFeaturedState extends State{ 21 | 22 | HttpController mHttpController; 23 | 24 | @override 25 | void initState() { 26 | // TODO: implement initState 27 | super.initState(); 28 | mHttpController=new HttpController(); 29 | } 30 | 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | // TODO: implement build 35 | return getManFeaturedWidgets(widget.manLists); 36 | } 37 | 38 | Widget getManFeaturedWidgets(List manPushLists){ 39 | return Column( 40 | crossAxisAlignment: CrossAxisAlignment.start, 41 | children: [ 42 | Container( 43 | padding: EdgeInsets.only(top: 10.0), 44 | child: Text(widget.isMan ? '男生精选' : '女生精选',style: TextStyle(fontSize: 16.0,color: Colors.black,fontWeight: FontWeight.bold),), 45 | ), 46 | Container( 47 | padding: EdgeInsets.only(top: 10.0), 48 | child: Row( 49 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 50 | children: manPushLists.map((FictionIntroduction fictionIntroduction){ 51 | return getFictionNormalStyle(fictionIntroduction); 52 | }).toList(), 53 | ), 54 | ), 55 | Container( 56 | margin: EdgeInsets.only(top: 10.0), 57 | height: 1.0, 58 | color: Color.fromARGB(150, 235, 235, 235), 59 | ), 60 | InkWell( 61 | onTap: (){ 62 | getReplaceFiction(widget.isMan ? 'boy' : 'girl'); 63 | }, 64 | child: ConstrainedBox( 65 | constraints: BoxConstraints(minWidth: MediaQuery.of(context).size.width), 66 | child: Stack( 67 | fit: StackFit.loose, 68 | alignment: AlignmentDirectional.center, 69 | children: [ 70 | Container( 71 | margin: EdgeInsets.only(top: 10.0,bottom: 10.0), 72 | child: Image.asset('images/icon_replace.png',width: 78.0,height: 22.0,), 73 | ), 74 | Text('换一换',style: TextStyle(fontSize: 14.0,color: Color(0xFFFFB30A)),) 75 | ], 76 | ), 77 | ) 78 | ), 79 | 80 | ], 81 | ); 82 | } 83 | 84 | Widget getFictionNormalStyle(FictionIntroduction fictionIntroduction){ 85 | return Column( 86 | mainAxisSize: MainAxisSize.min, 87 | mainAxisAlignment: MainAxisAlignment.start, 88 | crossAxisAlignment: CrossAxisAlignment.start, 89 | children: [ 90 | Image.network(fictionIntroduction.picture,width: 90.0,height: 120.0,), 91 | Container( 92 | width: 90.0, 93 | margin: EdgeInsets.only(top: 5.0,bottom: 3.0), 94 | child: Text(fictionIntroduction.name,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),softWrap: false,overflow: TextOverflow.ellipsis,), 95 | ), 96 | Container( 97 | width: 90.0, 98 | child: Text(fictionIntroduction.author,style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),softWrap: false,overflow: TextOverflow.ellipsis,), 99 | ), 100 | ], 101 | ); 102 | } 103 | 104 | void getReplaceFiction(String type) async{ 105 | await mHttpController.getReplaceFiction(type,(replacePushResponse){ 106 | if(replacePushResponse!=null){ 107 | setState(() { 108 | widget.manLists=replacePushResponse.data; 109 | }); 110 | } 111 | }); 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /flutter_demo/lib/ImagePickerPage.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:image_picker/image_picker.dart'; 4 | 5 | class ImagePickerPage extends StatefulWidget { 6 | @override 7 | ImagePickerPageState createState() => ImagePickerPageState(); 8 | } 9 | 10 | class ImagePickerPageState extends State { 11 | File _image; 12 | 13 | Future getImage() async { 14 | var image = await ImagePicker.pickImage(source: ImageSource.gallery); 15 | 16 | setState(() { 17 | _image = image; 18 | }); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Scaffold( 24 | appBar: AppBar( 25 | title: Text('Image Picker Example'), 26 | ), 27 | body: Center( 28 | child: _image == null 29 | ? Text('No image selected.') 30 | : Image.file(_image), 31 | ), 32 | floatingActionButton: FloatingActionButton( 33 | onPressed: getImage, 34 | tooltip: 'Pick Image', 35 | child: Icon(Icons.add_a_photo), 36 | ), 37 | ); 38 | } 39 | } -------------------------------------------------------------------------------- /flutter_demo/lib/NewsDetailPageView.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_demo/bean/NewsResData.dart'; 5 | import 'package:flutter_demo/view/NewDetailWebview.dart'; 6 | 7 | class NewsDetailPageView extends StatefulWidget{ 8 | News mNews; 9 | NewsDetailPageView({this.mNews}); 10 | 11 | @override 12 | State createState() { 13 | // TODO: implement createState 14 | return new NewsDetailPageViewState(); 15 | } 16 | 17 | } 18 | 19 | class NewsDetailPageViewState extends State{ 20 | @override 21 | Widget build(BuildContext context) { 22 | // TODO: implement build 23 | return new Theme( 24 | data: ThemeData( 25 | primaryColor: Color(0xFFF5F5F5) 26 | ), 27 | child: Scaffold( 28 | body: Column( 29 | children: [ 30 | Container( 31 | height: 40.0, 32 | child: Text('中国联通中国联通中国联通'), 33 | ), 34 | Transform(transform: null), 35 | Container( 36 | height: MediaQuery.of(context).size.height-150.0, 37 | child: NewDetailWebview(mNews: widget.mNews), 38 | ), 39 | 40 | ], 41 | ), 42 | ) 43 | ); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /flutter_demo/lib/PersonalPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PersonalPage extends StatefulWidget{ 4 | @override 5 | State createState() { 6 | // TODO: implement createState 7 | return new PersonalPageState(); 8 | } 9 | 10 | } 11 | 12 | class PersonalPageState extends State{ 13 | @override 14 | Widget build(BuildContext context) { 15 | // TODO: implement build 16 | return Scaffold( 17 | body: Column( 18 | children: [ 19 | getHeartView(), 20 | ], 21 | ), 22 | ); 23 | } 24 | 25 | Widget getHeartView(){ 26 | return Stack( 27 | children: [ 28 | Image.asset('images/personal_heart_bg.png',), 29 | Column( 30 | children: [ 31 | Row( 32 | textDirection: TextDirection.rtl, 33 | mainAxisAlignment: MainAxisAlignment.start, 34 | crossAxisAlignment: CrossAxisAlignment.center, 35 | children: [ 36 | Container( 37 | padding: EdgeInsets.all(2.0), 38 | margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top,right: 8.0), 39 | child: Image.asset('images/setting.png',width: 20.0,height: 20.0,), 40 | ) 41 | ], 42 | ), 43 | 44 | Container( 45 | margin: EdgeInsets.only(left: 20.0), 46 | child: Row( 47 | mainAxisAlignment: MainAxisAlignment.start, 48 | crossAxisAlignment: CrossAxisAlignment.center, 49 | children: [ 50 | Image.asset('images/personal_ava_default.png',width: 72.0,height: 72.0,), 51 | Container( 52 | margin: EdgeInsets.only(left: 8.0), 53 | child: Column( 54 | mainAxisAlignment: MainAxisAlignment.center, 55 | crossAxisAlignment: CrossAxisAlignment.start, 56 | children: [ 57 | Text('Betty',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333),),), 58 | Text('ID:12345678',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333),),), 59 | ], 60 | ), 61 | ) 62 | ], 63 | ), 64 | ), 65 | 66 | Container( 67 | padding: EdgeInsets.fromLTRB(30.0, 30.0, 30.0, 0.0), 68 | child: Row( 69 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 70 | crossAxisAlignment: CrossAxisAlignment.center, 71 | children: [ 72 | Column( 73 | mainAxisSize: MainAxisSize.min, 74 | crossAxisAlignment: CrossAxisAlignment.center, 75 | children: [ 76 | Text('5000',style: TextStyle(fontSize: 20.0,color: Color(0xFF333333),),), 77 | Padding( 78 | padding: EdgeInsets.only(top: 3.0), 79 | child: Text('我的金币',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 80 | ) 81 | ], 82 | ), 83 | Container( 84 | width: 1.0, 85 | height: 27.0, 86 | color: Color(0xFF999999), 87 | ), 88 | Column( 89 | mainAxisSize: MainAxisSize.min, 90 | crossAxisAlignment: CrossAxisAlignment.center, 91 | children: [ 92 | Text('10',style: TextStyle(fontSize: 20.0,color: Color(0xFF333333),),), 93 | Padding( 94 | padding: EdgeInsets.only(top: 3.0), 95 | child: Text('我的零钱',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 96 | ) 97 | ], 98 | ), 99 | Container( 100 | width: 1.0, 101 | height: 27.0, 102 | color: Color(0xFF999999), 103 | ), 104 | Column( 105 | mainAxisSize: MainAxisSize.min, 106 | crossAxisAlignment: CrossAxisAlignment.center, 107 | children: [ 108 | Text('7',style: TextStyle(fontSize: 20.0,color: Color(0xFF333333),),), 109 | Padding( 110 | padding: EdgeInsets.only(top: 3.0), 111 | child: Text('收徒人数',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 112 | ) 113 | ], 114 | ) 115 | ], 116 | ), 117 | ), 118 | 119 | Container( 120 | padding: EdgeInsets.fromLTRB(30.0, 35.0, 30.0, 15.0), 121 | child: Row( 122 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 123 | crossAxisAlignment: CrossAxisAlignment.center, 124 | children: [ 125 | Column( 126 | mainAxisSize: MainAxisSize.min, 127 | crossAxisAlignment: CrossAxisAlignment.center, 128 | children: [ 129 | Image.asset('images/mine_withdraw_icon.png',width: 24.0,height: 24.0,), 130 | Padding( 131 | padding: EdgeInsets.only(top: 3.0), 132 | child: Text('提现',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 133 | ) 134 | ], 135 | ), 136 | Column( 137 | mainAxisSize: MainAxisSize.min, 138 | crossAxisAlignment: CrossAxisAlignment.center, 139 | children: [ 140 | Image.asset('images/mine_cash_icon.png',width: 24.0,height: 24.0,), 141 | Padding( 142 | padding: EdgeInsets.only(top: 3.0), 143 | child: Text('明细',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 144 | ) 145 | ], 146 | ), 147 | Column( 148 | mainAxisSize: MainAxisSize.min, 149 | crossAxisAlignment: CrossAxisAlignment.center, 150 | children: [ 151 | Image.asset('images/mine_apprentice_icon.png',width: 24.0,height: 24.0,), 152 | Padding( 153 | padding: EdgeInsets.only(top: 3.0), 154 | child: Text('收徒',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 155 | ) 156 | ], 157 | ), 158 | Column( 159 | mainAxisSize: MainAxisSize.min, 160 | crossAxisAlignment: CrossAxisAlignment.center, 161 | children: [ 162 | Image.asset('images/mine_message_icon.png',width: 24.0,height: 24.0,), 163 | Padding( 164 | padding: EdgeInsets.only(top: 3.0), 165 | child: Text('消息',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 166 | ) 167 | ], 168 | ), 169 | ], 170 | ), 171 | ), 172 | 173 | Container( 174 | width: MediaQuery.of(context).size.width, 175 | height: 10.0, 176 | color: Color(0xFFEEEEEE), 177 | ), 178 | 179 | Container( 180 | padding: EdgeInsets.all(12.0), 181 | width: MediaQuery.of(context).size.width, 182 | color: Colors.white, 183 | child: Stack( 184 | alignment: AlignmentDirectional.center, 185 | children: [ 186 | Row( 187 | crossAxisAlignment: CrossAxisAlignment.center, 188 | children: [ 189 | Image.asset('images/mine_code_icon.png',width: 20.0,height: 20.0,), 190 | Container( 191 | padding: EdgeInsets.only(left: 10.0), 192 | child: Text('面对面收徒',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 193 | ) 194 | 195 | ], 196 | ), 197 | Row( 198 | textDirection: TextDirection.rtl, 199 | mainAxisAlignment: MainAxisAlignment.start, 200 | crossAxisAlignment: CrossAxisAlignment.center, 201 | children: [ 202 | Image.asset('images/icon_right.png',width: 6.0,height: 12.0,) 203 | ], 204 | ) 205 | ], 206 | ), 207 | ), 208 | 209 | Container( 210 | padding: EdgeInsets.all(12.0), 211 | margin: EdgeInsets.only(top: 1.0), 212 | width: MediaQuery.of(context).size.width, 213 | color: Colors.white, 214 | child: Stack( 215 | alignment: AlignmentDirectional.center, 216 | children: [ 217 | Row( 218 | crossAxisAlignment: CrossAxisAlignment.center, 219 | children: [ 220 | Image.asset('images/mine_riddle_icon.png',width: 20.0,height: 20.0,), 221 | Container( 222 | padding: EdgeInsets.only(left: 10.0), 223 | child: Text('答题解谜',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 224 | ) 225 | 226 | ], 227 | ), 228 | Row( 229 | textDirection: TextDirection.rtl, 230 | mainAxisAlignment: MainAxisAlignment.start, 231 | crossAxisAlignment: CrossAxisAlignment.center, 232 | children: [ 233 | Image.asset('images/icon_right.png',width: 6.0,height: 12.0,) 234 | ], 235 | ) 236 | ], 237 | ), 238 | ), 239 | 240 | Container( 241 | padding: EdgeInsets.all(12.0), 242 | margin: EdgeInsets.only(top: 1.0), 243 | width: MediaQuery.of(context).size.width, 244 | color: Colors.white, 245 | child: Stack( 246 | alignment: AlignmentDirectional.center, 247 | children: [ 248 | Row( 249 | crossAxisAlignment: CrossAxisAlignment.center, 250 | children: [ 251 | Image.asset('images/mine_guess_icon.png',width: 20.0,height: 20.0,), 252 | Container( 253 | padding: EdgeInsets.only(left: 10.0), 254 | child: Text('趣味竞猜',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 255 | ) 256 | 257 | ], 258 | ), 259 | Row( 260 | textDirection: TextDirection.rtl, 261 | mainAxisAlignment: MainAxisAlignment.start, 262 | crossAxisAlignment: CrossAxisAlignment.center, 263 | children: [ 264 | Image.asset('images/icon_right.png',width: 6.0,height: 12.0,) 265 | ], 266 | ) 267 | ], 268 | ), 269 | ), 270 | 271 | Container( 272 | width: MediaQuery.of(context).size.width, 273 | height: 10.0, 274 | color: Color(0xFFEEEEEE), 275 | ), 276 | 277 | Container( 278 | padding: EdgeInsets.all(12.0), 279 | margin: EdgeInsets.only(top: 1.0), 280 | width: MediaQuery.of(context).size.width, 281 | color: Colors.white, 282 | child: Stack( 283 | alignment: AlignmentDirectional.center, 284 | children: [ 285 | Row( 286 | crossAxisAlignment: CrossAxisAlignment.center, 287 | children: [ 288 | Image.asset('images/mine_wallet_icon.png',width: 20.0,height: 20.0,), 289 | Container( 290 | padding: EdgeInsets.only(left: 10.0), 291 | child: Text('赚钱攻略',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 292 | ) 293 | 294 | ], 295 | ), 296 | Row( 297 | textDirection: TextDirection.rtl, 298 | mainAxisAlignment: MainAxisAlignment.start, 299 | crossAxisAlignment: CrossAxisAlignment.center, 300 | children: [ 301 | Image.asset('images/icon_right.png',width: 6.0,height: 12.0,), 302 | Container( 303 | padding: EdgeInsets.only(right: 10.0), 304 | child: Text('教你玩转百万头条',style: TextStyle(fontSize: 13.0,color: Color(0xFFFF9600)),), 305 | ), 306 | ], 307 | ) 308 | ], 309 | ), 310 | ), 311 | 312 | ], 313 | ) 314 | ], 315 | ); 316 | } 317 | 318 | } -------------------------------------------------------------------------------- /flutter_demo/lib/ScannerPage.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:pointycastle/asymmetric/pkcs1.dart'; 6 | import 'package:pointycastle/asymmetric/rsa.dart'; 7 | import 'dart:async'; 8 | import 'package:qrcode_reader/qrcode_reader.dart'; 9 | import 'package:pointycastle/pointycastle.dart'; 10 | 11 | class ScannerPage extends StatefulWidget { 12 | 13 | final Map pluginParameters = { 14 | }; 15 | 16 | @override 17 | ScannerPageState createState() => new ScannerPageState(); 18 | } 19 | 20 | class ScannerPageState extends State { 21 | Future _barcodeString; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return new Scaffold( 26 | appBar: new AppBar( 27 | title: const Text('QRCode Reader Example'), 28 | ), 29 | body: new Center( 30 | child: new FutureBuilder( 31 | future: _barcodeString, 32 | builder: (BuildContext context, AsyncSnapshot snapshot) { 33 | return new Text(snapshot.data != null ? snapshot.data : ''); 34 | })), 35 | floatingActionButton: new FloatingActionButton( 36 | onPressed: () { 37 | // getHuText(); 38 | setState(() { 39 | _barcodeString = new QRCodeReader() 40 | .setAutoFocusIntervalInMs(200) 41 | .setForceAutoFocus(true) 42 | .setTorchEnabled(true) 43 | .setHandlePermissions(true) 44 | .setExecuteAfterPermissionGranted(true) 45 | .scan(); 46 | }); 47 | }, 48 | tooltip: 'Reader the QRCode', 49 | child: new Icon(Icons.add_a_photo), 50 | ), 51 | ); 52 | } 53 | 54 | 55 | getHuText(){ 56 | var text = "3112003057"; 57 | String key="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1nMYS0QLT6yAgHM1d+pqYhRRhTABXp/kq0W7nIUT3etjSWi8JfoqvkfShINF4CovBSTJ7sNko7j3yKEFn5HzaF1INKWTVfZprpEyFBnAa+ydBiVHKQ85vRyyoX67lMSKOrnq7B37h5bdnE7faoajsaOCnx5wtlya7AGVB4fxfOQIDAQAB"; 58 | BigInt modulus = BigInt.parse(key,radix: 16); 59 | BigInt exponent = BigInt.from(65537); 60 | var pubKey = RSAPublicKey(modulus, exponent); 61 | AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine()); 62 | cipher.init(true, PublicKeyParameter(pubKey)); 63 | Uint8List output = cipher.process(utf8.encode(text)); 64 | var base64EncodedText = base64Encode(output); 65 | print("base64EncodedText="+base64EncodedText); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /flutter_demo/lib/SearchPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_demo/bean/ChannelResponse.dart'; 4 | import 'package:flutter_demo/bean/HotSearchResponse.dart'; 5 | import 'package:flutter_demo/channelView.dart'; 6 | import 'package:flutter_demo/controller/HttpController.dart'; 7 | import 'package:flutter_demo/utils/SpUtil.dart'; 8 | import 'package:flutter_demo/view/SearchView.dart'; 9 | 10 | class SearchPage extends StatefulWidget{ 11 | 12 | @override 13 | State createState() { 14 | // TODO: implement createState 15 | return new SearchPageSate(); 16 | } 17 | } 18 | 19 | class SearchPageSate extends State{ 20 | 21 | HttpController mHttpController; 22 | 23 | List historySearchList= []; 24 | bool mShowSearchContent=false; 25 | 26 | FocusNode _focusNode = FocusNode(); 27 | TextEditingController _controller = new TextEditingController(); 28 | 29 | String mSearchText=""; 30 | 31 | @override 32 | void initState() { 33 | // TODO: implement initState 34 | super.initState(); 35 | mHttpController=new HttpController(); 36 | getHistory(); 37 | } 38 | 39 | void getHistory(){ 40 | List data=SpUtil.getStringList("historySearch",defValue : []); 41 | setState(() { 42 | historySearchList.addAll(data); 43 | }); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | // TODO: implement build 49 | // return layout(context); 50 | return Theme( 51 | data: ThemeData( 52 | primaryColor: Color(0xFFF5F5F5) 53 | ), 54 | child: Scaffold( 55 | body: Stack( 56 | children: [ 57 | Positioned( 58 | top: 0.0, 59 | left: 0.0, 60 | child: Container( 61 | color: Color(0xFFFFFFFF), 62 | height: MediaQuery.of(context).padding.top, 63 | width: MediaQuery.of(context).size.width, 64 | ) 65 | ), 66 | Positioned( 67 | top: MediaQuery.of(context).padding.top, 68 | left: 0.0, 69 | child: new Container( 70 | color: Color(0xFFFFFFFF), 71 | height: 40.0, 72 | width: MediaQuery.of(context).size.width, 73 | padding: EdgeInsets.only(left: 12.0,right: 12.0), 74 | child: Row( 75 | mainAxisAlignment: MainAxisAlignment.start, 76 | crossAxisAlignment: CrossAxisAlignment.center, 77 | children: [ 78 | Expanded( 79 | flex: 5, 80 | child: new SearchView( 81 | focusNode: _focusNode, 82 | controller: _controller, 83 | inputFormatters: [ 84 | LengthLimitingTextInputFormatter(50), 85 | ], 86 | onChangedCallback: () { 87 | onSearchTextChangeCallBack(); 88 | }, 89 | onEditingComplete: () => _checkInput() 90 | ) 91 | ), 92 | Expanded( 93 | flex: 1, 94 | child: InkWell( 95 | onTap: (){ 96 | Navigator.pop(context); 97 | }, 98 | child: Container( 99 | padding: EdgeInsets.only(left: 10.0), 100 | child: Text('取消',style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 101 | ), 102 | ) 103 | ) 104 | ], 105 | ), 106 | ), 107 | ), 108 | Positioned( 109 | top: MediaQuery.of(context).padding.top + 40.0, 110 | left: 0.0, 111 | height: MediaQuery.of(context).size.height-40.0-MediaQuery.of(context).padding.top, 112 | width: MediaQuery.of(context).size.width, 113 | child: Container( 114 | color: Color(0xFFFFFFFF), 115 | padding: EdgeInsets.only(top: 5.0), 116 | child: layout(context) 117 | ) 118 | ) 119 | ], 120 | ) 121 | ) 122 | ); 123 | } 124 | 125 | Widget layout(BuildContext context){ 126 | if(!mShowSearchContent){ 127 | return Column( 128 | children: [ 129 | getHeadView(), 130 | Container( 131 | width: MediaQuery.of(context).size.width, 132 | color: Color(0xFFFFFFFF), 133 | padding: EdgeInsets.all(12.0), 134 | child: Text('热门搜索',style: TextStyle(fontSize: 16.0,color: Color(0xFF000000),fontWeight: FontWeight.bold),), 135 | ), 136 | Container( 137 | width: MediaQuery.of(context).size.width, 138 | height: 300.0, 139 | child: FutureBuilder( 140 | future: mHttpController.getHotSearchKeyWord(), 141 | builder: (BuildContext context, AsyncSnapshot snapshot){ 142 | switch (snapshot.connectionState) { 143 | case ConnectionState.waiting: 144 | return Center( 145 | child: CircularProgressIndicator(), 146 | ); 147 | case ConnectionState.done: 148 | if (snapshot.hasError) return Text('Error: ${snapshot.error}'); 149 | return getHotSearchContent(snapshot.data); 150 | default: 151 | return null; 152 | } 153 | } 154 | ), 155 | ), 156 | ], 157 | ); 158 | }else{ 159 | return NewsListView(mChannelCode: 0.toString(),mSearchText: mSearchText,); 160 | } 161 | } 162 | 163 | void _checkInput() { 164 | String searchText = _controller.text; 165 | if (searchText.isEmpty) { 166 | FocusScope.of(context).requestFocus(_focusNode); 167 | return; 168 | } 169 | 170 | setState(() { 171 | mSearchText=searchText; 172 | mShowSearchContent=true; 173 | historySearchList.insert(0, mSearchText); 174 | SpUtil.putStringList('historySearch', historySearchList); 175 | 176 | }); 177 | 178 | } 179 | 180 | void onSearchTextChangeCallBack(){ 181 | String searchText = _controller.text; 182 | if (searchText.isEmpty) { 183 | setState(() { 184 | mSearchText=""; 185 | mShowSearchContent=false; 186 | }); 187 | } 188 | } 189 | 190 | Widget getHotSearchContent(HotSearchResponse response){ 191 | List data=response.data; 192 | return new GridView.builder( 193 | padding: const EdgeInsets.only(left: 12.0), 194 | gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( 195 | mainAxisSpacing: 5.0, 196 | crossAxisSpacing: 10.0, 197 | crossAxisCount: 2, 198 | childAspectRatio: 4.0 199 | ), 200 | itemBuilder: (BuildContext context, int index) { 201 | return InkWell( 202 | onTap: (){ 203 | setState(() { 204 | mSearchText=data[index].name; 205 | mShowSearchContent=true; 206 | _controller.text=mSearchText; 207 | }); 208 | }, 209 | child: Container( 210 | child: Row( 211 | mainAxisAlignment: MainAxisAlignment.start, 212 | crossAxisAlignment: CrossAxisAlignment.center, 213 | children: [ 214 | Text((index+1).toString()+".",style: TextStyle(fontSize: 16.0,color: Color(0xFFFFB30A)),), 215 | Text(data[index].name,style: TextStyle(fontSize: 16.0,color: Color(0xFF333333)),), 216 | ], 217 | ), 218 | ), 219 | ); 220 | }, 221 | itemCount: data.length, 222 | ); 223 | } 224 | 225 | 226 | 227 | Widget getHeadView(){ 228 | return Column( 229 | children: [ 230 | Container( 231 | height: 40.0, 232 | color: Color(0xFFF5F5F5), 233 | padding: EdgeInsets.only(left: 12.0,right: 12.0), 234 | child: Row( 235 | crossAxisAlignment: CrossAxisAlignment.center, 236 | children: [ 237 | Expanded( 238 | flex: 5, 239 | child: Text('最近搜索',style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),) 240 | ), 241 | Expanded( 242 | flex: 1, 243 | child: InkWell( 244 | onTap: (){ 245 | setState(() { 246 | historySearchList.clear(); 247 | SpUtil.putStringList('historySearch', historySearchList); 248 | }); 249 | }, 250 | child: Text('清空记录',style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),), 251 | ) 252 | ) 253 | ], 254 | ), 255 | ), 256 | Column( 257 | mainAxisAlignment: MainAxisAlignment.start, 258 | crossAxisAlignment: CrossAxisAlignment.start, 259 | children: historySearchList.map((String history){ 260 | return Column( 261 | crossAxisAlignment: CrossAxisAlignment.start, 262 | children: [ 263 | Container( 264 | height: 40.0, 265 | color: Color(0xFFFFFFFF), 266 | padding: EdgeInsets.only(left: 12.0,right: 12.0), 267 | child: Row( 268 | crossAxisAlignment: CrossAxisAlignment.center, 269 | children: [ 270 | Expanded( 271 | flex: 8, 272 | child: InkWell( 273 | onTap: (){ 274 | setState(() { 275 | mSearchText=history; 276 | mShowSearchContent=true; 277 | _controller.text=mSearchText; 278 | }); 279 | }, 280 | child: Container( 281 | padding: EdgeInsets.only(top: 5.0,bottom: 5.0), 282 | child: Text(history,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 283 | ), 284 | ) 285 | ), 286 | Expanded( 287 | flex: 1, 288 | child: InkWell( 289 | onTap: (){ 290 | setState(() { 291 | historySearchList.remove(history); 292 | }); 293 | }, 294 | child: Icon( 295 | Icons.clear, 296 | size: 18.0, 297 | color: Colors.grey, 298 | ), 299 | ) 300 | ) 301 | ], 302 | ) 303 | ), 304 | Container( 305 | margin: EdgeInsets.only(left: 12.0,right: 12.0), 306 | child: Divider(height: 2.0,), 307 | ) 308 | ], 309 | ); 310 | }).toList(), 311 | ) 312 | ], 313 | ); 314 | } 315 | 316 | } -------------------------------------------------------------------------------- /flutter_demo/lib/bean/BannerInfoResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class BannerInfoResponse { 4 | 5 | int result; 6 | String msg; 7 | List data; 8 | 9 | BannerInfoResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory BannerInfoResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new BannerInfoResponse.fromJson(json.decode(jsonStr)) : new BannerInfoResponse.fromJson(jsonStr); 12 | 13 | BannerInfoResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : []; 17 | 18 | for (var dataItem in data == null ? [] : jsonRes['data']){ 19 | data.add(dataItem == null ? null : new DataBean.fromJson(dataItem)); 20 | } 21 | } 22 | 23 | @override 24 | String toString() { 25 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 26 | } 27 | } 28 | 29 | class DataBean { 30 | 31 | String redirctUrl; 32 | int flagId; 33 | String infoType; 34 | String pictureUrl; 35 | String redirectType; 36 | 37 | DataBean.fromParams({this.redirctUrl, this.flagId, this.infoType, this.pictureUrl, this.redirectType}); 38 | 39 | DataBean.fromJson(jsonRes) { 40 | redirctUrl = jsonRes['redirctUrl']; 41 | flagId = jsonRes['flagId']; 42 | infoType = jsonRes['infoType']; 43 | pictureUrl = jsonRes['pictureUrl']; 44 | redirectType = jsonRes['redirectType']; 45 | } 46 | 47 | @override 48 | String toString() { 49 | return '{"redirctUrl": ${redirctUrl != null?'${json.encode(redirctUrl)}':'null'},"flagId": $flagId,"infoType": ${infoType != null?'${json.encode(infoType)}':'null'},"pictureUrl": ${pictureUrl != null?'${json.encode(pictureUrl)}':'null'},"redirectType": ${redirectType != null?'${json.encode(redirectType)}':'null'}}'; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/ChannelResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class ChannelResponse { 4 | 5 | int result; 6 | String msg; 7 | List data; 8 | 9 | ChannelResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory ChannelResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new ChannelResponse.fromJson(json.decode(jsonStr)) : new ChannelResponse.fromJson(jsonStr); 12 | 13 | ChannelResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : []; 17 | 18 | for (var dataItem in data == null ? [] : jsonRes['data']){ 19 | data.add(dataItem == null ? null : new Channel.fromJson(dataItem)); 20 | } 21 | } 22 | 23 | @override 24 | String toString() { 25 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 26 | } 27 | } 28 | 29 | class Channel { 30 | 31 | int code; 32 | int sortIndex; 33 | bool isUserTag; 34 | String name; 35 | 36 | Channel.fromParams({this.code, this.sortIndex, this.isUserTag, this.name}); 37 | 38 | Channel.fromJson(jsonRes) { 39 | code = jsonRes['code']; 40 | sortIndex = jsonRes['sortIndex']; 41 | isUserTag = jsonRes['isUserTag']; 42 | name = jsonRes['name']; 43 | } 44 | 45 | @override 46 | String toString() { 47 | return '{"code": $code,"sortIndex": $sortIndex,"isUserTag": $isUserTag,"name": ${name != null?'${json.encode(name)}':'null'}}'; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/FictionDetailResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class FictionDetailResponse { 4 | 5 | int result; 6 | String msg; 7 | FictionDetailBean data; 8 | 9 | FictionDetailResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory FictionDetailResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new FictionDetailResponse.fromJson(json.decode(jsonStr)) : new FictionDetailResponse.fromJson(jsonStr); 12 | 13 | FictionDetailResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : new FictionDetailBean.fromJson(jsonRes['data']); 17 | } 18 | 19 | @override 20 | String toString() { 21 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 22 | } 23 | } 24 | 25 | class FictionDetailBean { 26 | 27 | int chapterCount; 28 | int commentCount; 29 | int id; 30 | int score; 31 | int wordCount; 32 | bool isFavorite; 33 | String author; 34 | String cp; 35 | String description; 36 | String lastChapter; 37 | String name; 38 | String picture; 39 | String state; 40 | List pushBookList; 41 | List tags; 42 | LastComment lastComment; 43 | 44 | FictionDetailBean.fromParams({this.chapterCount, this.commentCount, this.id, this.score, this.wordCount, this.isFavorite, this.author, this.cp, this.description, this.lastChapter, this.name, this.picture, this.state, this.pushBookList, this.tags, this.lastComment}); 45 | 46 | FictionDetailBean.fromJson(jsonRes) { 47 | chapterCount = jsonRes['chapterCount']; 48 | commentCount = jsonRes['commentCount']; 49 | id = jsonRes['id']; 50 | score = jsonRes['score']; 51 | wordCount = jsonRes['wordCount']; 52 | isFavorite = jsonRes['isFavorite']; 53 | author = jsonRes['author']; 54 | cp = jsonRes['cp']; 55 | description = jsonRes['description']; 56 | lastChapter = jsonRes['lastChapter']; 57 | name = jsonRes['name']; 58 | picture = jsonRes['picture']; 59 | state = jsonRes['state']; 60 | pushBookList = jsonRes['pushBookList'] == null ? null : []; 61 | 62 | for (var pushBookListItem in pushBookList == null ? [] : jsonRes['pushBookList']){ 63 | pushBookList.add(pushBookListItem == null ? null : new FictionPushBook.fromJson(pushBookListItem)); 64 | } 65 | 66 | tags = jsonRes['tags'] == null ? null : []; 67 | 68 | for (var tagsItem in tags == null ? [] : jsonRes['tags']){ 69 | tags.add(tagsItem); 70 | } 71 | 72 | lastComment = jsonRes['lastComment'] == null ? null : new LastComment.fromJson(jsonRes['lastComment']); 73 | } 74 | 75 | @override 76 | String toString() { 77 | return '{"chapterCount": $chapterCount,"commentCount": $commentCount,"id": $id,"score": $score,"wordCount": $wordCount,"isFavorite": $isFavorite,"author": ${author != null?'${json.encode(author)}':'null'},"cp": ${cp != null?'${json.encode(cp)}':'null'},"description": ${description != null?'${json.encode(description)}':'null'},"lastChapter": ${lastChapter != null?'${json.encode(lastChapter)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'},"picture": ${picture != null?'${json.encode(picture)}':'null'},"state": ${state != null?'${json.encode(state)}':'null'},"pushBookList": $pushBookList,"tags": $tags,"lastComment": $lastComment}'; 78 | } 79 | } 80 | 81 | class LastComment { 82 | 83 | int level; 84 | String comment; 85 | String userAvatar; 86 | String userName; 87 | 88 | LastComment.fromParams({this.level, this.comment, this.userAvatar, this.userName}); 89 | 90 | LastComment.fromJson(jsonRes) { 91 | level = jsonRes['level']; 92 | comment = jsonRes['comment']; 93 | userAvatar = jsonRes['userAvatar']; 94 | userName = jsonRes['userName']; 95 | } 96 | 97 | @override 98 | String toString() { 99 | return '{"level": $level,"comment": ${comment != null?'${json.encode(comment)}':'null'},"userAvatar": ${userAvatar != null?'${json.encode(userAvatar)}':'null'},"userName": ${userName != null?'${json.encode(userName)}':'null'}}'; 100 | } 101 | } 102 | 103 | class FictionPushBook { 104 | 105 | int id; 106 | String author; 107 | String name; 108 | String picture; 109 | 110 | FictionPushBook.fromParams({this.id, this.author, this.name, this.picture}); 111 | 112 | FictionPushBook.fromJson(jsonRes) { 113 | id = jsonRes['id']; 114 | author = jsonRes['author']; 115 | name = jsonRes['name']; 116 | picture = jsonRes['picture']; 117 | } 118 | 119 | @override 120 | String toString() { 121 | return '{"id": $id,"author": ${author != null?'${json.encode(author)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'},"picture": ${picture != null?'${json.encode(picture)}':'null'}}'; 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/FictionHomeInfoResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class FictionHomeInfoResponse { 4 | 5 | List other; 6 | HotPushResponse editerPush; 7 | HotPushResponse freeTime; 8 | HotPushResponse hotPush; 9 | 10 | FictionHomeInfoResponse.fromParams({this.other, this.editerPush, this.freeTime, this.hotPush}); 11 | 12 | factory FictionHomeInfoResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new FictionHomeInfoResponse.fromJson(json.decode(jsonStr)) : new FictionHomeInfoResponse.fromJson(jsonStr); 13 | 14 | FictionHomeInfoResponse.fromJson(jsonRes) { 15 | other = jsonRes['other'] == null ? null : []; 16 | 17 | for (var otherItem in other == null ? [] : jsonRes['other']){ 18 | other.add(otherItem == null ? null : new HotPushResponse.fromJson(otherItem)); 19 | } 20 | 21 | editerPush = jsonRes['editerPush'] == null ? null : new HotPushResponse.fromJson(jsonRes['editerPush']); 22 | freeTime = jsonRes['freeTime'] == null ? null : new HotPushResponse.fromJson(jsonRes['freeTime']); 23 | hotPush = jsonRes['hotPush'] == null ? null : new HotPushResponse.fromJson(jsonRes['hotPush']); 24 | } 25 | 26 | @override 27 | String toString() { 28 | return '{"other": $other,"editerPush": $editerPush,"freeTime": $freeTime,"hotPush": $hotPush}'; 29 | } 30 | } 31 | 32 | class HotPushResponse{ 33 | int result; 34 | String msg; 35 | String type; 36 | String title; 37 | List data; 38 | 39 | HotPushResponse.fromParams({this.result, this.msg, this.type, this.title, this.data}); 40 | 41 | factory HotPushResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new HotPushResponse.fromJson(json.decode(jsonStr)) : new HotPushResponse.fromJson(jsonStr); 42 | 43 | HotPushResponse.fromJson(jsonRes) { 44 | result = jsonRes['result']; 45 | msg = jsonRes['msg']; 46 | type = jsonRes['type']; 47 | title = jsonRes['title']; 48 | data = jsonRes['data'] == null ? null : []; 49 | 50 | for (var dataItem in data == null ? [] : jsonRes['data']){ 51 | data.add(dataItem == null ? null : new FictionIntroduction.fromJson(dataItem)); 52 | } 53 | } 54 | 55 | @override 56 | String toString() { 57 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"type": ${type != null?'${json.encode(type)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"data": $data}'; 58 | } 59 | 60 | } 61 | 62 | class FictionIntroduction { 63 | 64 | int bookId; 65 | String author; 66 | String description; 67 | String name; 68 | String picture; 69 | String pushDescription; 70 | 71 | FictionIntroduction.fromParams({this.bookId, this.author, this.description, this.name, this.picture, this.pushDescription}); 72 | 73 | FictionIntroduction.fromJson(jsonRes) { 74 | bookId = jsonRes['bookId']; 75 | author = jsonRes['author']; 76 | description = jsonRes['description']; 77 | name = jsonRes['name']; 78 | picture = jsonRes['picture']; 79 | pushDescription = jsonRes['pushDescription']; 80 | } 81 | 82 | @override 83 | String toString() { 84 | return '{"bookId": $bookId,"author": ${author != null?'${json.encode(author)}':'null'},"description": ${description != null?'${json.encode(description)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'},"picture": ${picture != null?'${json.encode(picture)}':'null'},"pushDescription": ${pushDescription != null?'${json.encode(pushDescription)}':'null'}}'; 85 | } 86 | } 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/HotSearchResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class HotSearchResponse { 4 | 5 | int result; 6 | String msg; 7 | List data; 8 | 9 | HotSearchResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory HotSearchResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new HotSearchResponse.fromJson(json.decode(jsonStr)) : new HotSearchResponse.fromJson(jsonStr); 12 | 13 | HotSearchResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : []; 17 | 18 | for (var dataItem in data == null ? [] : jsonRes['data']){ 19 | data.add(dataItem == null ? null : new HotSearchBean.fromJson(dataItem)); 20 | } 21 | } 22 | 23 | @override 24 | String toString() { 25 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 26 | } 27 | } 28 | 29 | class HotSearchBean { 30 | 31 | int code; 32 | String name; 33 | 34 | HotSearchBean.fromParams({this.code, this.name}); 35 | 36 | HotSearchBean.fromJson(jsonRes) { 37 | code = jsonRes['code']; 38 | name = jsonRes['name']; 39 | } 40 | 41 | @override 42 | String toString() { 43 | return '{"code": $code,"name": ${name != null?'${json.encode(name)}':'null'}}'; 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/NewsDetailResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class NewsDetailResponse { 4 | 5 | int result; 6 | String msg; 7 | NewsDetail data; 8 | 9 | NewsDetailResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory NewsDetailResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new NewsDetailResponse.fromJson(json.decode(jsonStr)) : new NewsDetailResponse.fromJson(jsonStr); 12 | 13 | NewsDetailResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : new NewsDetail.fromJson(jsonRes['data']); 17 | } 18 | 19 | @override 20 | String toString() { 21 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 22 | } 23 | } 24 | 25 | class NewsDetail { 26 | 27 | int FPS; 28 | int addTime; 29 | int bitRate; 30 | int commentCount; 31 | int id; 32 | int likes; 33 | int readcount; 34 | int videoSize; 35 | bool enableComment; 36 | bool isFavorite; 37 | bool isNoneImg; 38 | String addTimeStr; 39 | String author; 40 | String content; 41 | String description; 42 | String src; 43 | String timeLong; 44 | String title; 45 | String videoSrc; 46 | String xcShareId; 47 | String xcSharePath; 48 | List pictureList; 49 | List tagList; 50 | 51 | NewsDetail.fromParams({this.FPS, this.addTime, this.bitRate, this.commentCount, this.id, this.likes, this.readcount, this.videoSize, this.enableComment, this.isFavorite, this.isNoneImg, this.addTimeStr, this.author, this.content, this.description, this.src, this.timeLong, this.title, this.videoSrc, this.xcShareId, this.xcSharePath, this.pictureList, this.tagList}); 52 | 53 | NewsDetail.fromJson(jsonRes) { 54 | FPS = jsonRes['FPS']; 55 | addTime = jsonRes['addTime']; 56 | bitRate = jsonRes['bitRate']; 57 | commentCount = jsonRes['commentCount']; 58 | id = jsonRes['id']; 59 | likes = jsonRes['likes']; 60 | readcount = jsonRes['readcount']; 61 | videoSize = jsonRes['videoSize']; 62 | enableComment = jsonRes['enableComment']; 63 | isFavorite = jsonRes['isFavorite']; 64 | isNoneImg = jsonRes['isNoneImg']; 65 | addTimeStr = jsonRes['addTimeStr']; 66 | author = jsonRes['author']; 67 | content = jsonRes['content']; 68 | description = jsonRes['description']; 69 | src = jsonRes['src']; 70 | timeLong = jsonRes['timeLong']; 71 | title = jsonRes['title']; 72 | videoSrc = jsonRes['videoSrc']; 73 | xcShareId = jsonRes['xcShareId']; 74 | xcSharePath = jsonRes['xcSharePath']; 75 | pictureList = jsonRes['pictureList'] == null ? null : []; 76 | 77 | for (var pictureListItem in pictureList == null ? [] : jsonRes['pictureList']){ 78 | pictureList.add(pictureListItem); 79 | } 80 | 81 | tagList = jsonRes['tagList'] == null ? null : []; 82 | 83 | for (var tagListItem in tagList == null ? [] : jsonRes['tagList']){ 84 | tagList.add(tagListItem); 85 | } 86 | } 87 | 88 | @override 89 | String toString() { 90 | return '{"FPS": $FPS,"addTime": $addTime,"bitRate": $bitRate,"commentCount": $commentCount,"id": $id,"likes": $likes,"readcount": $readcount,"videoSize": $videoSize,"enableComment": $enableComment,"isFavorite": $isFavorite,"isNoneImg": $isNoneImg,"addTimeStr": ${addTimeStr != null?'${json.encode(addTimeStr)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"content": ${content != null?'${json.encode(content)}':'null'},"description": ${description != null?'${json.encode(description)}':'null'},"src": ${src != null?'${json.encode(src)}':'null'},"timeLong": ${timeLong != null?'${json.encode(timeLong)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"videoSrc": ${videoSrc != null?'${json.encode(videoSrc)}':'null'},"xcShareId": ${xcShareId != null?'${json.encode(xcShareId)}':'null'},"xcSharePath": ${xcSharePath != null?'${json.encode(xcSharePath)}':'null'},"pictureList": $pictureList,"tagList": $tagList}'; 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/NewsResData.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class NewsResData { 4 | 5 | int result; 6 | String msg; 7 | NewsObject data; 8 | 9 | NewsResData.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory NewsResData(jsonStr) => jsonStr == null ? null : jsonStr is String ? new NewsResData.fromJson(json.decode(jsonStr)) : new NewsResData.fromJson(jsonStr); 12 | 13 | NewsResData.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : new NewsObject.fromJson(jsonRes['data']); 17 | } 18 | 19 | @override 20 | String toString() { 21 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 22 | } 23 | } 24 | 25 | class NewsObject { 26 | 27 | String search; 28 | Object toplist; 29 | int currentindex; 30 | int currentpage; 31 | int lasttime; 32 | int tag; 33 | List list; 34 | 35 | NewsObject.fromParams({this.search, this.toplist, this.currentindex, this.currentpage, this.lasttime, this.tag, this.list}); 36 | 37 | NewsObject.fromJson(jsonRes) { 38 | search = jsonRes['search']; 39 | toplist = jsonRes['toplist']; 40 | currentindex = jsonRes['currentindex']; 41 | currentpage = jsonRes['currentpage']; 42 | lasttime = jsonRes['lasttime']; 43 | tag = jsonRes['tag']; 44 | list = jsonRes['list'] == null ? null : []; 45 | 46 | for (var listItem in list == null ? [] : jsonRes['list']){ 47 | list.add(listItem == null ? null : new News.fromJson(listItem)); 48 | } 49 | } 50 | 51 | @override 52 | String toString() { 53 | return '{"search": ${search != null?'${json.encode(search)}':'null'},"toplist": $toplist,"currentindex": $currentindex,"currentpage": $currentpage,"lasttime": $lasttime,"tag": $tag,"list": $list}'; 54 | } 55 | } 56 | 57 | class News { 58 | 59 | int addTime; 60 | int commentCount; 61 | int flagId; 62 | int id; 63 | int likes; 64 | int pictureCount; 65 | int readcount; 66 | bool isBigIcon; 67 | bool isHot; 68 | bool isSpecial; 69 | bool isTop; 70 | String author; 71 | String description; 72 | String infoType; 73 | String redirectType; 74 | String src; 75 | String timeLong; 76 | String title; 77 | List pictureList; 78 | 79 | News.fromParams({this.addTime, this.commentCount, this.flagId, this.id, this.likes, this.pictureCount, this.readcount, this.isBigIcon, this.isHot, this.isSpecial, this.isTop, this.author, this.description, this.infoType, this.redirectType, this.src, this.timeLong, this.title, this.pictureList}); 80 | 81 | News.fromJson(jsonRes) { 82 | addTime = jsonRes['addTime']; 83 | commentCount = jsonRes['commentCount']; 84 | flagId = jsonRes['flagId']; 85 | id = jsonRes['id']; 86 | likes = jsonRes['likes']; 87 | pictureCount = jsonRes['pictureCount']; 88 | readcount = jsonRes['readcount']; 89 | isBigIcon = jsonRes['isBigIcon']; 90 | isHot = jsonRes['isHot']; 91 | isSpecial = jsonRes['isSpecial']; 92 | isTop = jsonRes['isTop']; 93 | author = jsonRes['author']; 94 | description = jsonRes['description']; 95 | infoType = jsonRes['infoType']; 96 | redirectType = jsonRes['redirectType']; 97 | src = jsonRes['src']; 98 | timeLong = jsonRes['timeLong']; 99 | title = jsonRes['title']; 100 | pictureList = jsonRes['pictureList'] == null ? null : []; 101 | 102 | for (var pictureListItem in pictureList == null ? [] : jsonRes['pictureList']){ 103 | pictureList.add(pictureListItem); 104 | } 105 | } 106 | 107 | @override 108 | String toString() { 109 | return '{"addTime": $addTime,"commentCount": $commentCount,"flagId": $flagId,"id": $id,"likes": $likes,"pictureCount": $pictureCount,"readcount": $readcount,"isBigIcon": $isBigIcon,"isHot": $isHot,"isSpecial": $isSpecial,"isTop": $isTop,"author": ${author != null?'${json.encode(author)}':'null'},"description": ${description != null?'${json.encode(description)}':'null'},"infoType": ${infoType != null?'${json.encode(infoType)}':'null'},"redirectType": ${redirectType != null?'${json.encode(redirectType)}':'null'},"src": ${src != null?'${json.encode(src)}':'null'},"timeLong": ${timeLong != null?'${json.encode(timeLong)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"pictureList": $pictureList}'; 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /flutter_demo/lib/bean/RelativeInfoResponse.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json; 2 | 3 | class RelativeInfoResponse { 4 | 5 | int result; 6 | String msg; 7 | List data; 8 | 9 | RelativeInfoResponse.fromParams({this.result, this.msg, this.data}); 10 | 11 | factory RelativeInfoResponse(jsonStr) => jsonStr == null ? null : jsonStr is String ? new RelativeInfoResponse.fromJson(json.decode(jsonStr)) : new RelativeInfoResponse.fromJson(jsonStr); 12 | 13 | RelativeInfoResponse.fromJson(jsonRes) { 14 | result = jsonRes['result']; 15 | msg = jsonRes['msg']; 16 | data = jsonRes['data'] == null ? null : []; 17 | 18 | for (var dataItem in data == null ? [] : jsonRes['data']){ 19 | data.add(dataItem == null ? null : new RelativeNews.fromJson(dataItem)); 20 | } 21 | } 22 | 23 | @override 24 | String toString() { 25 | return '{"result": $result,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}'; 26 | } 27 | } 28 | 29 | class RelativeNews { 30 | 31 | int addTime; 32 | int commentCount; 33 | int id; 34 | int likes; 35 | String author; 36 | String description; 37 | String infoType; 38 | String src; 39 | String timeLong; 40 | String title; 41 | List pictureList; 42 | List tagList; 43 | 44 | RelativeNews.fromParams({this.addTime, this.commentCount, this.id, this.likes, this.author, this.description, this.infoType, this.src, this.timeLong, this.title, this.pictureList, this.tagList}); 45 | 46 | RelativeNews.fromJson(jsonRes) { 47 | addTime = jsonRes['addTime']; 48 | commentCount = jsonRes['commentCount']; 49 | id = jsonRes['id']; 50 | likes = jsonRes['likes']; 51 | author = jsonRes['author']; 52 | description = jsonRes['description']; 53 | infoType = jsonRes['infoType']; 54 | src = jsonRes['src']; 55 | timeLong = jsonRes['timeLong']; 56 | title = jsonRes['title']; 57 | pictureList = jsonRes['pictureList'] == null ? null : []; 58 | 59 | for (var pictureListItem in pictureList == null ? [] : jsonRes['pictureList']){ 60 | pictureList.add(pictureListItem); 61 | } 62 | 63 | tagList = jsonRes['tagList'] == null ? null : []; 64 | 65 | for (var tagListItem in tagList == null ? [] : jsonRes['tagList']){ 66 | tagList.add(tagListItem); 67 | } 68 | } 69 | 70 | @override 71 | String toString() { 72 | return '{"addTime": $addTime,"commentCount": $commentCount,"id": $id,"likes": $likes,"author": ${author != null?'${json.encode(author)}':'null'},"description": ${description != null?'${json.encode(description)}':'null'},"infoType": ${infoType != null?'${json.encode(infoType)}':'null'},"src": ${src != null?'${json.encode(src)}':'null'},"timeLong": ${timeLong != null?'${json.encode(timeLong)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"pictureList": $pictureList,"tagList": $tagList}'; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /flutter_demo/lib/channelView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_demo/NewsDetailPageView.dart'; 3 | import 'package:flutter_demo/view/NewDetailWebview.dart'; 4 | import 'bean/ChannelResponse.dart'; 5 | import 'bean/NewsResData.dart'; 6 | import 'controller/HttpController.dart'; 7 | import 'news_detail_page.dart'; 8 | import 'videoListPage.dart'; 9 | 10 | class NewsListView extends StatefulWidget{ 11 | final String mChannelCode; 12 | final String mSearchText; 13 | NewsListView({this.mChannelCode,this.mSearchText}); 14 | 15 | @override 16 | State createState() { 17 | // TODO: implement createState 18 | return new NewsListViewState(); 19 | } 20 | 21 | } 22 | 23 | class NewsListViewState extends State with AutomaticKeepAliveClientMixin{ 24 | 25 | HttpController mHttpController; 26 | NewsResData mNewsResData; 27 | List mNewsList = []; 28 | Map newsDataMap=new Map(); 29 | ScrollController _scrollController=new ScrollController(); 30 | bool isLoadMore=false;//是否正在加载更多数据 31 | bool isFirstLoadData=true; //是否是第一次加载数据 32 | 33 | @override 34 | void initState() { 35 | // TODO: implement initState 36 | super.initState(); 37 | assert(widget.mChannelCode!=null); 38 | mHttpController=new HttpController(); 39 | getData(widget.mChannelCode,widget.mSearchText,2,0); 40 | _scrollController.addListener((){ 41 | if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){ 42 | if(!isLoadMore && mNewsList.length>1){ 43 | setState(() { 44 | isLoadMore=true; 45 | }); 46 | getData(widget.mChannelCode,widget.mSearchText,mNewsResData.data.currentpage,mNewsResData.data.currentindex); 47 | } 48 | 49 | } 50 | }); 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | // TODO: implement build 56 | return layout(context); 57 | } 58 | 59 | Widget layout(BuildContext context){ 60 | if(isFirstLoadData){ 61 | return Center( 62 | child: CircularProgressIndicator( 63 | backgroundColor: Colors.blue, 64 | strokeWidth: 4, 65 | ) 66 | ); 67 | }else{ 68 | return Container( 69 | child: RefreshIndicator( 70 | child: ListView.builder(itemCount:mNewsList.length,itemBuilder: itemView,controller: _scrollController,padding: EdgeInsets.only(top: 0.0), ), 71 | onRefresh: _onRefresh), 72 | ); 73 | } 74 | } 75 | 76 | 77 | Future _onRefresh() async{ 78 | if(mNewsResData!=null){ 79 | await getData(widget.mChannelCode,widget.mSearchText,mNewsResData.data.currentpage,mNewsResData.data.currentindex); 80 | } 81 | } 82 | 83 | void getData(String tag,String searchText,int page,int currentIndex) async{ 84 | Map dataMap = new Map(); 85 | dataMap["tag"]=tag; 86 | dataMap["search"]=searchText; 87 | dataMap["page"]=page.toString(); 88 | dataMap["currentindex"]=currentIndex.toString(); 89 | await mHttpController.getNewsList("https://app.tenyou0574.com/App/Info/InfoList",(data){ 90 | if(data!=null){ 91 | setState(() { 92 | isLoadMore=false; 93 | isFirstLoadData=false; 94 | mNewsResData=data; 95 | mNewsList.addAll(mNewsResData.data.list); 96 | for(News news in mNewsResData.data.list){ 97 | newsDataMap[news.id]=news; 98 | } 99 | }); 100 | } 101 | },params: dataMap); 102 | } 103 | 104 | Route _getRoute(RouteSettings settings) { 105 | // Routes, by convention, are split on slashes, like filesystem paths. 106 | final List path = settings.name.split('/'); 107 | if (path[0] != '') 108 | return null; 109 | if (path[1].startsWith('newsDetail:')) { 110 | if (path.length != 3) 111 | return null; 112 | final String infoId = path[1].substring(11); 113 | final String index = path[2]; 114 | return MaterialPageRoute( 115 | settings: settings, 116 | builder: (BuildContext context) => NewsDetailPage(mNews:mNewsList[int.parse(index)]), 117 | ); 118 | } 119 | // The other paths we support are in the routes table. 120 | return null; 121 | } 122 | 123 | 124 | Widget itemView(BuildContext context,int index){ 125 | News news=this.mNewsList[index]; 126 | 127 | if(news.pictureList==null){ 128 | return Expanded(child: Text(news.title)); 129 | } 130 | 131 | if(news.pictureList.length>=1 && news.pictureList.length<3){ 132 | return InkWell( 133 | onTap: (){ 134 | // Navigator.pushNamed(context, '/newsDetail:${news.id}/${index}'); 135 | Navigator.push( 136 | context, 137 | MaterialPageRoute(builder: (context){ 138 | if(news.infoType=="Article"){ 139 | return NewsDetailPage(mNews:mNewsList[index]); 140 | // return NewsDetailPageView(mNews:mNewsList[index]); 141 | }else{ 142 | return VideoListPage(mNews:mNewsList[index]); 143 | } 144 | }) 145 | ); 146 | }, 147 | child: Column( 148 | crossAxisAlignment: CrossAxisAlignment.start, 149 | children: [ 150 | Container( 151 | padding: EdgeInsets.all(10.0), 152 | child: Text(news.title,style: TextStyle( 153 | fontSize: 16.0 154 | ),), 155 | ), 156 | Row( 157 | mainAxisAlignment: MainAxisAlignment.start, 158 | children: [ 159 | Expanded( 160 | child: Container( 161 | padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), 162 | child: Image.network(news.pictureList[0],height: 199.0,fit: BoxFit.cover,) , 163 | ), 164 | ), 165 | ], 166 | ), 167 | Container( 168 | margin: EdgeInsets.only(top: 8.0), 169 | child: Divider(height: 2.0,), 170 | ), 171 | 172 | ], 173 | ), 174 | ); 175 | } 176 | 177 | if(news.pictureList.length>=3){ 178 | return InkWell( 179 | onTap: (){ 180 | // Navigator.pushNamed(context, '/newsDetail:${news.id}/${index}'); 181 | Navigator.push( 182 | context, 183 | MaterialPageRoute(builder: (context){ 184 | if(news.infoType=="Article"){ 185 | return NewsDetailPage(mNews:mNewsList[index]); 186 | // return NewsDetailPageView(mNews:mNewsList[index]); 187 | }else{ 188 | return VideoListPage(mNews:mNewsList[index]); 189 | } 190 | }) 191 | ); 192 | }, 193 | child: Column( 194 | crossAxisAlignment: CrossAxisAlignment.start, 195 | children: [ 196 | Container( 197 | padding: EdgeInsets.all(10.0), 198 | child: Text(news.title,style: TextStyle( 199 | fontSize: 16.0, 200 | ),), 201 | ), 202 | Container( 203 | padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), 204 | child: Row( 205 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 206 | children: [ 207 | Expanded( 208 | flex: 1, 209 | child: Container( 210 | margin: EdgeInsets.only(right: 5.0), 211 | child: Image.network(news.pictureList[0],height: 78.0,fit: BoxFit.cover,) , 212 | ) 213 | ), 214 | Expanded( 215 | flex: 1, 216 | child: Container( 217 | margin: EdgeInsets.only(right: 5.0), 218 | child: Image.network(news.pictureList[1],height: 78.0,fit: BoxFit.cover,) , 219 | ) 220 | ), 221 | Expanded( 222 | flex: 1, 223 | child: Image.network(news.pictureList[2],height: 78.0,fit: BoxFit.cover,) , 224 | ), 225 | ], 226 | ) 227 | ), 228 | Container( 229 | margin: EdgeInsets.only(top: 8.0), 230 | child: Divider(height: 2.0,), 231 | ), 232 | ], 233 | ), 234 | ); 235 | } 236 | } 237 | 238 | @override 239 | void dispose() { 240 | // TODO: implement dispose 241 | super.dispose(); 242 | _scrollController.dispose(); 243 | } 244 | 245 | @override 246 | // TODO: implement wantKeepAlive 247 | bool get wantKeepAlive => true; 248 | } -------------------------------------------------------------------------------- /flutter_demo/lib/controller/HttpController.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter_demo/bean/HotSearchResponse.dart'; 3 | import 'dart:async'; 4 | import 'package:flutter_demo/bean/NewsResData.dart'; 5 | import 'package:flutter_demo/bean/ChannelResponse.dart'; 6 | import 'package:flutter_demo/bean/RelativeInfoResponse.dart'; 7 | import 'package:flutter_demo/bean/BannerInfoResponse.dart'; 8 | import 'package:flutter_demo/bean/FictionHomeInfoResponse.dart'; 9 | import 'package:flutter_demo/bean/NewsDetailResponse.dart'; 10 | import 'package:flutter_demo/bean/FictionDetailResponse.dart'; 11 | 12 | class HttpController{ 13 | Dio dio; 14 | HttpController(){ 15 | dio=new Dio(); 16 | } 17 | void getNewsList(String url,Function callBack,{Map params,Function errorCallback}){ 18 | dio.get(url,data: params).then((Response response){ 19 | print(response.data.toString()); 20 | NewsResData newsResData=new NewsResData.fromJson(response.data); 21 | if(newsResData.result==200){ 22 | callBack(newsResData); 23 | print("数据大小="+newsResData.data.list.length.toString()); 24 | } 25 | }); 26 | } 27 | 28 | //获取channel频道 29 | void getChannelList(Function callBack,{Function errorCallBack}){ 30 | dio.get("https://app.tenyou0574.com/App/Info/GetDefaultTags").then((Response response){ 31 | try { 32 | ChannelResponse channelResponse=new ChannelResponse.fromJson(response.data); 33 | if(channelResponse.result==200){ 34 | callBack(channelResponse.data); 35 | }else{ 36 | errorCallBack(channelResponse.msg); 37 | } 38 | } catch (e) { 39 | errorCallBack(e.toString()); 40 | } 41 | }); 42 | } 43 | 44 | void getRelativeInfo(int infoId,Function callBack,{Function errorCallBack}) { 45 | Map dataMap=new Map(); 46 | dataMap["id"]=infoId.toString(); 47 | dio.get("https://app.tenyou0574.com/App/Info/GetRelationInfo",data: dataMap).then((Response response){ 48 | RelativeInfoResponse relativeInfoResponse=new RelativeInfoResponse.fromJson(response.data); 49 | if(relativeInfoResponse.result==200){ 50 | RelativeNews relativeNews=new RelativeNews.fromParams(infoType: "videoTitle"); 51 | relativeInfoResponse.data.insert(0, relativeNews); 52 | callBack(relativeInfoResponse); 53 | }else{ 54 | errorCallBack(relativeInfoResponse.msg); 55 | } 56 | }); 57 | } 58 | 59 | void getNewsDetail(int infoId,Function callBack,{Function errorCallBack}){ 60 | Map dataMap=new Map(); 61 | dataMap["id"]=infoId.toString(); 62 | dio.get("https://app.tenyou0574.com/App/Info/GetDetailInfo",data: dataMap).then((Response response){ 63 | NewsDetailResponse newsDetailResponse=new NewsDetailResponse.fromJson(response.data); 64 | if(newsDetailResponse.result==200){ 65 | callBack(newsDetailResponse.data); 66 | print("NewsDetailResponse="+newsDetailResponse.toString()); 67 | }else{ 68 | errorCallBack(newsDetailResponse.msg); 69 | } 70 | }); 71 | } 72 | 73 | Future> getBannerInfo(String type,{Function errorCallBack}) async{ 74 | Map dataMap=new Map(); 75 | dataMap["type"]=type; 76 | /*await dio.get("https://app.tenyou0574.com/App/Common/GetBannerInfo",data: dataMap).then((Response response){ 77 | BannerInfoResponse bannerInfoResponse=new BannerInfoResponse.fromJson(response.data); 78 | return bannerInfoResponse.data; 79 | });*/ 80 | Response response=await dio.get("https://app.tenyou0574.com/App/Common/GetBannerInfo",data: dataMap); 81 | BannerInfoResponse bannerInfoResponse=new BannerInfoResponse.fromJson(response.data); 82 | return bannerInfoResponse.data; 83 | } 84 | 85 | //获取小说首页内容 86 | Future getFictionHomePageInfo () async{ 87 | Response response=await dio.get("https://app.tenyou0574.com/App/Book/HomePageBook"); 88 | FictionHomeInfoResponse fictionHomeInfoResponse=new FictionHomeInfoResponse.fromJson(response.data); 89 | return fictionHomeInfoResponse; 90 | } 91 | 92 | void getReplaceFiction(String type,Function callBack,{Function errorCallBack}) { 93 | Map dataMap=new Map(); 94 | dataMap["type"]=type; 95 | dio.get("https://app.tenyou0574.com/App/Book/GetOtherPush",data: dataMap).then((Response response){ 96 | HotPushResponse replacePushResponse=new HotPushResponse.fromJson(response.data); 97 | if(replacePushResponse.result==200){ 98 | callBack(replacePushResponse); 99 | }else{ 100 | errorCallBack(replacePushResponse.msg); 101 | } 102 | }); 103 | } 104 | 105 | Future getFictionDetail(int fictionId) async{ 106 | Map dataMap=new Map(); 107 | dataMap["bookid"]=fictionId.toString(); 108 | Response response=await dio.get("https://app.tenyou0574.com/App/Book/GetBookDetail",data: dataMap); 109 | FictionDetailResponse fictionDetailResponse =FictionDetailResponse.fromJson(response.data); 110 | return fictionDetailResponse; 111 | } 112 | 113 | //获取所搜热词 114 | Future getHotSearchKeyWord () async{ 115 | Response response=await dio.get("https://app.tenyou0574.com/App/Info/GetHotSearchKeyWord"); 116 | HotSearchResponse hotSearchResponse=new HotSearchResponse.fromJson(response.data); 117 | /* HotSearchBean hotSearchBean=HotSearchBean.fromParams(code: -1,name: "热门搜索"); 118 | hotSearchResponse.data.insert(0, hotSearchBean);*/ 119 | return hotSearchResponse; 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /flutter_demo/lib/fiction/mainFiction.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_swiper/flutter_swiper.dart'; 3 | import 'package:flutter_demo/controller/HttpController.dart'; 4 | import 'package:flutter_demo/bean/BannerInfoResponse.dart'; 5 | import 'package:flutter_demo/bean/FictionHomeInfoResponse.dart'; 6 | import 'package:flutter_demo/FictionManFeatured.dart'; 7 | import 'package:flutter_demo/FictionDetailPage.dart'; 8 | 9 | class mainFiction extends StatefulWidget{ 10 | 11 | @override 12 | State createState() { 13 | // TODO: implement createState 14 | return new mainFictionState(); 15 | } 16 | } 17 | 18 | class mainFictionState extends State with AutomaticKeepAliveClientMixin{ 19 | HttpController mHttpController; 20 | 21 | @override 22 | void initState() { 23 | // TODO: implement initState 24 | super.initState(); 25 | mHttpController=new HttpController(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | // TODO: implement build 31 | return Theme( 32 | data: ThemeData( 33 | primaryColor: Colors.white 34 | ), 35 | child: Scaffold( 36 | appBar: AppBar( 37 | leading: Container( 38 | padding: EdgeInsets.only(left: 10.0), 39 | child: ClipOval( 40 | child: Image.asset('images/fiction_header_icon.png'), 41 | ) 42 | ), 43 | title: DecoratedBox( 44 | decoration: BoxDecoration( 45 | color: Color.fromARGB(150, 235, 235, 235), 46 | borderRadius: BorderRadius.circular(20.0), 47 | border: Border.all(color: Color(0xFFC90E),width: 1.0) 48 | ), 49 | child: Row( 50 | mainAxisSize: MainAxisSize.min, 51 | mainAxisAlignment: MainAxisAlignment.start, 52 | crossAxisAlignment: CrossAxisAlignment.center, 53 | children: [ 54 | Padding( 55 | padding: EdgeInsets.only(left: 10.0), 56 | child: Image.asset('images/icon_function_search.png',width: 14.0,height: 14.0,), 57 | ), 58 | Padding( 59 | padding: EdgeInsets.fromLTRB(10.0, 5.0, 100.0, 5.0), 60 | child: Text('搜索书名或者作者名',style: TextStyle(fontSize: 14.0,color: Colors.black),), 61 | ) 62 | ], 63 | ), 64 | ), 65 | ), 66 | 67 | body: ListView( 68 | children: [ 69 | getHeadView(), 70 | FutureBuilder( 71 | future: mHttpController.getFictionHomePageInfo(), 72 | builder: (BuildContext context, AsyncSnapshot snapshot){ 73 | switch (snapshot.connectionState) { 74 | case ConnectionState.waiting: 75 | return Center( 76 | child: CircularProgressIndicator(), 77 | ); 78 | case ConnectionState.done: 79 | if (snapshot.hasError) return Text('Error: ${snapshot.error}'); 80 | return getFictionHomeContent(snapshot.data); 81 | default: 82 | return null; 83 | } 84 | } 85 | ), 86 | ], 87 | ) 88 | ), 89 | ); 90 | } 91 | 92 | Widget getHeadView(){ 93 | return Column( 94 | crossAxisAlignment: CrossAxisAlignment.start, 95 | children: [ 96 | Container( 97 | width: MediaQuery.of(context).size.width, 98 | height: 142.0, 99 | child: FutureBuilder>( 100 | future: mHttpController.getBannerInfo('BookTop'), 101 | builder: _buildFuture 102 | ), 103 | ), 104 | Padding( 105 | padding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), 106 | child: Row( 107 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 108 | crossAxisAlignment: CrossAxisAlignment.center, 109 | children: [ 110 | Column( 111 | mainAxisSize: MainAxisSize.min, 112 | crossAxisAlignment: CrossAxisAlignment.center, 113 | children: [ 114 | Image.asset('images/fiction_1.png',width: 42.0,height: 42.0,), 115 | Padding( 116 | padding: EdgeInsets.only(top: 3.0), 117 | child: Text('书架',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 118 | ) 119 | ], 120 | ), 121 | Column( 122 | mainAxisSize: MainAxisSize.min, 123 | crossAxisAlignment: CrossAxisAlignment.center, 124 | children: [ 125 | Image.asset('images/fiction_2.png',width: 42.0,height: 42.0,), 126 | Padding( 127 | padding: EdgeInsets.only(top: 3.0), 128 | child: Text('排行',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 129 | ) 130 | ], 131 | ), 132 | Column( 133 | mainAxisSize: MainAxisSize.min, 134 | crossAxisAlignment: CrossAxisAlignment.center, 135 | children: [ 136 | Image.asset('images/fiction_3.png',width: 42.0,height: 42.0,), 137 | Padding( 138 | padding: EdgeInsets.only(top: 3.0), 139 | child: Text('专题',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 140 | ) 141 | ], 142 | ), 143 | Column( 144 | mainAxisSize: MainAxisSize.min, 145 | crossAxisAlignment: CrossAxisAlignment.center, 146 | children: [ 147 | Image.asset('images/fiction_4.png',width: 42.0,height: 42.0,), 148 | Padding( 149 | padding: EdgeInsets.only(top: 3.0), 150 | child: Text('书库',style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),), 151 | ) 152 | ], 153 | ), 154 | ], 155 | ), 156 | ), 157 | Container( 158 | height: 15.0, 159 | color: Color.fromARGB(150, 235, 235, 235), 160 | ) 161 | 162 | ], 163 | ); 164 | } 165 | 166 | ///snapshot就是_calculation在时间轴上执行过程的状态快照 167 | Widget _buildFuture(BuildContext context, AsyncSnapshot snapshot) { 168 | switch (snapshot.connectionState) { 169 | case ConnectionState.none: 170 | print('还没有开始网络请求'); 171 | return Text('还没有开始网络请求'); 172 | case ConnectionState.active: 173 | print('active'); 174 | return Text('ConnectionState.active'); 175 | case ConnectionState.waiting: 176 | print('waiting'); 177 | return Center( 178 | child: CircularProgressIndicator(), 179 | ); 180 | case ConnectionState.done: 181 | print('done'); 182 | if (snapshot.hasError) return Text('Error: ${snapshot.error}'); 183 | return getBannerView(snapshot.data); 184 | default: 185 | return null; 186 | } 187 | } 188 | 189 | Widget getBannerView(List banners){ 190 | return Swiper( 191 | itemCount: banners.length, 192 | itemBuilder: (context,index){ 193 | return Image.network(banners[index].pictureUrl,fit:BoxFit.fill); 194 | }, 195 | pagination: new SwiperPagination( 196 | builder: DotSwiperPaginationBuilder( 197 | color: Colors.black54, 198 | activeColor: Colors.white, 199 | )), 200 | control: new SwiperControl(), 201 | scrollDirection: Axis.horizontal, 202 | autoplay: true, 203 | onTap: (index) => print('点击了第$index个'), 204 | ); 205 | } 206 | 207 | Widget getFictionHomeContent(FictionHomeInfoResponse response){ 208 | List hotPushLists=response.hotPush.data; 209 | List editPushLists=response.editerPush.data; 210 | List manLists=response.other[0].data; 211 | List girlLists=response.other[1].data; 212 | return Container( 213 | padding: EdgeInsets.all(10.0), 214 | child: Column( 215 | crossAxisAlignment: CrossAxisAlignment.start, 216 | children: [ 217 | getHotPushWidgets(hotPushLists), 218 | getEditPushWidgets(editPushLists), 219 | FictionManFeatured(manLists:manLists,isMan: true,), 220 | FictionManFeatured(manLists:girlLists,isMan: false,), 221 | ], 222 | ), 223 | ); 224 | } 225 | 226 | //获取热门推荐 227 | Widget getHotPushWidgets(List hotPushLists){ 228 | return Column( 229 | crossAxisAlignment: CrossAxisAlignment.start, 230 | children: [ 231 | Text('热门精选',style: TextStyle(fontSize: 16.0,color: Colors.black,fontWeight: FontWeight.bold),), 232 | getFictionDetailStyle(hotPushLists[0]), 233 | Container( 234 | padding: EdgeInsets.only(top: 10.0), 235 | child: Row( 236 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 237 | children: hotPushLists.sublist(1,4).map((FictionIntroduction fictionIntroduction){ 238 | return getFictionNormalStyle(fictionIntroduction); 239 | }).toList(), 240 | ), 241 | ), 242 | Container( 243 | margin: EdgeInsets.only(top: 10.0), 244 | height: 15.0, 245 | color: Color.fromARGB(150, 235, 235, 235), 246 | ) 247 | 248 | ], 249 | ); 250 | } 251 | 252 | //获取主编力推 253 | Widget getEditPushWidgets(List editPushLists){ 254 | return Column( 255 | crossAxisAlignment: CrossAxisAlignment.start, 256 | children: [ 257 | Container( 258 | padding: EdgeInsets.only(top: 10.0), 259 | child: Text('主编力推',style: TextStyle(fontSize: 16.0,color: Colors.black,fontWeight: FontWeight.bold),), 260 | ), 261 | Column( 262 | crossAxisAlignment: CrossAxisAlignment.start, 263 | children: editPushLists.map((FictionIntroduction fictionIntroduction){ 264 | return getFictionDetailStyle(fictionIntroduction); 265 | }).toList(), 266 | ), 267 | Container( 268 | margin: EdgeInsets.only(top: 10.0), 269 | height: 15.0, 270 | color: Color.fromARGB(150, 235, 235, 235), 271 | ) 272 | ], 273 | ); 274 | } 275 | 276 | Widget getFictionDetailStyle(FictionIntroduction fictionIntroduction){ 277 | return InkWell( 278 | onTap: (){ 279 | Navigator.push(context, 280 | MaterialPageRoute(builder: (context){ 281 | return FictionDetailPage(fictionId : fictionIntroduction.bookId); 282 | // return ImagePickerPage(); 283 | // return ScannerPage(); 284 | })); 285 | }, 286 | child: Container( 287 | padding: EdgeInsets.only(top: 10.0), 288 | child: Row( 289 | mainAxisAlignment: MainAxisAlignment.start, 290 | crossAxisAlignment: CrossAxisAlignment.center, 291 | children: [ 292 | Image.network(fictionIntroduction.picture,width: 90.0,height: 120.0,), 293 | Expanded( 294 | child: Container( 295 | padding: EdgeInsets.only(left: 10.0), 296 | child: Column( 297 | mainAxisSize: MainAxisSize.min, 298 | mainAxisAlignment: MainAxisAlignment.start, 299 | crossAxisAlignment: CrossAxisAlignment.start, 300 | children: [ 301 | Text(fictionIntroduction.name,style: TextStyle(fontSize: 16.0,color: Colors.black,fontWeight: FontWeight.w500),), 302 | Container( 303 | padding: EdgeInsets.only(top: 15.0,bottom: 15.0), 304 | child: Text(fictionIntroduction.description,style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),maxLines: 2,overflow: TextOverflow.ellipsis,), 305 | ), 306 | 307 | Row( 308 | mainAxisSize: MainAxisSize.min, 309 | mainAxisAlignment: MainAxisAlignment.start, 310 | children: [ 311 | Image.asset('images/fiction_author.png',width: 18.0,height: 18.0,), 312 | Container( 313 | padding: EdgeInsets.only(left: 10.0), 314 | child: Text(fictionIntroduction.author,style: TextStyle(fontSize: 14.0,color: Color(0xFF999999))), 315 | ) 316 | ], 317 | ) 318 | ], 319 | ), 320 | ) 321 | ), 322 | 323 | ], 324 | ), 325 | ), 326 | ); 327 | } 328 | 329 | Widget getFictionNormalStyle(FictionIntroduction fictionIntroduction){ 330 | return InkWell( 331 | onTap: (){ 332 | Navigator.push(context, 333 | MaterialPageRoute(builder: (context){ 334 | return FictionDetailPage(fictionId : fictionIntroduction.bookId); 335 | })); 336 | }, 337 | child: Column( 338 | mainAxisSize: MainAxisSize.min, 339 | mainAxisAlignment: MainAxisAlignment.start, 340 | crossAxisAlignment: CrossAxisAlignment.start, 341 | children: [ 342 | Image.network(fictionIntroduction.picture,width: 90.0,height: 120.0,), 343 | Container( 344 | width: 90.0, 345 | margin: EdgeInsets.only(top: 5.0,bottom: 3.0), 346 | child: Text(fictionIntroduction.name,style: TextStyle(fontSize: 14.0,color: Color(0xFF333333)),softWrap: false,overflow: TextOverflow.ellipsis,), 347 | ), 348 | Container( 349 | width: 90.0, 350 | child: Text(fictionIntroduction.author,style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)),softWrap: false,overflow: TextOverflow.ellipsis,), 351 | ), 352 | ], 353 | ), 354 | ); 355 | } 356 | 357 | @override 358 | // TODO: implement wantKeepAlive 359 | bool get wantKeepAlive => true; 360 | 361 | } -------------------------------------------------------------------------------- /flutter_demo/lib/homePage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_demo/SearchPage.dart'; 3 | import 'controller/HttpController.dart'; 4 | import 'bean/ChannelResponse.dart'; 5 | import 'channelView.dart'; 6 | 7 | class HomePage extends StatefulWidget{ 8 | @override 9 | State createState() { 10 | // TODO: implement createState 11 | return new HomePageState(); 12 | } 13 | } 14 | 15 | class HomePageState extends State with AutomaticKeepAliveClientMixin{ 16 | 17 | HttpController mHttpController; 18 | bool isLoadChannel=true;//是否在加载channel 19 | 20 | List channels=[]; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | // TODO: implement build 25 | return layout(context); 26 | /* return MaterialApp( 27 | routes: { 28 | '/': (BuildContext context) => layout(context), 29 | }, 30 | );*/ 31 | } 32 | 33 | @override 34 | void initState() { 35 | // TODO: implement initState 36 | super.initState(); 37 | mHttpController=new HttpController(); 38 | getChannel(); 39 | } 40 | 41 | void getChannel() async{ 42 | await mHttpController.getChannelList((data){ 43 | if(data!=null){ 44 | setState(() { 45 | isLoadChannel=false; 46 | channels.addAll(data); 47 | print("channel data="+channels.toString()); 48 | }); 49 | } 50 | }); 51 | } 52 | 53 | 54 | Widget layout(BuildContext context){ 55 | 56 | if(isLoadChannel){ 57 | return Theme( 58 | data: ThemeData( 59 | primaryColor: Colors.white 60 | ), 61 | child: Scaffold( 62 | appBar: AppBar( 63 | leading: Container( 64 | padding: EdgeInsets.only(left: 5.0), 65 | child: Image.asset('images/icon_logo.png',width: 63.0,height: 15.0,), 66 | ), 67 | title:DecoratedBox( 68 | decoration: BoxDecoration( 69 | color: Color.fromARGB(150, 245, 245, 245), 70 | borderRadius: BorderRadius.circular(20.0), 71 | border: Border.all(color: Color(0xFFC90E),width: 1.0) 72 | ), 73 | child: Row( 74 | mainAxisSize: MainAxisSize.min, 75 | mainAxisAlignment: MainAxisAlignment.start, 76 | crossAxisAlignment: CrossAxisAlignment.center, 77 | children: [ 78 | Padding( 79 | padding: EdgeInsets.only(left: 10.0), 80 | child: Image.asset('images/icon_function_search.png',width: 14.0,height: 14.0,), 81 | ), 82 | Padding( 83 | padding: EdgeInsets.fromLTRB(10.0, 5.0, 80.0, 5.0), 84 | child: Text('搜索你感兴趣的内容',style: TextStyle(fontSize: 14.0,color: Colors.black),), 85 | ), 86 | ], 87 | ), 88 | ), 89 | ), 90 | body: Center( 91 | child: CircularProgressIndicator( 92 | backgroundColor: Colors.blue, 93 | strokeWidth: 4, 94 | ) 95 | ), 96 | ) 97 | ); 98 | } 99 | 100 | return Theme( 101 | data: ThemeData( 102 | primaryColor: Colors.white 103 | ), 104 | child: DefaultTabController( 105 | length: channels.length, 106 | child: Scaffold( 107 | appBar: AppBar( 108 | leading: Container( 109 | padding: EdgeInsets.only(left: 5.0), 110 | child: Image.asset('images/icon_logo.png',width: 63.0,height: 15.0,), 111 | ), 112 | title: DecoratedBox( 113 | decoration: BoxDecoration( 114 | color: Color.fromARGB(150, 245, 245, 245), 115 | borderRadius: BorderRadius.circular(20.0), 116 | // border: Border.all(color: Color(0xFFFFC90E),width: 1.0) 117 | ), 118 | child: InkWell( 119 | onTap: (){ 120 | Navigator.push( 121 | context, 122 | MaterialPageRoute(builder: (context){ 123 | return SearchPage(); 124 | }) 125 | ); 126 | 127 | }, 128 | 129 | child: Row( 130 | mainAxisSize: MainAxisSize.min, 131 | mainAxisAlignment: MainAxisAlignment.start, 132 | crossAxisAlignment: CrossAxisAlignment.center, 133 | children: [ 134 | Padding( 135 | padding: EdgeInsets.only(left: 10.0), 136 | child: Image.asset('images/icon_function_search.png',width: 14.0,height: 14.0,), 137 | ), 138 | Padding( 139 | padding: EdgeInsets.fromLTRB(10.0, 5.0, 80.0, 5.0), 140 | child: Text('搜索你感兴趣的内容',style: TextStyle(fontSize: 14.0,color: Colors.black),), 141 | ), 142 | ], 143 | ), 144 | ), 145 | ), 146 | bottom: TabBar( 147 | isScrollable: true, 148 | indicatorColor: Color(0xFFFFB40C), 149 | labelColor: Colors.black, 150 | labelStyle: TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold), 151 | unselectedLabelColor: Color(0xFF666666), 152 | unselectedLabelStyle: TextStyle(fontSize: 14.0), 153 | tabs: channels.map((Channel channel){ 154 | return Tab( 155 | text: channel.name, 156 | ); 157 | }).toList(), 158 | ), 159 | ), 160 | body: TabBarView( 161 | children: channels.map((Channel channel){ 162 | return Container( 163 | /*child: RefreshIndicator( 164 | child: ListView.builder(itemCount:mNewsList.length,itemBuilder: itemView,controller: _scrollController, ), 165 | onRefresh: _onRefresh),*/ 166 | child: _buildChannelTab(context,channel), 167 | ); 168 | }).toList(), 169 | ), 170 | ), 171 | ) 172 | ); 173 | } 174 | 175 | Widget _buildChannelTab(BuildContext context,Channel channel){ 176 | return NewsListView(mChannelCode: channel.code.toString(),mSearchText: "",); 177 | } 178 | 179 | @override 180 | // TODO: implement wantKeepAlive 181 | bool get wantKeepAlive => true; 182 | 183 | 184 | } -------------------------------------------------------------------------------- /flutter_demo/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:english_words/english_words.dart'; 3 | import 'package:flutter_demo/utils/SpUtil.dart'; 4 | import 'homePage.dart'; 5 | import 'PersonalPage.dart'; 6 | import 'fiction/mainFiction.dart'; 7 | 8 | void main() => runApp(AppHome()); 9 | 10 | class AppHome extends StatelessWidget{ 11 | @override 12 | Widget build(BuildContext context) { 13 | // TODO: implement build 14 | return MaterialApp( 15 | home: MainPage() 16 | ); 17 | } 18 | } 19 | 20 | 21 | class MainPage extends StatefulWidget{ 22 | @override 23 | State createState() { 24 | // TODO: implement createState 25 | return new MainPageState(); 26 | } 27 | } 28 | 29 | class MainPageState extends State{ 30 | int _tabIndex = 0; 31 | var _pageList; 32 | var tabImages; 33 | var appBarTitles= ['新闻','小说','中心']; 34 | 35 | var _pageController = new PageController(initialPage: 0); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | _initData(); 40 | return Scaffold( 41 | body: PageView( 42 | scrollDirection: Axis.horizontal, 43 | physics: NeverScrollableScrollPhysics(), 44 | controller: _pageController, 45 | children: _pageList, 46 | ), 47 | bottomNavigationBar: BottomNavigationBar( 48 | items: [ 49 | BottomNavigationBarItem( 50 | icon: getTabIcon(0), 51 | title: getTabTitle(0) 52 | ), 53 | BottomNavigationBarItem( 54 | icon: getTabIcon(1), 55 | title: getTabTitle(1) 56 | ), 57 | BottomNavigationBarItem( 58 | icon: getTabIcon(2), 59 | title: getTabTitle(2) 60 | ), 61 | ], 62 | type: BottomNavigationBarType.fixed, 63 | currentIndex: _tabIndex, 64 | iconSize: 24.0, 65 | onTap: (index){ 66 | if(index==_tabIndex) 67 | return; 68 | 69 | setState(() { 70 | _tabIndex=index; 71 | }); 72 | 73 | _pageController.jumpToPage(index); 74 | }, 75 | ), 76 | ); 77 | } 78 | 79 | @override 80 | void initState() { 81 | // TODO: implement initState 82 | super.initState(); 83 | _initAsync(); 84 | } 85 | 86 | 87 | //初始化sp 88 | void _initAsync() async { 89 | await SpUtil.getInstance(); 90 | } 91 | 92 | void _initData(){ 93 | _pageList = [ 94 | new HomePage(), 95 | new mainFiction(), 96 | new PersonalPage(), 97 | ]; 98 | 99 | tabImages=[ 100 | [getTabImage('images/icon_main_tab_news_normal.png'),getTabImage('images/icon_main_tab_news_selected.png')], 101 | [getTabImage('images/icon_main_tab_micro_normal.png'),getTabImage('images/icon_main_tab_micro_select.png')], 102 | [getTabImage('images/icon_main_tab_person_normal.png'),getTabImage('images/icon_main_tab_person_selected.png')], 103 | 104 | ]; 105 | } 106 | 107 | Image getTabImage(path) { 108 | return new Image.asset(path, width: 24.0, height: 24.0,fit: BoxFit.contain,); 109 | } 110 | 111 | Image getTabIcon(int index){ 112 | if(index==_tabIndex){ 113 | return tabImages[index][1]; 114 | }else{ 115 | return tabImages[index][0]; 116 | } 117 | } 118 | 119 | //获取tab的文字 120 | Text getTabTitle(int index){ 121 | if(index == _tabIndex){ 122 | return Text( 123 | appBarTitles[index], 124 | style: TextStyle(fontSize: 14.0,color: Color(0xFFFFCA12)), 125 | ); 126 | }else{ 127 | return Text( 128 | appBarTitles[index], 129 | style: TextStyle(fontSize: 14.0,color: Color(0xFF999999)), 130 | ); 131 | } 132 | } 133 | 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /flutter_demo/lib/news_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'bean/NewsResData.dart'; 5 | import 'package:webview_flutter/webview_flutter.dart'; 6 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 7 | 8 | class NewsDetailPage extends StatelessWidget{ 9 | 10 | final Completer _controller = Completer(); 11 | 12 | NewsDetailPage({this.mNews}); 13 | final News mNews; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | assert(mNews!=null); 18 | return WebviewScaffold( 19 | url: mNews.src, 20 | appBar: new AppBar( 21 | title: Text('${mNews.title}'), 22 | ), 23 | hidden: true, 24 | initialChild: Container( 25 | child: const Center( 26 | child: Text('Waiting.....'), 27 | ), 28 | ), 29 | ); 30 | // TODO: implement build 31 | /*return Scaffold( 32 | appBar: AppBar( 33 | title: Text('${mNews.title}'), 34 | // This drop down menu demonstrates that Flutter widgets can be shown over the web view. 35 | actions: [ 36 | NavigationControls(_controller.future), 37 | const SampleMenu(), 38 | ], 39 | ), 40 | body: WebView( 41 | initialUrl: mNews.src, 42 | javaScriptMode: JavaScriptMode.unrestricted, 43 | onWebViewCreated: (WebViewController webViewController) { 44 | _controller.complete(webViewController); 45 | }, 46 | ), 47 | floatingActionButton: favoriteButton(), 48 | );*/ 49 | } 50 | 51 | Widget favoriteButton() { 52 | return FutureBuilder( 53 | future: _controller.future, 54 | builder: (BuildContext context, 55 | AsyncSnapshot controller) { 56 | if (controller.hasData) { 57 | return FloatingActionButton( 58 | onPressed: () async { 59 | final String url = await controller.data.currentUrl(); 60 | Scaffold.of(context).showSnackBar( 61 | SnackBar(content: Text("Favorited $url")), 62 | ); 63 | }, 64 | child: const Icon(Icons.favorite), 65 | ); 66 | } 67 | return Container(); 68 | }); 69 | } 70 | } 71 | 72 | class SampleMenu extends StatelessWidget { 73 | const SampleMenu(); 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return PopupMenuButton( 78 | onSelected: (String value) { 79 | Scaffold.of(context) 80 | .showSnackBar(SnackBar(content: Text('You selected: $value'))); 81 | }, 82 | itemBuilder: (BuildContext context) => >[ 83 | const PopupMenuItem( 84 | value: 'Item 1', 85 | child: Text('Item 1'), 86 | ), 87 | const PopupMenuItem( 88 | value: 'Item 2', 89 | child: Text('Item 2'), 90 | ), 91 | ], 92 | ); 93 | } 94 | } 95 | 96 | class NavigationControls extends StatelessWidget { 97 | const NavigationControls(this._webViewControllerFuture) 98 | : assert(_webViewControllerFuture != null); 99 | 100 | final Future _webViewControllerFuture; 101 | 102 | @override 103 | Widget build(BuildContext context) { 104 | return FutureBuilder( 105 | future: _webViewControllerFuture, 106 | builder: 107 | (BuildContext context, AsyncSnapshot snapshot) { 108 | final bool webViewReady = 109 | snapshot.connectionState == ConnectionState.done; 110 | final WebViewController controller = snapshot.data; 111 | return Row( 112 | children: [ 113 | IconButton( 114 | icon: const Icon(Icons.arrow_back_ios), 115 | onPressed: !webViewReady 116 | ? null 117 | : () async { 118 | if (await controller.canGoBack()) { 119 | controller.goBack(); 120 | } else { 121 | Scaffold.of(context).showSnackBar( 122 | const SnackBar(content: Text("No back history item")), 123 | ); 124 | return; 125 | } 126 | }, 127 | ), 128 | IconButton( 129 | icon: const Icon(Icons.arrow_forward_ios), 130 | onPressed: !webViewReady 131 | ? null 132 | : () async { 133 | if (await controller.canGoForward()) { 134 | controller.goForward(); 135 | } else { 136 | Scaffold.of(context).showSnackBar( 137 | const SnackBar( 138 | content: Text("No forward history item")), 139 | ); 140 | return; 141 | } 142 | }, 143 | ), 144 | IconButton( 145 | icon: const Icon(Icons.replay), 146 | onPressed: !webViewReady 147 | ? null 148 | : () { 149 | controller.reload(); 150 | }, 151 | ), 152 | ], 153 | ); 154 | }, 155 | ); 156 | } 157 | } -------------------------------------------------------------------------------- /flutter_demo/lib/utils/SpUtil.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | import 'package:synchronized/synchronized.dart'; 6 | 7 | /** 8 | * @Author: thl 9 | * @GitHub: https://github.com/Sky24n 10 | * @Email: 863764940@qq.com 11 | * @Email: sky24no@gmail.com 12 | * @Description: Sp Util. 13 | * @Date: 2018/9/8 14 | */ 15 | 16 | /// SharedPreferences Util. 17 | class SpUtil { 18 | static SpUtil _singleton; 19 | static SharedPreferences _prefs; 20 | static Lock _lock = Lock(); 21 | 22 | static Future getInstance() async { 23 | if (_singleton == null) { 24 | await _lock.synchronized(() async { 25 | if (_singleton == null) { 26 | // keep local instance till it is fully initialized. 27 | // 保持本地实例直到完全初始化。 28 | var singleton = SpUtil._(); 29 | await singleton._init(); 30 | _singleton = singleton; 31 | } 32 | }); 33 | } 34 | return _singleton; 35 | } 36 | 37 | SpUtil._(); 38 | 39 | Future _init() async { 40 | _prefs = await SharedPreferences.getInstance(); 41 | } 42 | 43 | /// put object. 44 | static Future putObject(String key, Object value) { 45 | if (_prefs == null) return null; 46 | return _prefs.setString(key, value == null ? "" : json.encode(value)); 47 | } 48 | 49 | /// get object. 50 | static Map getObject(String key) { 51 | if (_prefs == null) return null; 52 | String _data = _prefs.getString(key); 53 | return (_data == null || _data.isEmpty) ? null : json.decode(_data); 54 | } 55 | 56 | /// put object list. 57 | static Future putObjectList(String key, List list) { 58 | if (_prefs == null) return null; 59 | List _dataList = list?.map((value) { 60 | return json.encode(value); 61 | })?.toList(); 62 | return _prefs.setStringList(key, _dataList); 63 | } 64 | 65 | /// get object list. 66 | static List getObjectList(String key) { 67 | if (_prefs == null) return null; 68 | List dataLis = _prefs.getStringList(key); 69 | return dataLis?.map((value) { 70 | Map _dataMap = json.decode(value); 71 | return _dataMap; 72 | })?.toList(); 73 | } 74 | 75 | /// get string. 76 | static String getString(String key, {String defValue: ''}) { 77 | if (_prefs == null) return defValue; 78 | return _prefs.getString(key) ?? defValue; 79 | } 80 | 81 | /// put string. 82 | static Future putString(String key, String value) { 83 | if (_prefs == null) return null; 84 | return _prefs.setString(key, value); 85 | } 86 | 87 | /// get bool. 88 | static bool getBool(String key, {bool defValue: false}) { 89 | if (_prefs == null) return defValue; 90 | return _prefs.getBool(key) ?? defValue; 91 | } 92 | 93 | /// put bool. 94 | static Future putBool(String key, bool value) { 95 | if (_prefs == null) return null; 96 | return _prefs.setBool(key, value); 97 | } 98 | 99 | /// get int. 100 | static int getInt(String key, {int defValue: 0}) { 101 | if (_prefs == null) return defValue; 102 | return _prefs.getInt(key) ?? defValue; 103 | } 104 | 105 | /// put int. 106 | static Future putInt(String key, int value) { 107 | if (_prefs == null) return null; 108 | return _prefs.setInt(key, value); 109 | } 110 | 111 | /// get double. 112 | static double getDouble(String key, {double defValue: 0.0}) { 113 | if (_prefs == null) return defValue; 114 | return _prefs.getDouble(key) ?? defValue; 115 | } 116 | 117 | /// put double. 118 | static Future putDouble(String key, double value) { 119 | if (_prefs == null) return null; 120 | return _prefs.setDouble(key, value); 121 | } 122 | 123 | /// get string list. 124 | static List getStringList(String key, 125 | {List defValue: const []}) { 126 | if (_prefs == null) return defValue; 127 | return _prefs.getStringList(key) ?? defValue; 128 | } 129 | 130 | /// put string list. 131 | static Future putStringList(String key, List value) { 132 | if (_prefs == null) return null; 133 | return _prefs.setStringList(key, value); 134 | } 135 | 136 | /// get dynamic. 137 | static dynamic getDynamic(String key, {Object defValue}) { 138 | if (_prefs == null) return defValue; 139 | return _prefs.get(key) ?? defValue; 140 | } 141 | 142 | /// have key. 143 | static bool haveKey(String key) { 144 | if (_prefs == null) return null; 145 | return _prefs.getKeys().contains(key); 146 | } 147 | 148 | /// get keys. 149 | static Set getKeys() { 150 | if (_prefs == null) return null; 151 | return _prefs.getKeys(); 152 | } 153 | 154 | /// remove. 155 | static Future remove(String key) { 156 | if (_prefs == null) return null; 157 | return _prefs.remove(key); 158 | } 159 | 160 | /// clear. 161 | static Future clear() { 162 | if (_prefs == null) return null; 163 | return _prefs.clear(); 164 | } 165 | 166 | ///Sp is initialized. 167 | static bool isInitialized() { 168 | return _prefs != null; 169 | } 170 | } -------------------------------------------------------------------------------- /flutter_demo/lib/utils/functions.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | class Functions {} 4 | 5 | typedef OnChangedCallback = Future Function(); //输入内容变化时触发 6 | 7 | -------------------------------------------------------------------------------- /flutter_demo/lib/videoListPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:chewie/chewie.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:video_player/video_player.dart'; 5 | import 'controller/HttpController.dart'; 6 | import 'bean/RelativeInfoResponse.dart'; 7 | import 'bean/NewsResData.dart'; 8 | import 'bean/NewsDetailResponse.dart'; 9 | 10 | class VideoListPage extends StatefulWidget { 11 | final News mNews; 12 | 13 | VideoListPage({this.mNews}); 14 | 15 | @override 16 | State createState() { 17 | // TODO: implement createState 18 | 19 | return new VideoListPageState(); 20 | } 21 | } 22 | 23 | class VideoListPageState extends State with AutomaticKeepAliveClientMixin{ 24 | TargetPlatform _platform; 25 | VideoPlayerController _controller; 26 | 27 | HttpController _httpController; 28 | 29 | bool _isLoading=true; 30 | RelativeInfoResponse mRelativeInfoResponse; 31 | NewsDetail mNewsDetail; 32 | 33 | @override 34 | void dispose() { 35 | // TODO: implement dispose 36 | super.dispose(); 37 | _controller.dispose(); 38 | } 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | assert(widget.mNews!=null); 44 | _httpController=new HttpController(); 45 | _platform=TargetPlatform.iOS; 46 | 47 | getNewsDetail(); 48 | } 49 | 50 | void getRelativeInfo() async{ 51 | await _httpController.getRelativeInfo(widget.mNews.id,(data){ 52 | if(data!=null){ 53 | setState(() { 54 | _isLoading=false; 55 | mRelativeInfoResponse=data; 56 | }); 57 | } 58 | }); 59 | } 60 | 61 | void getNewsDetail() async{ 62 | await _httpController.getNewsDetail(widget.mNews.id,(data){ 63 | if(data!=null){ 64 | setState(() { 65 | mNewsDetail=data; 66 | _controller = new VideoPlayerController.network(mNewsDetail.videoSrc); 67 | getRelativeInfo(); 68 | }); 69 | } 70 | }); 71 | } 72 | 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return new Scaffold( 77 | /*appBar: new AppBar( 78 | title: new Text(widget.mNews.title), 79 | ),*/ 80 | body: Theme( 81 | data: new ThemeData.light().copyWith( 82 | // platform: _platform ?? Theme.of(context).platform, 83 | platform: TargetPlatform.android, 84 | //视频播放器的底部的控制布局的背景色获取的是dialogBackgroundColor的颜色,所以 85 | //要想改变视频控制栏的背景颜色的话只能通过修改dialogBackgroundColor 的值来修改 86 | dialogBackgroundColor: Color.fromRGBO(41, 41, 41, 0.7), 87 | ), 88 | child: getView(), 89 | ) 90 | ); 91 | } 92 | 93 | Widget getView(){ 94 | if(_isLoading){ 95 | return Center( 96 | child: CircularProgressIndicator(), 97 | ); 98 | }else{ 99 | // return _getRelativeWidgets(mRelativeInfoResponse); 100 | return Stack( 101 | children: [ 102 | Positioned( 103 | top: 0.0, 104 | left: 0.0, 105 | child: Container( 106 | color: Colors.black, 107 | height: MediaQuery.of(context).padding.top, 108 | width: MediaQuery.of(context).size.width, 109 | ) 110 | ), 111 | Positioned( 112 | top: MediaQuery.of(context).padding.top, 113 | left: 0.0, 114 | child: new Container( 115 | child: new Chewie( 116 | _controller, 117 | aspectRatio: 1.6, 118 | autoPlay: true, 119 | looping: true, 120 | 121 | // Try playing around with some of these other options: 122 | 123 | // showControls: false, 124 | materialProgressColors: new ChewieProgressColors( 125 | playedColor: Colors.red, 126 | handleColor: Colors.blue, 127 | backgroundColor: Colors.grey, 128 | bufferedColor: Colors.lightGreen, 129 | ), 130 | placeholder: new Container( 131 | // color: Colors.grey, 132 | child: Image.network(widget.mNews.pictureList[0]), 133 | ), 134 | autoInitialize: true, 135 | ), 136 | ), 137 | ), 138 | Positioned( 139 | top: MediaQuery.of(context).padding.top, 140 | left: 0.0, 141 | child: InkWell( 142 | onTap: (){ 143 | Navigator.pop(context); 144 | }, 145 | child: Container( 146 | margin: EdgeInsets.only(left: 10.0,top: 10.0), 147 | child: Image.asset('images/icon_back_pressed.png',width: 20.0,height: 20.0,), 148 | ) 149 | ) 150 | ), 151 | Positioned( 152 | left: 0.0, 153 | top: 230.0+MediaQuery.of(context).padding.top, 154 | height: MediaQuery.of(context).size.height-230-MediaQuery.of(context).padding.top, 155 | width: MediaQuery.of(context).size.width, 156 | child: _getRelativeWidgets(mRelativeInfoResponse) 157 | ) 158 | ], 159 | ); 160 | } 161 | } 162 | 163 | ListView _getRelativeWidgets(RelativeInfoResponse relativeInfoResponse){ 164 | List resources=relativeInfoResponse.data; 165 | 166 | return ListView.builder( 167 | itemCount: resources.length, 168 | padding: EdgeInsets.only(top: 0.0), //ListView 的paddingTop 默认是有会有30左右的高度,所以这里一定要记得设置为0,一开始不知道的时候搞了好久都没明白 169 | itemBuilder: (context,index){ 170 | String type=resources[index].infoType; 171 | if(type=="videoTitle"){ 172 | return _getTitleWidget(); 173 | }else{ 174 | return _getRelativeWidget(resources[index]); 175 | } 176 | } 177 | ); 178 | 179 | } 180 | 181 | Widget _getTitleWidget(){ 182 | return Column( 183 | crossAxisAlignment: CrossAxisAlignment.start, 184 | 185 | children: [ 186 | /*new Container( 187 | child: new Chewie( 188 | _controller, 189 | aspectRatio: 1.6, 190 | autoPlay: true, 191 | looping: true, 192 | 193 | // Try playing around with some of these other options: 194 | 195 | // showControls: false, 196 | // materialProgressColors: new ChewieProgressColors( 197 | // playedColor: Colors.red, 198 | // handleColor: Colors.blue, 199 | // backgroundColor: Colors.grey, 200 | // bufferedColor: Colors.lightGreen, 201 | // ), 202 | // placeholder: new Container( 203 | // color: Colors.grey, 204 | // ), 205 | // autoInitialize: true, 206 | ), 207 | ),*/ 208 | 209 | Container( 210 | padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 5.0), 211 | child: Text(mNewsDetail.title,style: TextStyle(color: Colors.black,fontSize: 15.0),), 212 | ), 213 | Padding( 214 | padding: EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 10.0), 215 | child:Row( 216 | mainAxisAlignment: MainAxisAlignment.start, 217 | children: [ 218 | Text(mNewsDetail.author,style: TextStyle(fontSize: 13.0,color: Color(0xFF999999)),), 219 | Container( 220 | padding: EdgeInsets.only(left: 10.0), 221 | child: Text(mNewsDetail.addTimeStr,style: TextStyle(fontSize: 13.0,color: Color(0xFF999999)),), 222 | ), 223 | Row( 224 | textDirection: TextDirection.rtl, 225 | mainAxisAlignment: MainAxisAlignment.start, 226 | children: [ 227 | Container( 228 | padding: EdgeInsets.only(left: 70.0), 229 | child: Text(mNewsDetail.readcount.toString() +"次阅读",style: TextStyle(fontSize: 13.0,color: Color(0xFF999999)),), 230 | ), 231 | ], 232 | ) 233 | ], 234 | ), 235 | ), 236 | 237 | ], 238 | ); 239 | } 240 | 241 | Widget _getRelativeWidget(RelativeNews relativeNews){ 242 | return Padding( 243 | padding: EdgeInsets.fromLTRB(10.0, 3.0, 10.0, 3.0), 244 | child: Row( 245 | mainAxisAlignment: MainAxisAlignment.start, 246 | crossAxisAlignment: CrossAxisAlignment.start, 247 | children: [ 248 | Container( 249 | margin: EdgeInsets.only(right: 10.0), 250 | child: Image.network(relativeNews.pictureList[0],height: 78.0,width: 113,fit: BoxFit.cover,) , 251 | ), 252 | 253 | Expanded( 254 | child: Container( 255 | child: Text(relativeNews.title,style: TextStyle(color: Color(0xFF032F62),fontSize: 16.0),), 256 | ) 257 | ) 258 | 259 | ], 260 | ), 261 | ); 262 | } 263 | 264 | @override 265 | // TODO: implement wantKeepAlive 266 | bool get wantKeepAlive => true; 267 | 268 | } -------------------------------------------------------------------------------- /flutter_demo/lib/view/NewDetailWebview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_demo/bean/NewsResData.dart'; 4 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 5 | 6 | class NewDetailWebview extends StatelessWidget{ 7 | final News mNews; 8 | NewDetailWebview({this.mNews}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | assert(mNews!=null); 13 | return WebviewScaffold( 14 | url: mNews.src, 15 | hidden: true, 16 | initialChild: Container( 17 | child: const Center( 18 | child: Text('Waiting.....'), 19 | ), 20 | ), 21 | ); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /flutter_demo/lib/view/SearchView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_demo/utils/functions.dart'; 4 | class SearchView extends StatefulWidget{ 5 | 6 | final double height; 7 | final double elevation; //阴影 8 | final String hintText; 9 | final FocusNode focusNode; 10 | final TextEditingController controller; 11 | final IconData prefixIcon; 12 | final List inputFormatters; 13 | final VoidCallback onEditingComplete; 14 | final OnChangedCallback onChangedCallback; 15 | 16 | const SearchView( 17 | {Key key, 18 | this.height: 46.0, 19 | this.elevation: 0.5, 20 | this.hintText: '请输入关键词', 21 | this.focusNode, 22 | this.controller, 23 | this.inputFormatters, 24 | this.onEditingComplete, 25 | this.onChangedCallback, 26 | this.prefixIcon: Icons.search}) 27 | : super(key: key); 28 | 29 | @override 30 | State createState() { 31 | // TODO: implement createState 32 | return new SearchViewState(); 33 | } 34 | 35 | } 36 | 37 | class SearchViewState extends State{ 38 | bool _hasdeleteIcon = false; 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | // TODO: implement build 43 | return Container( 44 | height: 40.0, 45 | child: new TextField( 46 | focusNode: widget.focusNode, 47 | keyboardType: TextInputType.text, 48 | textInputAction: TextInputAction.done, 49 | controller: widget.controller, 50 | maxLines: 1, 51 | inputFormatters: widget.inputFormatters, 52 | decoration: InputDecoration( 53 | hintText: widget.hintText, 54 | hintStyle: TextStyle( 55 | color: Color(0xFF999999), 56 | fontSize: 16.0, 57 | ), 58 | prefixIcon: Padding( 59 | padding: EdgeInsetsDirectional.only(start: 10.0), 60 | child: Icon( 61 | widget.prefixIcon, 62 | color: Colors.black, 63 | )), 64 | suffixIcon: Padding( 65 | padding: EdgeInsetsDirectional.only( 66 | start: 2.0, end: _hasdeleteIcon ? 20.0 : 0), 67 | child: _hasdeleteIcon 68 | ? new InkWell( 69 | onTap: (() { 70 | setState(() { 71 | widget.controller.text = ''; 72 | _hasdeleteIcon = false; 73 | if (null != widget.onChangedCallback) { 74 | widget.onChangedCallback(); 75 | } 76 | }); 77 | }), 78 | child: Icon( 79 | Icons.clear, 80 | size: 18.0, 81 | color: Colors.black, 82 | )) 83 | : new Text('')), 84 | contentPadding: EdgeInsets.fromLTRB(0, 10, 0, 0), 85 | filled: true, 86 | fillColor: Color.fromARGB(150, 235, 235, 235), 87 | enabledBorder: OutlineInputBorder( //可用状态下的边框 88 | borderRadius: BorderRadius.circular(20.0), 89 | borderSide: BorderSide( 90 | color: Color(0xFFCCCCCC) 91 | ) 92 | ), 93 | focusedBorder: OutlineInputBorder( //可用状态获取焦点下的边框 94 | borderRadius: BorderRadius.circular(20.0), 95 | borderSide: BorderSide( 96 | color: Color(0xFFCCCCCC) 97 | ) 98 | ), 99 | 100 | ), 101 | onChanged: (str) { 102 | if (null != widget.onChangedCallback) { 103 | widget.onChangedCallback(); 104 | } 105 | 106 | setState(() { 107 | if (str.isEmpty) { 108 | _hasdeleteIcon = false; 109 | } else { 110 | _hasdeleteIcon = true; 111 | } 112 | }); 113 | }, 114 | onEditingComplete: widget.onEditingComplete 115 | ), 116 | ); 117 | 118 | } 119 | 120 | } -------------------------------------------------------------------------------- /flutter_demo/lib/view/StaticRatingBar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'dart:math' as Math; 3 | 4 | const double kMaxRate = 5.0; 5 | const int kNumberOfStarts = 5; 6 | const double kSpacing = 3.0; 7 | const double kSize = 50.0; 8 | 9 | class StaticRatingBar extends StatelessWidget { 10 | /// number of stars 11 | final int count; 12 | 13 | /// init rate 14 | final double rate; 15 | 16 | /// size of the starts 17 | final double size; 18 | 19 | final Color colorLight; 20 | 21 | final Color colorDark; 22 | 23 | StaticRatingBar({ 24 | double rate, 25 | Color colorLight, 26 | Color colorDark, 27 | int count, 28 | this.size: kSize, 29 | }) : rate = rate ?? kMaxRate, 30 | count = count ?? kNumberOfStarts, 31 | colorDark = colorDark ?? new Color(0xffeeeeee), 32 | colorLight = colorLight ?? new Color(0xffFF962E); 33 | 34 | Widget buildStar() { 35 | return new SizedBox( 36 | width: size * count, 37 | height: size, 38 | child: new CustomPaint( 39 | painter: new _PainterStars( 40 | size: this.size / 2, 41 | color: colorLight, 42 | style: PaintingStyle.fill, 43 | strokeWidth: 0.0), 44 | )); 45 | } 46 | 47 | Widget buildHollowStar() { 48 | return new SizedBox( 49 | width: size * count, 50 | height: size, 51 | child: new CustomPaint( 52 | painter: new _PainterStars( 53 | size: this.size / 2, 54 | color: colorDark, 55 | style: PaintingStyle.fill, 56 | strokeWidth: 0.0), 57 | )); 58 | } 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | return new Stack( 63 | children: [ 64 | buildHollowStar(), 65 | new ClipRect( 66 | clipper: new _RatingBarClipper(width: rate * size), 67 | child: buildStar(), 68 | ) 69 | ], 70 | ); 71 | } 72 | } 73 | 74 | class _RatingBarClipper extends CustomClipper { 75 | final double width; 76 | 77 | _RatingBarClipper({this.width}) : assert(width != null); 78 | 79 | @override 80 | Rect getClip(Size size) { 81 | return new Rect.fromLTRB(0.0, 0.0, width, size.height); 82 | } 83 | 84 | @override 85 | bool shouldReclip(_RatingBarClipper oldClipper) { 86 | return width != oldClipper.width; 87 | } 88 | } 89 | 90 | 91 | 92 | class _PainterStars extends CustomPainter { 93 | final double size; 94 | final Color color; 95 | final PaintingStyle style; 96 | final double strokeWidth; 97 | 98 | _PainterStars({this.size, this.color, this.strokeWidth, this.style}); 99 | 100 | /// 角度转弧度公式 101 | double degree2Radian(int degree) { 102 | return (Math.pi * degree / 180); 103 | } 104 | 105 | Path createStarPath(double radius, Path path) { 106 | double radian = degree2Radian(36); // 36为五角星的角度 107 | double radius_in = (radius * Math.sin(radian / 2) / Math.cos(radian)) * 108 | 1.1; // 中间五边形的半径,太正不是很好看,扩大一点点 109 | 110 | path.moveTo((radius * Math.cos(radian / 2)), 0.0); // 此点为多边形的起点 111 | path.lineTo((radius * Math.cos(radian / 2) + radius_in * Math.sin(radian)), 112 | (radius - radius * Math.sin(radian / 2))); 113 | path.lineTo((radius * Math.cos(radian / 2) * 2), 114 | (radius - radius * Math.sin(radian / 2))); 115 | path.lineTo( 116 | (radius * Math.cos(radian / 2) + radius_in * Math.cos(radian / 2)), 117 | (radius + radius_in * Math.sin(radian / 2))); 118 | path.lineTo((radius * Math.cos(radian / 2) + radius * Math.sin(radian)), 119 | (radius + radius * Math.cos(radian))); 120 | path.lineTo((radius * Math.cos(radian / 2)), (radius + radius_in)); 121 | path.lineTo((radius * Math.cos(radian / 2) - radius * Math.sin(radian)), 122 | (radius + radius * Math.cos(radian))); 123 | path.lineTo( 124 | (radius * Math.cos(radian / 2) - radius_in * Math.cos(radian / 2)), 125 | (radius + radius_in * Math.sin(radian / 2))); 126 | path.lineTo(0.0, (radius - radius * Math.sin(radian / 2))); 127 | path.lineTo((radius * Math.cos(radian / 2) - radius_in * Math.sin(radian)), 128 | (radius - radius * Math.sin(radian / 2))); 129 | 130 | path.lineTo((radius * Math.cos(radian / 2)), 0.0); 131 | return path; 132 | } 133 | 134 | @override 135 | void paint(Canvas canvas, Size size) { 136 | Paint paint = new Paint(); 137 | // paint.color = Colors.redAccent; 138 | paint.strokeWidth = strokeWidth; 139 | paint.color = color; 140 | paint.style = style; 141 | 142 | Path path = new Path(); 143 | 144 | double offset = strokeWidth > 0 ? strokeWidth + 2 : 0.0; 145 | 146 | path = createStarPath(this.size - offset, path); 147 | path = path.shift(new Offset(this.size * 2, 0.0)); 148 | path = createStarPath(this.size - offset, path); 149 | path = path.shift(new Offset(this.size * 2, 0.0)); 150 | path = createStarPath(this.size - offset, path); 151 | path = path.shift(new Offset(this.size * 2, 0.0)); 152 | path = createStarPath(this.size - offset, path); 153 | path = path.shift(new Offset(this.size * 2, 0.0)); 154 | path = createStarPath(this.size - offset, path); 155 | 156 | if (offset > 0) { 157 | path = path.shift(new Offset(offset, offset)); 158 | } 159 | path.close(); 160 | 161 | canvas.drawPath(path, paint); 162 | } 163 | 164 | @override 165 | bool shouldRepaint(_PainterStars oldDelegate) { 166 | return oldDelegate.size != this.size; 167 | } 168 | } -------------------------------------------------------------------------------- /flutter_demo/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_demo 2 | description: A new Flutter application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | environment: 13 | sdk: ">=2.0.0-dev.68.0 <3.0.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | # The following adds the Cupertino Icons font to your application. 20 | # Use with the CupertinoIcons class for iOS style icons. 21 | cupertino_icons: ^0.1.2 22 | english_words: ^3.1.0 23 | dio: ^1.0.13 24 | webview_flutter: ^0.1.2 25 | flutter_webview_plugin: ^0.3.0+2 26 | chewie: ^0.8.0 27 | flutter_swiper: ^1.1.4 28 | image_picker: ^0.4.12+1 29 | qrcode_reader: ^0.4.4 30 | pointycastle: ^1.0.0 31 | shared_preferences: ^0.5.1+2 32 | synchronized: ^2.1.0 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | 38 | 39 | # For information on the generic Dart part of this file, see the 40 | # following page: https://www.dartlang.org/tools/pub/pubspec 41 | 42 | # The following section is specific to Flutter. 43 | flutter: 44 | 45 | # The following line ensures that the Material Icons font is 46 | # included with your application, so that you can use the icons in 47 | # the material Icons class. 48 | uses-material-design: true 49 | 50 | 51 | # To add assets to your application, add an assets section, like this: 52 | assets: 53 | - images/icon_logo.png 54 | - images/icon_function_search.png 55 | - images/icon_main_tab_news_normal.png 56 | - images/icon_main_tab_news_selected.png 57 | - images/icon_main_tab_micro_normal.png 58 | - images/icon_main_tab_micro_select.png 59 | - images/icon_history_time.png 60 | - images/icon_main_tab_person_normal.png 61 | - images/icon_main_tab_person_selected.png 62 | - images/fiction_header_icon.png 63 | - images/fiction_1.png 64 | - images/fiction_2.png 65 | - images/fiction_3.png 66 | - images/fiction_4.png 67 | - images/fiction_author.png 68 | - images/icon_replace.png 69 | - images/icon_share.png 70 | - images/icon_back.png 71 | - images/icon_right.png 72 | - images/icon_add_comment.png 73 | - images/icon_back_pressed.png 74 | - images/icon_main_tab_fiction_normal.png 75 | - images/icon_main_tab_fiction_selected.png 76 | - images/setting.png 77 | - images/personal_heart_bg.png 78 | - images/personal_ava_default.png 79 | - images/mine_apprentice_icon.png 80 | - images/mine_cash_icon.png 81 | - images/mine_message_icon.png 82 | - images/mine_withdraw_icon.png 83 | - images/mine_code_icon.png 84 | - images/mine_guess_icon.png 85 | - images/mine_read_icon.png 86 | - images/mine_riddle_icon.png 87 | - images/mine_wallet_icon.png 88 | - images/icon_coin.png 89 | - images/icon_coin.png 90 | - images/icon_coin_bg.png 91 | # - images/a_dot_ham.jpeg 92 | 93 | # An image asset can refer to one or more resolution-specific "variants", see 94 | # https://flutter.io/assets-and-images/#resolution-aware. 95 | 96 | # For details regarding adding assets from package dependencies, see 97 | # https://flutter.io/assets-and-images/#from-packages 98 | 99 | # To add custom fonts to your application, add a fonts section here, 100 | # in this "flutter" section. Each entry in this list should have a 101 | # "family" key with the font family name, and a "fonts" key with a 102 | # list giving the asset and other descriptors for the font. For 103 | # example: 104 | # fonts: 105 | # - family: Schyler 106 | # fonts: 107 | # - asset: fonts/Schyler-Regular.ttf 108 | # - asset: fonts/Schyler-Italic.ttf 109 | # style: italic 110 | # - family: Trajan Pro 111 | # fonts: 112 | # - asset: fonts/TrajanPro.ttf 113 | # - asset: fonts/TrajanPro_Bold.ttf 114 | # weight: 700 115 | # 116 | # For details regarding fonts from package dependencies, 117 | # see https://flutter.io/custom-fonts/#from-packages 118 | -------------------------------------------------------------------------------- /flutter_demo/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:flutter_demo/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(AppHome()); 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 | -------------------------------------------------------------------------------- /images/1550481959(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550481959(1).jpg -------------------------------------------------------------------------------- /images/1550481996(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550481996(1).jpg -------------------------------------------------------------------------------- /images/1550482021(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550482021(1).jpg -------------------------------------------------------------------------------- /images/1550482063(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550482063(1).jpg -------------------------------------------------------------------------------- /images/1550482086(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550482086(1).jpg -------------------------------------------------------------------------------- /images/1550482109(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1550482109(1).jpg -------------------------------------------------------------------------------- /images/1553766601(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1553766601(1).jpg -------------------------------------------------------------------------------- /images/1553766652(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HWHUAN/Flutter_bwkd/20a4caa3ebca8e69d7b07d63a6b329229102fb2b/images/1553766652(1).jpg --------------------------------------------------------------------------------