commit acd72c1d278a50cc1812442cd0f5059c11a8dc81 Author: toly <1981462002@qq.com> Date: Fri Apr 17 07:28:08 2020 +0800 清除所有历史版本以减少仓库大小 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee60ef6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ +/lib/tools/ +# Web related +lib/generated_plugin_registrant.dart + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..01d2dcb --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 0b8abb4724aa590dd0f429683339b1e045a1594d + channel: stable + +project_type: app diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6e3089 --- /dev/null +++ b/README.md @@ -0,0 +1,184 @@ +### FlutterUnit apk 下载体验: + +![](https://user-gold-cdn.xitu.io/2020/4/16/17182551c57d6ebb?w=300&h=390&f=png&s=22366) + + +--- + + +### 一、组件的展示页面 + +#### 1. `200+组件收录` + +> Flutter源码中的可用的组件一共350个左右,纷繁复杂,也没有明确的分类标准 +FlutterUnit 对`大大小小,常用不常用`的组件能收的尽量收录。并`根据个人感觉进行评星 ` +`目前收录组件207个`,每个都有至少一个演示展现和代码展示。 + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175af35f63c8fb?w=1080&h=2340&f=jpeg&s=158267)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175b0c1c92a004?w=1080&h=2340&f=jpeg&s=161619)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175b0a95d5c549?w=1080&h=2340&f=jpeg&s=150406) | +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175af9b09f76f6?w=1080&h=2340&f=jpeg&s=153575) | ![](https://user-gold-cdn.xitu.io/2020/4/14/17175b0766ed455b?w=1080&h=2340&f=jpeg&s=166128) |![](https://user-gold-cdn.xitu.io/2020/4/14/17175af6b9523083?w=1080&h=2340&f=jpeg&s=163290) | + + +--- + +#### 2. 组件详情页 + +> `207个组件`全部都有详情页。对于重要的组件会详细展现 +一般都会有某个演示对应的组件和属性,尽量做到细致,如果有需要补充,欢迎联系我。 +`最重要的是: 所有的演示展现都是Flutter的组件形成的,而非图片,这就意味着可操作性更高。` + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175c3f21476fc5?w=1080&h=2340&f=jpeg&s=67728)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175c44a1cfa94c?w=1080&h=2340&f=jpeg&s=92664)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175c4a7cd90126?w=1080&h=2340&f=jpeg&s=114306) | +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175c5171d0373f?w=1080&h=2340&f=jpeg&s=159437) | ![](https://user-gold-cdn.xitu.io/2020/4/14/17175c56ce136676?w=1080&h=2340&f=jpeg&s=87311) |![](https://user-gold-cdn.xitu.io/2020/4/14/17175c61623c6462?w=1080&h=2340&f=jpeg&s=108215)| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/171775f429e77628?w=1080&h=2340&f=png&s=350811) | ![](https://user-gold-cdn.xitu.io/2020/4/14/17175d050c8ebdac?w=1080&h=2340&f=jpeg&s=116274) |![](https://user-gold-cdn.xitu.io/2020/4/14/17175d09ac9ebd06?w=1080&h=2340&f=jpeg&s=103820)| + + + + + + +--- + +#### 3. 组件的可操作性 + +> 对一些操作交互的组件或有可操作性的某些组件,`提供操作演示` + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175df98f83e05c?w=362&h=724&f=gif&s=1061771)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175dcce9022ddc?w=362&h=724&f=gif&s=232124)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175de9b348a26a?w=362&h=724&f=gif&s=946647)| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175e07aeb7c5db?w=362&h=724&f=gif&s=934471) | ![](https://user-gold-cdn.xitu.io/2020/4/14/17175e14f00bacd6?w=362&h=724&f=gif&s=2032439) |![](https://user-gold-cdn.xitu.io/2020/4/14/17175e2353306a37)| + +--- + +#### 4. 相关组件的关联切换 +> `相关组件通过link to 可以进行切换, 满足你的探索欲。` +如果有的关联未加入,欢迎联系我,对我来说,加个数字就行了。 + +![](https://user-gold-cdn.xitu.io/2020/4/14/17175ea0ea610669?w=610&h=226&f=png&s=37961) + +| . | . | . | +|------|------------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/17175e8c2a46e1f3?w=362&h=724&f=gif&s=471182)|![](https://user-gold-cdn.xitu.io/2020/4/14/17175e921dfc5c81?w=362&h=724&f=gif&s=658708)| ![](https://user-gold-cdn.xitu.io/2020/4/14/17175e968c4f68e4?w=362&h=724&f=gif&s=300803)| + +--- + +#### 5. 代码的查看和分享 +> 激动人心的是,你可以通过右侧的图标`展开/隐藏 实现下面效果的代码` +并且`支持分享`,如果你想亲自体验,so,easy ! 而且`代码高亮样式可以自定义`。 + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/171760369b9ae9d6?w=362&h=724&f=gif&s=1207409)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717603ad9119f2a?w=362&h=724&f=gif&s=1064037)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717604b10154271?w=362&h=724&f=gif&s=2849830)| + + +--- + + +### 二、全局配置 + +#### 1. 颜色主题 +> 只提供八种颜色,可在`右滑菜单页`的`我的主题`配置,`可以拓展` + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/171760c51633383d?w=1080&h=2340&f=jpeg&s=94977)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171760cbc7d0ddba?w=1080&h=2340&f=jpeg&s=89001) | ![](https://user-gold-cdn.xitu.io/2020/4/14/171760b8c24c188f?w=1080&h=2340&f=jpeg&s=168263) | +| ![](https://user-gold-cdn.xitu.io/2020/4/14/171760e274f4bbd4?w=1080&h=2340&f=jpeg&s=165793) | ![](https://user-gold-cdn.xitu.io/2020/4/14/171760e5a8ef180d?w=1080&h=2340&f=jpeg&s=167091) |![](https://user-gold-cdn.xitu.io/2020/4/14/171760fd8bb60a8f?w=1080&h=2340&f=png&s=1105286)| + + + + +--- + + +#### 2.字体配置 + +> 支持全局字体设置,`可以拓展` + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717615741f8d2e3?w=1080&h=2340&f=png&s=167438)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171761667bbf6051?w=1080&h=2340&f=png&s=808002) | ![](https://user-gold-cdn.xitu.io/2020/4/14/1717617b8ab59421?w=1080&h=2340&f=png&s=796618)| + +--- + + +#### 3.item样式设置 + +> 支持item样式设置,`可以拓展,支持征集`,详见`Flutter Unit 1.0 征集方案` + +| . | . | . | +|------|------------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/1717620037fd9a50?w=1080&h=2340&f=jpeg&s=105051)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717620161fa89ec?w=1080&h=2340&f=jpeg&s=158327)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171762026eb8656d?w=1080&h=2340&f=jpeg&s=146688)| + +--- + +#### 4.代码面板风格设置 + +> 支持代码风格设置,`可以拓展,支持征集`,详见`Flutter Unit 1.0 征集方案` + +| . | . | +|------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/1717628b5fe1591c?w=1080&h=759&f=png&s=105023)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717629001ade9b0?w=1080&h=773&f=png&s=102672)| +![](https://user-gold-cdn.xitu.io/2020/4/14/17176298797c49a7?w=1080&h=769&f=png&s=93521) |![](https://user-gold-cdn.xitu.io/2020/4/14/171762a2e5534237?w=1080&h=753&f=png&s=122928)| +![](https://user-gold-cdn.xitu.io/2020/4/14/171762a5db361ce9?w=1080&h=759&f=png&s=106838)|![](https://user-gold-cdn.xitu.io/2020/4/14/171762aad1c14ce7?w=1080&h=756&f=png&s=94480)| + + +--- + + + +### 三、搜索与收藏功能 + + +#### 1.搜索功能 + +> 由于Flutter中Widget比较杂乱,不太好分类,所以搜索是非常重要的 +另外可以根据星级进行过滤,支持多选。目前正在考虑根据功能分类,之后会有所完善。 + + +| . | . | . | +|------|------------|------------| +| ![](https://user-gold-cdn.xitu.io/2020/4/14/171775fc594e4605?w=1080&h=2340&f=png&s=265281)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171775fd99268a78?w=1080&h=2340&f=png&s=424599)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171775fefef50fb9?w=1080&h=2340&f=png&s=414437) | + +--- + +#### 2.搜藏功能 + +> 搜藏页做得比较简陋,后面打算做收藏夹,可以自己创建的那种。 + +| . | . | . | +|------|------------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/17177668aa7fd135?w=1080&h=2340&f=png&s=640245)|![](https://user-gold-cdn.xitu.io/2020/4/14/17177665c53256b4?w=1080&h=2340&f=png&s=797902)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717765ec688731c?w=1080&h=2340&f=png&s=272421)| + +> `FlutterUnit 1.0 `目前基本就是这么多功能,可以在Github中下载打包后的apk玩玩 +希望能对你的Flutter学习有所帮助。 + +--- + +#### 3.关于我与项目 +> 不多说,都在图里。 + +| . | . | . | +|------|------------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/171777c67ed0c205?w=1080&h=2340&f=png&s=1272888)|![](https://user-gold-cdn.xitu.io/2020/4/14/171777c8ccfce16b?w=1080&h=2340&f=png&s=1105006)| ![](https://user-gold-cdn.xitu.io/2020/4/14/171777caed85b26a?w=1080&h=2340&f=png&s=1190414) +| + + + +--- + +### 四、FlutterUnit 2.0 展望 + +> 后面将是一些集录,需要更多的Flutter爱好者参与,计划方案将陆续发布。 + +| . | . | +|------|------------| +|![](https://user-gold-cdn.xitu.io/2020/4/14/171777f2cf762719?w=1080&h=2340&f=png&s=407929)| ![](https://user-gold-cdn.xitu.io/2020/4/14/1717799a14c22a11?w=1080&h=2340&f=png&s=448164) | +![](https://user-gold-cdn.xitu.io/2020/4/14/1717799eb0f01c6f?w=1080&h=2340&f=png&s=431993) |![](https://user-gold-cdn.xitu.io/2020/4/14/171779a42e429ce1?w=1080&h=2340&f=png&s=393176)| + + +--- + + +> 最后,欢迎[Star和关注FlutterUnit](https://github.com/toly1994328/FlutterUnit) 的发展,让我们一起携手,成为Unit一员。 diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..82ed62c --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,8 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +/key.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..e135c38 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,81 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +//add------------------start +def keystorePropertiesFile = rootProject.file("key.properties") +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +//add------------------end + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.toly1994.flutter_unit" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..db3bcba --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4d701f0 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/toly1994/flutter_unit/MainActivity.kt b/android/app/src/main/kotlin/com/toly1994/flutter_unit/MainActivity.kt new file mode 100644 index 0000000..40bf860 --- /dev/null +++ b/android/app/src/main/kotlin/com/toly1994/flutter_unit/MainActivity.kt @@ -0,0 +1,12 @@ +package com.toly1994.flutter_unit + +import androidx.annotation.NonNull; +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +class MainActivity: FlutterActivity() { + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + } +} diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/logo.png b/android/app/src/main/res/mipmap-xxhdpi/logo.png new file mode 100644 index 0000000..fe2a961 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/logo.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..00fa441 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..db3bcba --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/key.properties b/android/key.properties new file mode 100644 index 0000000..4a650df --- /dev/null +++ b/android/key.properties @@ -0,0 +1,4 @@ +storePassword=toly1994 +keyPassword=toly1994 +keyAlias=key +storeFile=/Volumes/coder/file/key/toly.jks \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/flutter.db b/assets/flutter.db new file mode 100644 index 0000000..033908c Binary files /dev/null and b/assets/flutter.db differ diff --git a/assets/fonts/BalooBhai2-Regular.ttf b/assets/fonts/BalooBhai2-Regular.ttf new file mode 100644 index 0000000..21a9430 Binary files /dev/null and b/assets/fonts/BalooBhai2-Regular.ttf differ diff --git a/assets/fonts/ComicNeue-Regular.ttf b/assets/fonts/ComicNeue-Regular.ttf new file mode 100644 index 0000000..cbfed15 Binary files /dev/null and b/assets/fonts/ComicNeue-Regular.ttf differ diff --git a/assets/fonts/Inconsolata-Regular.ttf b/assets/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..18a0708 Binary files /dev/null and b/assets/fonts/Inconsolata-Regular.ttf differ diff --git a/assets/fonts/IndieFlower-Regular.ttf b/assets/fonts/IndieFlower-Regular.ttf new file mode 100644 index 0000000..1070aac Binary files /dev/null and b/assets/fonts/IndieFlower-Regular.ttf differ diff --git a/assets/fonts/Neucha-Regular.ttf b/assets/fonts/Neucha-Regular.ttf new file mode 100644 index 0000000..a9b9158 Binary files /dev/null and b/assets/fonts/Neucha-Regular.ttf differ diff --git a/assets/iconfont/icon_builder.dart b/assets/iconfont/icon_builder.dart new file mode 100644 index 0000000..885f584 --- /dev/null +++ b/assets/iconfont/icon_builder.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:path/path.dart' as path; + +main() async{ + var fontName ='TolyIcon'; + var resDir="assets/iconfont";//资源文件夹 + var outFile='lib/app/style/$fontName.dart';//输出文件地址 + + var result = """import 'package:flutter/widgets.dart'; +//Power By 张风捷特烈--- Generated file. Do not edit. + +class $fontName { + + $fontName._(); +"""; + var fileCss = File(path.join(Directory.current.path,"$resDir/iconfont.css")); + if (! await fileCss.exists()) return; + + var read = await fileCss.readAsString(); + var split = read.split(".icon-"); + split.forEach((str) { + if (str.contains("before")) { + var split = str.split(":"); + result += "static const IconData " + + split[0].replaceAll("-", "_") + + " = const IconData(" + + split[2].replaceAll("\"\\", "0x").split("\"")[0] + + ", fontFamily: \"$fontName\");\n"; + } + }); + result+="}"; + fileCss.delete();//删除css文件 + + var fileOut = File(path.join(Directory.current.path,"$outFile")); + if(! await fileOut.exists()){ + await fileOut.create(recursive: true); + } + fileOut.writeAsString(result);//将代码写入dart文件 + + var config=""" + fonts: + - family: $fontName + fonts: + - asset: """+"$resDir/iconfont.ttf"; + + print("build OK:\n $config"); +} \ No newline at end of file diff --git a/assets/iconfont/iconfont.ttf b/assets/iconfont/iconfont.ttf new file mode 100644 index 0000000..961ac27 Binary files /dev/null and b/assets/iconfont/iconfont.ttf differ diff --git a/assets/images/caver.jpeg b/assets/images/caver.jpeg new file mode 100755 index 0000000..5213cea Binary files /dev/null and b/assets/images/caver.jpeg differ diff --git a/assets/images/dart.jpg b/assets/images/dart.jpg new file mode 100644 index 0000000..362e81c Binary files /dev/null and b/assets/images/dart.jpg differ diff --git a/assets/images/head_icon/icon_5.jpg b/assets/images/head_icon/icon_5.jpg new file mode 100644 index 0000000..67f42e7 Binary files /dev/null and b/assets/images/head_icon/icon_5.jpg differ diff --git a/assets/images/head_icon/icon_6.jpg b/assets/images/head_icon/icon_6.jpg new file mode 100644 index 0000000..562a4f7 Binary files /dev/null and b/assets/images/head_icon/icon_6.jpg differ diff --git a/assets/images/head_icon/icon_7.jpg b/assets/images/head_icon/icon_7.jpg new file mode 100644 index 0000000..1d2788d Binary files /dev/null and b/assets/images/head_icon/icon_7.jpg differ diff --git a/assets/images/head_icon/icon_8.jpg b/assets/images/head_icon/icon_8.jpg new file mode 100644 index 0000000..0850b12 Binary files /dev/null and b/assets/images/head_icon/icon_8.jpg differ diff --git a/assets/images/icon_head.png b/assets/images/icon_head.png new file mode 100755 index 0000000..e12afaa Binary files /dev/null and b/assets/images/icon_head.png differ diff --git a/assets/images/java.jpeg b/assets/images/java.jpeg new file mode 100644 index 0000000..872333c Binary files /dev/null and b/assets/images/java.jpeg differ diff --git a/assets/images/kotlin.jpg b/assets/images/kotlin.jpg new file mode 100644 index 0000000..fe48186 Binary files /dev/null and b/assets/images/kotlin.jpg differ diff --git a/assets/images/leaf.png b/assets/images/leaf.png new file mode 100644 index 0000000..5755c73 Binary files /dev/null and b/assets/images/leaf.png differ diff --git a/assets/images/left_chat.png b/assets/images/left_chat.png new file mode 100755 index 0000000..7460d5f Binary files /dev/null and b/assets/images/left_chat.png differ diff --git a/assets/images/pica.gif b/assets/images/pica.gif new file mode 100644 index 0000000..6d2b050 Binary files /dev/null and b/assets/images/pica.gif differ diff --git a/assets/images/right_chat.png b/assets/images/right_chat.png new file mode 100755 index 0000000..299edbd Binary files /dev/null and b/assets/images/right_chat.png differ diff --git a/assets/images/sabar.jpg b/assets/images/sabar.jpg new file mode 100644 index 0000000..10b7aee Binary files /dev/null and b/assets/images/sabar.jpg differ diff --git a/assets/images/sabar_bar.jpg b/assets/images/sabar_bar.jpg new file mode 100644 index 0000000..410674d Binary files /dev/null and b/assets/images/sabar_bar.jpg differ diff --git a/assets/images/wechat.jpg b/assets/images/wechat.jpg new file mode 100644 index 0000000..91cc16a Binary files /dev/null and b/assets/images/wechat.jpg differ diff --git a/assets/images/wei_x.jpg b/assets/images/wei_x.jpg new file mode 100644 index 0000000..45c3c19 Binary files /dev/null and b/assets/images/wei_x.jpg differ diff --git a/assets/images/widgets/ActionChip.png b/assets/images/widgets/ActionChip.png new file mode 100644 index 0000000..b9ce8eb Binary files /dev/null and b/assets/images/widgets/ActionChip.png differ diff --git a/assets/images/widgets/Banner.png b/assets/images/widgets/Banner.png new file mode 100644 index 0000000..f6c0288 Binary files /dev/null and b/assets/images/widgets/Banner.png differ diff --git a/assets/images/widgets/Card.png b/assets/images/widgets/Card.png new file mode 100644 index 0000000..4118c05 Binary files /dev/null and b/assets/images/widgets/Card.png differ diff --git a/assets/images/widgets/CheckBoxListTile.png b/assets/images/widgets/CheckBoxListTile.png new file mode 100644 index 0000000..ff650a1 Binary files /dev/null and b/assets/images/widgets/CheckBoxListTile.png differ diff --git a/assets/images/widgets/Chip.png b/assets/images/widgets/Chip.png new file mode 100644 index 0000000..252ccfe Binary files /dev/null and b/assets/images/widgets/Chip.png differ diff --git a/assets/images/widgets/ChoiceChip.png b/assets/images/widgets/ChoiceChip.png new file mode 100644 index 0000000..d409c99 Binary files /dev/null and b/assets/images/widgets/ChoiceChip.png differ diff --git a/assets/images/widgets/CircleAvatar.png b/assets/images/widgets/CircleAvatar.png new file mode 100644 index 0000000..45c3e43 Binary files /dev/null and b/assets/images/widgets/CircleAvatar.png differ diff --git a/assets/images/widgets/Container.png b/assets/images/widgets/Container.png new file mode 100644 index 0000000..032eea2 Binary files /dev/null and b/assets/images/widgets/Container.png differ diff --git a/assets/images/widgets/FadeInImage.png b/assets/images/widgets/FadeInImage.png new file mode 100644 index 0000000..c11b3d3 Binary files /dev/null and b/assets/images/widgets/FadeInImage.png differ diff --git a/assets/images/widgets/FilterChip.png b/assets/images/widgets/FilterChip.png new file mode 100644 index 0000000..c9b93ce Binary files /dev/null and b/assets/images/widgets/FilterChip.png differ diff --git a/assets/images/widgets/FlutterLogo.png b/assets/images/widgets/FlutterLogo.png new file mode 100644 index 0000000..479e095 Binary files /dev/null and b/assets/images/widgets/FlutterLogo.png differ diff --git a/assets/images/widgets/GridTile.png b/assets/images/widgets/GridTile.png new file mode 100644 index 0000000..731a278 Binary files /dev/null and b/assets/images/widgets/GridTile.png differ diff --git a/assets/images/widgets/GridTileBar.png b/assets/images/widgets/GridTileBar.png new file mode 100644 index 0000000..a043ed0 Binary files /dev/null and b/assets/images/widgets/GridTileBar.png differ diff --git a/assets/images/widgets/Icon.png b/assets/images/widgets/Icon.png new file mode 100644 index 0000000..4aea9bc Binary files /dev/null and b/assets/images/widgets/Icon.png differ diff --git a/assets/images/widgets/ImageIcon.png b/assets/images/widgets/ImageIcon.png new file mode 100644 index 0000000..d458628 Binary files /dev/null and b/assets/images/widgets/ImageIcon.png differ diff --git a/assets/images/widgets/InputChip.png b/assets/images/widgets/InputChip.png new file mode 100644 index 0000000..a597e02 Binary files /dev/null and b/assets/images/widgets/InputChip.png differ diff --git a/assets/images/widgets/ListTile.png b/assets/images/widgets/ListTile.png new file mode 100644 index 0000000..9a2cfa7 Binary files /dev/null and b/assets/images/widgets/ListTile.png differ diff --git a/assets/images/widgets/RadioListTile.png b/assets/images/widgets/RadioListTile.png new file mode 100644 index 0000000..3aef662 Binary files /dev/null and b/assets/images/widgets/RadioListTile.png differ diff --git a/assets/images/widgets/SwitchListTile.png b/assets/images/widgets/SwitchListTile.png new file mode 100644 index 0000000..5cbcaa6 Binary files /dev/null and b/assets/images/widgets/SwitchListTile.png differ diff --git a/assets/images/widgets/Text.png b/assets/images/widgets/Text.png new file mode 100644 index 0000000..0c6fbe0 Binary files /dev/null and b/assets/images/widgets/Text.png differ diff --git a/assets/images/widgets/UserAccountsDrawerHeader.png b/assets/images/widgets/UserAccountsDrawerHeader.png new file mode 100644 index 0000000..ceaed63 Binary files /dev/null and b/assets/images/widgets/UserAccountsDrawerHeader.png differ diff --git a/assets/images/widgets/Visibility.png b/assets/images/widgets/Visibility.png new file mode 100644 index 0000000..8653677 Binary files /dev/null and b/assets/images/widgets/Visibility.png differ diff --git a/assets/images/wy_200x300.jpg b/assets/images/wy_200x300.jpg new file mode 100644 index 0000000..ce7c56b Binary files /dev/null and b/assets/images/wy_200x300.jpg differ diff --git a/assets/images/wy_300x200.jpg b/assets/images/wy_300x200.jpg new file mode 100644 index 0000000..82ad407 Binary files /dev/null and b/assets/images/wy_300x200.jpg differ diff --git a/assets/images/wy_300x200_filter.jpg b/assets/images/wy_300x200_filter.jpg new file mode 100755 index 0000000..847a7ad Binary files /dev/null and b/assets/images/wy_300x200_filter.jpg differ diff --git a/assets/images/wy_30x20.jpg b/assets/images/wy_30x20.jpg new file mode 100644 index 0000000..7795ad4 Binary files /dev/null and b/assets/images/wy_30x20.jpg differ diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..e8efba1 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..399e934 --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..b30a428 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,90 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. +install! 'cocoapods', :disable_input_output_paths => true + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..b379bb9 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,31 @@ +PODS: + - Flutter (1.0.0) + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - sqflite (0.0.1): + - Flutter + - FMDB (~> 2.7.2) + +DEPENDENCIES: + - Flutter (from `Flutter`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + +SPEC CHECKSUMS: + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 + +PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 + +COCOAPODS: 1.8.4 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7742cd1 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,584 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 05552E71DDEE1B210A67DBD4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70F3B239A93318DF93C8360D /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 33DC5F3DBC90F47343297D28 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 70F3B239A93318DF93C8360D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 877C40FF2CB98D47D56F9EDA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F3E5257BAD406E789F4D36B1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 05552E71DDEE1B210A67DBD4 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 02D8EC7DCA94EAA4A49FE3C6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 70F3B239A93318DF93C8360D /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + A408DD350F97C3364EAE65A1 /* Pods */, + 02D8EC7DCA94EAA4A49FE3C6 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; + A408DD350F97C3364EAE65A1 /* Pods */ = { + isa = PBXGroup; + children = ( + 877C40FF2CB98D47D56F9EDA /* Pods-Runner.debug.xcconfig */, + F3E5257BAD406E789F4D36B1 /* Pods-Runner.release.xcconfig */, + 33DC5F3DBC90F47343297D28 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 42D53A7D2712838DCD2AB50C /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 0C4E6FBEBC575BC370836E94 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0C4E6FBEBC575BC370836E94 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 42D53A7D2712838DCD2AB50C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.toly1994.flutterUnit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.toly1994.flutterUnit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.toly1994.flutterUnit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..0954408 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_unit + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..7335fdf --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..84ea85a --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1 @@ +/tools/ \ No newline at end of file diff --git a/lib/app/convert.dart b/lib/app/convert.dart new file mode 100644 index 0000000..d52c8bf --- /dev/null +++ b/lib/app/convert.dart @@ -0,0 +1,30 @@ +import 'package:flutter_unit/app/enums.dart'; + +/// create by 张风捷特烈 on 2020-03-07 +/// contact me by email 1981462002@qq.com +/// 说明: + +class Convert { + + + static WidgetFamily toFamily(int id) { + switch (id) { + case 0: + return WidgetFamily.statelessWidget; + case 1: + return WidgetFamily.statefulWidget; + case 2: + return WidgetFamily.singleChildRenderObjectWidget; + case 3: + return WidgetFamily.multiChildRenderObjectWidget; + case 4: + return WidgetFamily.sliver; + case 5: + return WidgetFamily.proxyWidget; + case 6: + return WidgetFamily.other; + default: + return WidgetFamily.statelessWidget; + } + } +} diff --git a/lib/app/enums.dart b/lib/app/enums.dart new file mode 100644 index 0000000..37a3338 --- /dev/null +++ b/lib/app/enums.dart @@ -0,0 +1,13 @@ +/// create by 张风捷特烈 on 2020-03-07 +/// contact me by email 1981462002@qq.com +/// 说明: + +enum WidgetFamily { + statelessWidget, + statefulWidget, + singleChildRenderObjectWidget, + multiChildRenderObjectWidget, + sliver, + proxyWidget, + other, +} diff --git a/lib/app/res/cons.dart b/lib/app/res/cons.dart new file mode 100644 index 0000000..050fa7e --- /dev/null +++ b/lib/app/res/cons.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/components/permanent/code/highlighter_style.dart'; + +class Cons { + static String version = 'V1.0.0'; + + static const MENU_INFO = ["关于", "帮助", "问题反馈"]; //菜单栏 + static const ICONS_MAP = { + //底栏图标 + "图鉴": TolyIcon.icon_layout, "收藏": TolyIcon.icon_star, +// "喜欢": Icons.favorite, "手册": Icons.class_, +// "我的": Icons.account_circle, + }; + + static const rainbow = [ + 0xffff0000, + 0xffFF7F00, + 0xffFFFF00, + 0xff00FF00, + 0xff00FFFF, + 0xff0000FF, + 0xff8B00FF + ]; + + static const tabColors = [ + 0xff44D1FD, + 0xffFD4F43, + 0xffB375FF, + 0xFF4CAF50, + 0xFFFF9800, + 0xFF00F1F1, + 0xFFDBD83F + ]; + static const tabs = [ + 'Stles', + 'Stful', + 'Scrow', + 'Mcrow', + 'Sliver', + 'Proxy', + 'Other' + ]; //标题列表 + + static const fontFamilySupport = [ + 'local', + 'ComicNeue', + 'IndieFlower', + 'BalooBhai2', + 'Inconsolata', + 'Neucha' + ]; + + static var codeThemeSupport = { + HighlighterStyle.fromColors(HighlighterStyle.gitHub):"GitHub - Power By 张风捷特烈", + HighlighterStyle.fromColors(HighlighterStyle.darkColor):"捷特黑 - Power By 张风捷特烈", + HighlighterStyle.fromColors(HighlighterStyle.lightColor):"捷特白 - Power By 张风捷特烈", + HighlighterStyle.fromColors(HighlighterStyle.zenburn):"zenburn - Power By 张风捷特烈", + HighlighterStyle.fromColors(HighlighterStyle.mf):"mf - Power By MF", + HighlighterStyle.fromColors(HighlighterStyle.solarized):"cst - Power By cst", + }; + + + static final themeColorSupport = { + Colors.red: "毁灭之红", + Colors.orange: "愤怒之橙", + Colors.yellow: "警告之黄", + Colors.green: "伪装之绿", + Colors.blue: "冷漠之蓝", + Colors.indigo: "无限之靛", + Colors.purple: "神秘之紫", + + MaterialColor(0xff2D2D2D, { + 50: Color(0xFF8A8A8A), + 100: Color(0xFF747474), + 200: Color(0xFF616161), + 300: Color(0xFF484848), + 400: Color(0xFF3D3D3D), + 500: Color(0xff2D2D2D), + 600: Color(0xFF252525), + 700: Color(0xFF141414), + 800: Color(0xFF050505), + 900: Color(0xff000000), + }): "归宿之黑" + }; + +} + diff --git a/lib/app/res/sp.dart b/lib/app/res/sp.dart new file mode 100644 index 0000000..b5aeb7d --- /dev/null +++ b/lib/app/res/sp.dart @@ -0,0 +1,13 @@ +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +class SP{ + + static const themeColorIndex = 'theme_color_index'; + static const showBackground = 'show_background'; + static const fontFamily = 'font_family'; + static const codeStyleIndex = 'code_style'; + static const itemStyleIndex = 'item_style_index'; + +} \ No newline at end of file diff --git a/lib/app/router.dart b/lib/app/router.dart new file mode 100644 index 0000000..36a9c35 --- /dev/null +++ b/lib/app/router.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/pages/about/about_me_page.dart'; +import 'package:flutter_unit/views/pages/about/about_app_page.dart'; +import 'package:flutter_unit/views/pages/search/serach_page.dart'; +import 'package:flutter_unit/views/pages/setting/code_style_setting.dart'; +import 'package:flutter_unit/views/pages/setting/font_setting.dart'; +import 'package:flutter_unit/views/pages/setting/item_style_setting.dart'; +import 'package:flutter_unit/views/pages/setting/theme_color_setting.dart'; +import 'package:flutter_unit/views/pages/unit_todo/attr_unit_page.dart'; +import 'package:flutter_unit/views/pages/unit_todo/bug_unit_page.dart'; +import 'package:flutter_unit/views/pages/collect/collect_page.dart'; +import 'package:flutter_unit/views/pages/detail/widget_detail_page.dart'; +import 'package:flutter_unit/views/pages/unit_todo/layout_unit_page.dart'; +import 'package:flutter_unit/views/pages/unit_todo/paint_unit_page.dart'; +import 'package:flutter_unit/views/pages/setting/setting_page.dart'; +import 'package:flutter_unit/views/pages/navigation/unit_navigation.dart'; + +import 'utils/router_utils.dart'; + +class Router { + static const String detail = 'detail'; + static const String home = '/'; + static const String logo = 'logo'; + static const String search = 'search'; + static const String nav = 'nav'; + static const String widget_detail = 'WidgetDetail'; + static const String collect = 'CollectPage'; + + static const String setting = 'SettingPage'; + static const String font_setting = 'FountSettingPage'; + static const String theme_color_setting = 'ThemeColorSettingPage'; + static const String code_style_setting = 'CodeStyleSettingPage'; + static const String item_style_setting = 'ItemStyleSettingPage'; + + static const String attr = 'AttrUnitPage'; + static const String bug = 'BugUnitPage'; + static const String paint = 'PaintUnitPage'; + static const String layout = 'LayoutUnitPage'; + static const String about_me = 'AboutMePage'; + static const String about_app = 'AboutAppPage'; + + static Route generateRoute(RouteSettings settings) { + switch (settings.name) { + //根据名称跳转相应页面 + case widget_detail: + return Right2LeftRouter(child: WidgetDetailPage()); + case search: + return Right2LeftRouter(child: SearchPage()); + case collect: + return Right2LeftRouter(child: CollectPage()); + case nav: + return Left2RightRouter(child: UnitNavigation()); + case setting: + return Right2LeftRouter(child: SettingPage()); + case font_setting: + return Right2LeftRouter(child: FontSettingPage()); + case theme_color_setting: + return Right2LeftRouter(child: ThemeColorSettingPage()); + case code_style_setting: + return Right2LeftRouter(child: CodeStyleSettingPage()); + case item_style_setting: + return Right2LeftRouter(child: ItemStyleSettingPage()); + + case attr: + return Right2LeftRouter(child: AttrUnitPage()); + case bug: + return Right2LeftRouter(child: BugUnitPage()); + case paint: + return Right2LeftRouter(child: PaintUnitPage()); + case layout: + return Right2LeftRouter(child: LayoutUnitPage()); + case about_app: + return Right2LeftRouter(child: AboutAppPage()); + case about_me: + return Right2LeftRouter(child: AboutMePage()); + + default: + return MaterialPageRoute( + builder: (_) => Scaffold( + body: Center( + child: Text('No route defined for ${settings.name}'), + ), + )); + } + } +} diff --git a/lib/app/style/TolyIcon.dart b/lib/app/style/TolyIcon.dart new file mode 100644 index 0000000..681afdc --- /dev/null +++ b/lib/app/style/TolyIcon.dart @@ -0,0 +1,24 @@ +import 'package:flutter/widgets.dart'; +//Power By 张风捷特烈--- Generated file. Do not edit. + +class TolyIcon { + + TolyIcon._(); +static const IconData icon_email = const IconData( 0xe694, fontFamily: "TolyIcon"); +static const IconData icon_github = const IconData( 0xe689, fontFamily: "TolyIcon"); +static const IconData icon_juejin = const IconData( 0xe601, fontFamily: "TolyIcon"); +static const IconData icon_share = const IconData( 0xe613, fontFamily: "TolyIcon"); +static const IconData icon_background = const IconData( 0xe60a, fontFamily: "TolyIcon"); +static const IconData icon_code = const IconData( 0xe70b, fontFamily: "TolyIcon"); +static const IconData icon_item = const IconData( 0xe66f, fontFamily: "TolyIcon"); +static const IconData icon_kafei = const IconData( 0xe6aa, fontFamily: "TolyIcon"); +static const IconData icon_tag = const IconData( 0xe6e7, fontFamily: "TolyIcon"); +static const IconData icon_them = const IconData( 0xe6c2, fontFamily: "TolyIcon"); +static const IconData icon_bug = const IconData( 0xe7af, fontFamily: "TolyIcon"); +static const IconData icon_layout = const IconData( 0xe631, fontFamily: "TolyIcon"); +static const IconData icon_sound = const IconData( 0xe606, fontFamily: "TolyIcon"); +static const IconData icon_search = const IconData( 0xe604, fontFamily: "TolyIcon"); +static const IconData icon_star_ok = const IconData( 0xe6ae, fontFamily: "TolyIcon"); +static const IconData icon_star = const IconData( 0xe609, fontFamily: "TolyIcon"); +static const IconData icon_star_add = const IconData( 0xe68e, fontFamily: "TolyIcon"); +} \ No newline at end of file diff --git a/lib/app/style/shape/coupon_shape_border.dart b/lib/app/style/shape/coupon_shape_border.dart new file mode 100644 index 0000000..d58f1de --- /dev/null +++ b/lib/app/style/shape/coupon_shape_border.dart @@ -0,0 +1,137 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-06 +/// contact me by email 1981462002@qq.com +/// 说明: + +class CouponShapeBorder extends ShapeBorder { + final int holeCount; + final double lineRate; + final bool dash; + final bool hasLine; + final Color color; + final bool hasTopHole; + final bool hasBottomHole; + final double edgeRadius; + + CouponShapeBorder( + {this.holeCount = 6, + this.hasTopHole =true, + this.hasBottomHole =false, + this.lineRate = 0.718, + this.dash = true, + this.hasLine = true, + this.color = Colors.white,this.edgeRadius}); + + @override + EdgeInsetsGeometry get dimensions => null; + + @override + Path getInnerPath(Rect rect, {TextDirection textDirection}) { + return null; + } + + @override + Path getOuterPath(Rect rect, {TextDirection textDirection}) { + var w = rect.width; + var h = rect.height; + + var d = h / (1 + 2 * holeCount); + + var path = Path(); + path.addRect(rect); + + _formHoldLeft(path, d); + + _formHoldRight(path, w, d); + if (hasLine) { + _formHoleTop(path, rect, d); + _formHoleBottom(path, rect, d); + } + if(edgeRadius!=null){ + if(hasTopHole){ + _formHoleTop(path, rect, edgeRadius); + } + if(hasBottomHole){ + _formHoleBottom(path, rect, edgeRadius); + } + + } + path.fillType = PathFillType.evenOdd; + + return path; + } + + void _formHoleBottom(Path path, Rect rect, double d) { + path.addArc( + Rect.fromCenter( + center: Offset(lineRate * rect.width, rect.height), + width: d, + height: d), + pi, + pi); + } + + void _formHoleTop(Path path, Rect rect, double d) { + path.addArc( + Rect.fromCenter( + center: Offset(lineRate * rect.width, 0), width: d, height: d), + 0, + pi); + } + + _formHoldLeft(Path path, double d) { + for (int i = 0; i < holeCount; i++) { + var left = -d / 2; + var top = 0.0 + d + 2 * d * (i); + var right = left + d; + var bottom = top + d; + path.addArc(Rect.fromLTRB(left, top, right, bottom), -pi / 2, pi); + } + } + + _formHoldRight(Path path, double w, double d) { + for (int i = 0; i < holeCount; i++) { + var left = -d / 2 + w; + var top = 0.0 + d + 2 * d * (i); + var right = left + d; + var bottom = top + d; + path.addArc(Rect.fromLTRB(left, top, right, bottom), pi / 2, pi); + } + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { + if(!hasLine) return; + var paint = Paint() + ..color = color + ..strokeWidth = 1.5 + ..style = PaintingStyle.stroke + ..strokeJoin = StrokeJoin.round; + var d = rect.height / (1 + 2 * holeCount); + if (dash) { + _drawDashLine(canvas, Offset(lineRate * rect.width, d / 2), + rect.height / 16, rect.height - 13, paint); + } else { + canvas.drawLine(Offset(lineRate * rect.width, d / 2), + Offset(lineRate * rect.width, rect.height - d / 2), paint); + } + } + + _drawDashLine( + Canvas canvas, Offset start, double count, double length, Paint paint) { + var step = length / count / 2; + for (int i = 0; i < count; i++) { + var offset = start + Offset(0, 2 * step * i); + canvas.drawLine(offset, offset + Offset(0, step), paint); + } + } + + @override + ShapeBorder scale(double t) { + // TODO: implement scale + return null; + } +} diff --git a/lib/app/style/shape/techno_shape.dart b/lib/app/style/shape/techno_shape.dart new file mode 100644 index 0000000..656f5bb --- /dev/null +++ b/lib/app/style/shape/techno_shape.dart @@ -0,0 +1,89 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-06 +/// contact me by email 1981462002@qq.com +/// 说明: 打个洞 +/// offset 洞的偏移量分率 x,y 在 0~1 之间 +/// size 洞的大小 + +class TechnoShapeBorder extends ShapeBorder { + final Path outLinePath = Path(); + final Paint _paint = Paint(); + final Path innerLinePath = Path(); + final Path innerLinePathTop = Path(); + final Color color; + + final cornerWidth; + + final spanWidth; + final storkWidth; + final innerRate; + + TechnoShapeBorder( + {this.color = Colors.green, + this.cornerWidth = 10.0, + this.spanWidth = 2.5, + this.innerRate = 0.15, + this.storkWidth = 1.0}) { + _paint + ..color = color + ..strokeWidth = storkWidth; + } + + @override + EdgeInsetsGeometry get dimensions => null; + + @override + Path getInnerPath(Rect rect, {TextDirection textDirection}) { + var path = Path(); + path.addRRect(RRect.fromRectAndRadius(rect, Radius.circular(5))); + return path; + } + + @override + Path getOuterPath(Rect rect, {TextDirection textDirection}) { + outLinePath + ..moveTo(cornerWidth, 0) + ..lineTo(rect.width - cornerWidth, 0) + ..lineTo(rect.width, cornerWidth) + ..lineTo(rect.width, rect.height - cornerWidth) + ..lineTo(rect.width - cornerWidth, rect.height) + ..lineTo(cornerWidth, rect.height) + ..lineTo(0, rect.height - cornerWidth) + ..lineTo(0, cornerWidth) + ..close(); + innerLinePath + ..moveTo(rect.width / 2, rect.height) + ..relativeLineTo(rect.width * innerRate, 0) + ..relativeLineTo(-spanWidth * 2, -spanWidth) + ..relativeLineTo(-rect.width * innerRate * 2, 0) + ..relativeLineTo(-spanWidth * 2, spanWidth) + ..close(); + return Path.combine(PathOperation.difference, outLinePath, innerLinePath); + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { + canvas.drawPath( + Path.combine(PathOperation.difference, outLinePath, innerLinePath), + _paint..style = PaintingStyle.stroke); + + innerLinePathTop + ..moveTo(rect.width / 2, 0) + ..relativeLineTo(rect.width * innerRate, 0) + ..relativeLineTo(-spanWidth * 2, spanWidth) + ..relativeLineTo(-rect.width * innerRate * 2, 0) + ..relativeLineTo(-spanWidth * 2, -spanWidth) + ..close(); + canvas.drawPath(innerLinePathTop, _paint..style = PaintingStyle.fill); + } + + @override + ShapeBorder scale(double t) { + // TODO: implement scale + return null; + } +} diff --git a/lib/app/utils/Toast.dart b/lib/app/utils/Toast.dart new file mode 100644 index 0000000..054b566 --- /dev/null +++ b/lib/app/utils/Toast.dart @@ -0,0 +1,13 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Toast { + static toast(BuildContext context, String msg, + {duration = const Duration(milliseconds: 600)}) { + Scaffold.of(context).showSnackBar(SnackBar( + content: Text(msg), + duration: duration, + backgroundColor: Theme.of(context).primaryColor, + )); + } +} diff --git a/lib/app/utils/color_utils.dart b/lib/app/utils/color_utils.dart new file mode 100644 index 0000000..e10352c --- /dev/null +++ b/lib/app/utils/color_utils.dart @@ -0,0 +1,86 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'random_provider.dart'; + +//Color randomColor(){/// 用来返回一个随机色 +//var random=Random(); +//var a = random.nextInt(256);//透明度值 +//var r = random.nextInt(256);//红值 +//var g = random.nextInt(256);//绿值 +//var b = random.nextInt(256);//蓝值 +//return Color.fromARGB(a, r, g, b);//生成argb模式的颜色 +//} + +//Color randomColor(int limitA){ +// var random=Random(); +// var a = limitA+random.nextInt(256-limitA);//透明度值 +// var r = random.nextInt(256);//红值 +// var g = random.nextInt(256);//绿值 +// var b = random.nextInt(256);//蓝值 +// return Color.fromARGB(a, r, g, b);//生成argb模式的颜色 +//} + +class ColorUtils { + static Color randomColor({ + int limitA = 120, + int limitR = 0, + int limitG = 0, + int limitB = 0, + }) { + var random = RandomProvider.random; + var a = limitA + random.nextInt(256 - limitA); //透明度值 + var r = limitR + random.nextInt(256 - limitR); //红值 + var g = limitG + random.nextInt(256 - limitG); //绿值 + var b = limitB + random.nextInt(256 - limitB); //蓝值 + return Color.fromARGB(a, r, g, b); //生成argb模式的颜色 + } + + + /// 使用方法: + /// var color1=ColorUtils.parse("#33428A43"); + /// var color2=ColorUtils.parse("33428A43"); + /// var color3=ColorUtils.parse("#428A43"); + ///var color4=ColorUtils.parse("428A43"); + /// + static Color parse(String code) { + Color result =Colors.red; + var value = 0 ; + if (code.contains("#")) { + try { + value = int.parse(code.substring(1), radix: 16); + } catch (e) { + print(e); + } + switch (code.length) { + case 1 + 6://6位 + result = Color(value + 0xFF000000); + break; + case 1 + 8://8位 + result = Color(value); + break; + default: + result =Colors.red; + } + }else { + try { + value = int.parse(code, radix: 16); + } catch (e) { + print(e); + } + switch (code.length) { + case 6: + result = Color(value + 0xFF000000); + break; + case 8: + result = Color(value); + break; + default: + result =Colors.red; + } + } + return result; + } +} + diff --git a/lib/app/utils/pather.dart b/lib/app/utils/pather.dart new file mode 100644 index 0000000..f4ed2dd --- /dev/null +++ b/lib/app/utils/pather.dart @@ -0,0 +1,25 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; + +class Pather { + Pather._(); + + static Pather create = Pather._(); + + Path _path = Path(); + + Path nStarPath(int num, double R, double r, {dx = 0, dy = 0}) { + _path.reset();//重置路径 + double perRad = 2 * pi / num;//每份的角度 + double radA = perRad / 2 / 2;//a角 + double radB = 2 * pi / (num - 1) / 2 - radA / 2 + radA;//起始b角 + _path.moveTo(cos(radA) * R + dx, -sin(radA) * R + dy);//移动到起点 + for (int i = 0; i < num; i++) {//循环生成点,路径连至 + _path.lineTo(cos(radA + perRad * i) * R + dx, -sin(radA + perRad * i) * R + dy); + _path.lineTo(cos(radB + perRad * i) * r + dx, -sin(radB + perRad * i) * r + dy); + } + _path.close(); + return _path; + } +} diff --git a/lib/app/utils/random_provider.dart b/lib/app/utils/random_provider.dart new file mode 100644 index 0000000..11239d8 --- /dev/null +++ b/lib/app/utils/random_provider.dart @@ -0,0 +1,7 @@ +import 'dart:math'; + +class RandomProvider{ + RandomProvider._();//私有化构造 + static final _random= Random(); + static get random =>_random; +} \ No newline at end of file diff --git a/lib/app/utils/router_utils.dart b/lib/app/utils/router_utils.dart new file mode 100644 index 0000000..9bce89c --- /dev/null +++ b/lib/app/utils/router_utils.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; + +//缩放路由动画 +class ScaleRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + ScaleRouter({this.child, this.durationMs = 500,this.curve=Curves.fastOutSlowIn}) + : super( + pageBuilder: (context, animation, secondaryAnimation) => child, + transitionDuration: Duration(milliseconds: durationMs), + transitionsBuilder: (context, a1, a2, child) => + ScaleTransition( + scale: Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: a1, curve: curve)), + child: child, + ), + ); +} +//渐变透明路由动画 +class FadeRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + FadeRouter({this.child, this.durationMs = 500,this.curve=Curves.fastOutSlowIn}) + : super( + pageBuilder: (context, animation, secondaryAnimation) => child, + transitionDuration: Duration(milliseconds: durationMs), + transitionsBuilder: (context, a1, a2, child) => + FadeTransition( + opacity: Tween(begin: 0.1, end: 1.0).animate( + CurvedAnimation(parent: a1, curve:curve,)), + child: child, + )); +} + +//旋转路由动画 +class RotateRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + RotateRouter({this.child, this.durationMs = 500,this.curve=Curves.fastOutSlowIn}) + : super( + pageBuilder: (context, animation, secondaryAnimation) => child, + transitionDuration: Duration(milliseconds: durationMs), + transitionsBuilder: (context, a1, a2, child) => + RotationTransition( + turns: Tween(begin: 0.1, end: 1.0).animate( + CurvedAnimation(parent: a1, curve:curve,)), + child: child, + )); +} + +//右--->左 +class Right2LeftRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + Right2LeftRouter({this.child,this.durationMs=500,this.curve=Curves.fastOutSlowIn}) + :super( + transitionDuration:Duration(milliseconds: durationMs), + pageBuilder:(ctx,a1,a2)=>child, + transitionsBuilder:(ctx,a1,a2, child,) => + SlideTransition( + child: child, + position: Tween( + begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0),).animate( + CurvedAnimation(parent: a1, curve: curve)), + )); +} + +//左--->右 +class Left2RightRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + List mapper; + Left2RightRouter({this.child,this.durationMs=500,this.curve=Curves.fastOutSlowIn}) + :assert(true),super( + transitionDuration:Duration(milliseconds: durationMs), + pageBuilder:(ctx,a1,a2){return child;}, + transitionsBuilder:(ctx,a1,a2,child,) { + return SlideTransition( + position: Tween( + begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0),).animate( + CurvedAnimation(parent: a1, curve: curve)), + child: child + ); + }); +} + +//上--->下 +class Top2BottomRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + Top2BottomRouter({this.child,this.durationMs=500,this.curve=Curves.fastOutSlowIn}) + :super( + transitionDuration:Duration(milliseconds: durationMs), + pageBuilder:(ctx,a1,a2){return child;}, + transitionsBuilder:(ctx,a1,a2, child,) { + return SlideTransition( + position: Tween( + begin: Offset(0.0,-1.0), end: Offset(0.0, 0.0),).animate( + CurvedAnimation(parent: a1, curve: curve)), + child: child + ); + }); +} + +//下--->上 +class Bottom2TopRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + Bottom2TopRouter({this.child,this.durationMs=500,this.curve=Curves.fastOutSlowIn}) + :super( + transitionDuration:Duration(milliseconds: durationMs), + pageBuilder:(ctx,a1,a2)=> child, + transitionsBuilder:(ctx,a1,a2, child,) { + return SlideTransition( + position: Tween( + begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0),).animate( + CurvedAnimation(parent: a1, curve: curve)), + child: child + ); + }); +} + +//缩放+透明+旋转路由动画 +class ScaleFadeRotateRouter extends PageRouteBuilder { + final Widget child; + final int durationMs; + final Curve curve; + ScaleFadeRotateRouter({this.child, this.durationMs = 1000,this.curve=Curves.fastOutSlowIn}) : super( + transitionDuration: Duration(milliseconds: durationMs), + pageBuilder: (ctx, a1, a2)=>child,//页面 + transitionsBuilder: (ctx, a1, a2, Widget child,) => + RotationTransition(//旋转动画 + turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( + parent: a1, + curve: curve, + )), + child: ScaleTransition(//缩放动画 + scale: Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: a1, curve: curve)), + child: FadeTransition(opacity://透明度动画 + Tween(begin: 0.5, end: 1.0).animate(CurvedAnimation(parent: a1, curve: curve)), + child: child,), + ), + )); +} +//无动画 +class NoAnimRouter extends PageRouteBuilder { + final Widget child; + NoAnimRouter({this.child}) + : super( + opaque: false, + pageBuilder: (context, animation, secondaryAnimation) => child, + transitionDuration: Duration(milliseconds: 0), + transitionsBuilder: + (context, animation, secondaryAnimation, child) => child); +} diff --git a/lib/app/utils/toly_utils.dart b/lib/app/utils/toly_utils.dart new file mode 100644 index 0000000..ea48a99 --- /dev/null +++ b/lib/app/utils/toly_utils.dart @@ -0,0 +1,3 @@ +library toly_utils; +export 'color_utils.dart'; +export 'random_provider.dart'; diff --git a/lib/blocs/collect/collect_bloc.dart b/lib/blocs/collect/collect_bloc.dart new file mode 100644 index 0000000..209638c --- /dev/null +++ b/lib/blocs/collect/collect_bloc.dart @@ -0,0 +1,38 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; +import 'package:flutter_unit/repositorys/widget_repository.dart'; + +import 'collect_event.dart'; +import 'collect_state.dart'; + +/// create by 张风捷特烈 on 2020-04-07 +/// contact me by email 1981462002@qq.com +/// 说明: + + + +class CollectBloc extends Bloc { + final WidgetRepository repository; + + CollectBloc({@required this.repository}); + + @override + CollectState get initialState => CollectState(widgets: []); //初始状态 + + @override + Stream mapEventToState( + CollectEvent event, + ) async* { + if (event is ToggleCollectEvent) { + await repository.toggleCollect(event.id); + final widgets = await repository.loadCollectWidgets(); + yield CollectState(widgets: widgets); + } + if( event is EventSetCollectData){ + final widgets = await repository.loadCollectWidgets(); + yield CollectState(widgets: widgets); + } + } +} diff --git a/lib/blocs/collect/collect_event.dart b/lib/blocs/collect/collect_event.dart new file mode 100644 index 0000000..f351d4d --- /dev/null +++ b/lib/blocs/collect/collect_event.dart @@ -0,0 +1,42 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-04-09 +/// contact me by email 1981462002@qq.com +/// 说明: + + +abstract class CollectEvent extends Equatable {} + + +//class EventSetCollect extends CollectEvent { +// final bool collect; +// +// EventSetCollect({this.collect}); +// +// @override +// // TODO: implement props +// List get props => [collect]; +//} + +class EventSetCollectData extends CollectEvent { + List get props => []; +} + + +class ToggleCollectEvent extends CollectEvent { + final int id; + + ToggleCollectEvent({this.id}); + + @override + // TODO: implement props + List get props => [id]; +} + +class LoadCollectEvent extends CollectEvent{ + @override + List get props => []; + +} + diff --git a/lib/blocs/collect/collect_state.dart b/lib/blocs/collect/collect_state.dart new file mode 100644 index 0000000..4c699fd --- /dev/null +++ b/lib/blocs/collect/collect_state.dart @@ -0,0 +1,16 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-04-09 +/// contact me by email 1981462002@qq.com +/// 说明: + +class CollectState extends Equatable { + final List widgets; + + CollectState({this.widgets}); + + @override + // TODO: implement props + List get props => [widgets]; +} diff --git a/lib/blocs/detail/detail_bloc.dart b/lib/blocs/detail/detail_bloc.dart new file mode 100644 index 0000000..2a5185b --- /dev/null +++ b/lib/blocs/detail/detail_bloc.dart @@ -0,0 +1,42 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/repositorys/widget_repository.dart'; + +import 'detail_event.dart'; +import 'detail_state.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: + +class DetailBloc extends Bloc { + final WidgetRepository repository; + + DetailBloc({@required this.repository}); + + @override + DetailState get initialState => DetailEmpty(); + + @override + Stream mapEventToState(DetailEvent event) async* { + if (event is FetchWidgetDetail) { + yield* _mapLoadWidgetToState(event.widgetModel); + } + if(event is ResetDetailState){ + yield DetailEmpty(); + } + } + + Stream _mapLoadWidgetToState( + WidgetModel widgetModel) async* { + try { + final nodes = await this.repository.loadNode(widgetModel); + final links = await this.repository.loadWidget(widgetModel.links); + yield DetailWithData( + widgetModel: widgetModel, nodes: nodes,links: links); + } catch (_) { + yield DetailFailed(); + } + } +} diff --git a/lib/blocs/detail/detail_event.dart b/lib/blocs/detail/detail_event.dart new file mode 100644 index 0000000..9229b87 --- /dev/null +++ b/lib/blocs/detail/detail_event.dart @@ -0,0 +1,33 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: 详情事件 + +abstract class DetailEvent extends Equatable { + const DetailEvent(); + @override + List get props => []; +} + + +class FetchWidgetDetail extends DetailEvent { + final WidgetModel widgetModel; + + const FetchWidgetDetail(this.widgetModel); + + @override + List get props => [widgetModel]; + + @override + String toString() { + return 'SeeWidgetDetail{widgetModel: $widgetModel}'; + } +} + + +class ResetDetailState extends DetailEvent { + +} \ No newline at end of file diff --git a/lib/blocs/detail/detail_state.dart b/lib/blocs/detail/detail_state.dart new file mode 100644 index 0000000..9711255 --- /dev/null +++ b/lib/blocs/detail/detail_state.dart @@ -0,0 +1,36 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/model/node_model.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: 详情状态类 + +abstract class DetailState extends Equatable { + const DetailState(); + + @override + List get props => []; +} + +class DetailWithData extends DetailState { + final WidgetModel widgetModel; + final List links; + final List nodes; + + const DetailWithData({this.widgetModel, this.nodes,this.links}); + + @override + List get props => [widgetModel,nodes]; + + @override + String toString() { + return 'DetailWithData{widget: $widgetModel, nodes: $nodes}'; + } + +} + +class DetailEmpty extends DetailState {} +class DetailFailed extends DetailState {} \ No newline at end of file diff --git a/lib/blocs/global/global_bloc.dart b/lib/blocs/global/global_bloc.dart new file mode 100644 index 0000000..eca10a5 --- /dev/null +++ b/lib/blocs/global/global_bloc.dart @@ -0,0 +1,64 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/storage/app_storage.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/res/sp.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'global_event.dart'; +import 'global_state.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: 全局信息的bloc + +class GlobalBloc extends Bloc { + @override + GlobalState get initialState => GlobalState(); + + final AppStorage storage ; + + + GlobalBloc(this.storage); + + Future get sp => storage.sp; + + @override + Stream mapEventToState(GlobalEvent event) async* { + if (event is EventInitApp) { + yield await storage.initApp(); + } + + if (event is EventSwitchFontFamily) { + var familyIndex = Cons.fontFamilySupport.indexOf(event.family); + await sp + ..setInt(SP.fontFamily, familyIndex); //固化数据 + yield state.copyWith(fontFamily: event.family); + } + + if (event is EventSwitchThemeColor) { + var themeIndex = + Cons.themeColorSupport.keys.toList().indexOf(event.color); + await sp + ..setInt(SP.themeColorIndex, themeIndex); //固化数据 + yield state.copyWith(themeColor: event.color); + } + + if (event is EventSwitchShowBg) { + await sp + ..setBool(SP.showBackground, event.show); //固化数据 + yield state.copyWith(showBackGround: event.show); + } + + if (event is EventSwitchCoderTheme) { + await sp + ..setInt(SP.codeStyleIndex, event.codeStyleIndex); //固化数据 + yield state.copyWith(codeStyleIndex: event.codeStyleIndex); + } + if (event is EventChangeItemStyle) { + await sp + ..setInt(SP.itemStyleIndex, event.index); //固化数据 + print('EventChangeItemStyle+${event.index}'); + yield state.copyWith(itemStyleIndex: event.index); + } + } +} diff --git a/lib/blocs/global/global_event.dart b/lib/blocs/global/global_event.dart new file mode 100644 index 0000000..48ceda7 --- /dev/null +++ b/lib/blocs/global/global_event.dart @@ -0,0 +1,60 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +abstract class GlobalEvent extends Equatable { + const GlobalEvent(); + + @override + List get props => []; +} + +class EventInitApp extends GlobalEvent { + const EventInitApp(); + @override + List get props => []; +} + +class EventSwitchFontFamily extends GlobalEvent { + final String family; + const EventSwitchFontFamily(this.family); + + @override + List get props => [family]; +} + + +class EventSwitchThemeColor extends GlobalEvent { + final MaterialColor color; + + const EventSwitchThemeColor(this.color); + + @override + List get props => [color]; +} + +class EventSwitchCoderTheme extends GlobalEvent { + final int codeStyleIndex; + + const EventSwitchCoderTheme(this.codeStyleIndex); + + @override + List get props => [codeStyleIndex]; +} + +class EventSwitchShowBg extends GlobalEvent { + final bool show; + + const EventSwitchShowBg(this.show); + + @override + List get props => [show]; +} + +class EventChangeItemStyle extends GlobalEvent { + final int index; + + const EventChangeItemStyle(this.index); + + @override + List get props => [index]; +} diff --git a/lib/blocs/global/global_state.dart b/lib/blocs/global/global_state.dart new file mode 100644 index 0000000..a1c4689 --- /dev/null +++ b/lib/blocs/global/global_state.dart @@ -0,0 +1,45 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +class GlobalState extends Equatable { + final String fontFamily; + final MaterialColor themeColor; + final bool showBackGround; + final int codeStyleIndex; + final int itemStyleIndex; + + const GlobalState({ + this.fontFamily = 'ComicNeue', + this.themeColor = Colors.blue, + this.showBackGround = true, + this.codeStyleIndex, + this.itemStyleIndex, + }); + + @override + List get props => + [ fontFamily, themeColor, showBackGround, codeStyleIndex,itemStyleIndex]; + + GlobalState copyWith({ + double height, + String fontFamily, + MaterialColor themeColor, + bool showBackGround, + int codeStyleIndex, + int itemStyleIndex, + }) => + GlobalState( + fontFamily: fontFamily ?? this.fontFamily, + themeColor: themeColor ?? this.themeColor, + showBackGround: showBackGround ?? this.showBackGround, + codeStyleIndex: codeStyleIndex ?? this.codeStyleIndex, + itemStyleIndex: itemStyleIndex ?? this.itemStyleIndex, + ); + + @override + String toString() { + return 'GlobalState{ fontFamily: $fontFamily, themeColor: $themeColor, showBackGround: $showBackGround, codeStyleIndex: $codeStyleIndex, itemStyleIndex: $itemStyleIndex}'; + } + + +} diff --git a/lib/blocs/search/search_bloc.dart b/lib/blocs/search/search_bloc.dart new file mode 100644 index 0000000..f57f45f --- /dev/null +++ b/lib/blocs/search/search_bloc.dart @@ -0,0 +1,47 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/repositorys/widget_repository.dart'; + +import 'search_event.dart'; +import 'search_state.dart'; +import 'package:bloc/bloc.dart'; +import 'package:rxdart/rxdart.dart'; + +class SearchBloc extends Bloc { + final WidgetRepository repository; + + SearchBloc({@required this.repository}); + @override + SearchState get initialState => SearchStateNoSearch();//初始状态 + + + @override + Stream transformEvents( + Stream events, + Stream Function(SearchEvent event) next,) { + return super.transformEvents(events + .debounceTime(Duration(milliseconds: 500),), + next, + ); + } + + @override + Stream mapEventToState(SearchEvent event,) async* { + if (event is EventTextChanged) { + if (event.args.name.isEmpty&&event.args.stars.every((e)=>e==-1)) { + yield SearchStateNoSearch(); + } else { + yield SearchStateLoading(); + try { + final results = await repository.searchWidgets(event.args); + yield results.length==0?SearchStateEmpty():SearchStateSuccess(results); + print('mapEventToState'); + } catch (error) { + print(error); + yield SearchStateError(); + } + } + } + } +} \ No newline at end of file diff --git a/lib/blocs/search/search_event.dart b/lib/blocs/search/search_event.dart new file mode 100644 index 0000000..1fdb5e0 --- /dev/null +++ b/lib/blocs/search/search_event.dart @@ -0,0 +1,12 @@ + + +import 'package:flutter_unit/storage/widget_dao.dart'; + +abstract class SearchEvent{//事件基 + const SearchEvent(); +} + +class EventTextChanged extends SearchEvent { + final SearchArgs args;//参数 + const EventTextChanged({this.args}); +} diff --git a/lib/blocs/search/search_state.dart b/lib/blocs/search/search_state.dart new file mode 100644 index 0000000..60254a3 --- /dev/null +++ b/lib/blocs/search/search_state.dart @@ -0,0 +1,19 @@ + + +import 'package:flutter_unit/model/widget_model.dart'; + +abstract class SearchState {//基态 + const SearchState(); +} + +class SearchStateNoSearch extends SearchState {}//无搜索状态 + +class SearchStateEmpty extends SearchState {}//结果为空 + +class SearchStateLoading extends SearchState {}//加载中 +class SearchStateError extends SearchState {}//异常 + +class SearchStateSuccess extends SearchState {//有结果 + final List result;//搜索结果 + const SearchStateSuccess(this.result); +} diff --git a/lib/blocs/widgets/home_bloc.dart b/lib/blocs/widgets/home_bloc.dart new file mode 100644 index 0000000..9e8f451 --- /dev/null +++ b/lib/blocs/widgets/home_bloc.dart @@ -0,0 +1,44 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/repositorys/widget_repository.dart'; + +import 'home_event.dart'; +import 'home_state.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: + +class HomeBloc extends Bloc { + final WidgetRepository repository; + + HomeBloc({@required this.repository}); + + @override + HomeState get initialState => WidgetsLoading( + homeColor: Color(Cons.tabColors[0])); + + @override + Stream mapEventToState(HomeEvent event) async* { + if (event is EventTabTap) { + yield* _mapLoadWidgetToState(event.family); + } + } + + Stream _mapLoadWidgetToState(WidgetFamily family) async* { + try { + final widgets = await this.repository.loadWidgets(family); + yield WidgetsLoaded( + widgets: widgets, + homeColor: Color(Cons.tabColors[family.index])); + } catch (err) { + print(err); + yield WidgetsLoadFailed(); + } + } +} diff --git a/lib/blocs/widgets/home_event.dart b/lib/blocs/widgets/home_event.dart new file mode 100644 index 0000000..690565b --- /dev/null +++ b/lib/blocs/widgets/home_event.dart @@ -0,0 +1,25 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/storage/po/widget_po.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: + +abstract class HomeEvent extends Equatable { + const HomeEvent(); + @override + List get props => []; +} + +class EventTabTap extends HomeEvent { + final WidgetFamily family; + + EventTabTap(this.family); + +} + + diff --git a/lib/blocs/widgets/home_state.dart b/lib/blocs/widgets/home_state.dart new file mode 100644 index 0000000..45edb67 --- /dev/null +++ b/lib/blocs/widgets/home_state.dart @@ -0,0 +1,45 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: widget状态类 + +abstract class HomeState extends Equatable { + final Color homeColor; + + const HomeState({this.homeColor}); + + @override + List get props => [homeColor]; +} + +class WidgetsLoading extends HomeState { + const WidgetsLoading({homeColor}) + : super(homeColor: homeColor); + @override + List get props => [homeColor]; +} + +class WidgetsLoaded extends HomeState { + final List widgets; + + const WidgetsLoaded({homeColor, barHeight, this.widgets = const []}) + : super(homeColor: homeColor); + + @override + List get props => [homeColor,widgets]; + + @override + String toString() { + return 'WidgetsLoaded{widgets: $widgets}'; + } +} + +class WidgetsLoadFailed extends HomeState { + const WidgetsLoadFailed({homeColor, barHeight}) + : super(homeColor: homeColor); + @override + List get props => [homeColor]; +} diff --git a/lib/components/flutter/no_shadow_tab_bar.dart b/lib/components/flutter/no_shadow_tab_bar.dart new file mode 100644 index 0000000..a1ae1ae --- /dev/null +++ b/lib/components/flutter/no_shadow_tab_bar.dart @@ -0,0 +1,1345 @@ +/// create by 张风捷特烈 on 2020-03-16 +/// contact me by email 1981462002@qq.com +/// 说明: + +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:ui' show lerpDouble; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter/gestures.dart' show DragStartBehavior; + + +const double _kTabHeight = 46.0; +const double _kTextAndIconTabHeight = 72.0; + +/// Defines how the bounds of the selected tab indicator are computed. +/// +/// See also: +/// +/// * [TabBar], which displays a row of tabs. +/// * [TabBarView], which displays a widget for the currently selected tab. +/// * [TabBar.indicator], which defines the appearance of the selected tab +/// indicator relative to the tab's bounds. +enum TabBarIndicatorSize { + /// The tab indicator's bounds are as wide as the space occupied by the tab + /// in the tab bar: from the right edge of the previous tab to the left edge + /// of the next tab. + tab, + + /// The tab's bounds are only as wide as the (centered) tab widget itself. + /// + /// This value is used to align the tab's label, typically a [Tab] + /// widget's text or icon, with the selected tab indicator. + label, +} + +class _TabStyle extends AnimatedWidget { + const _TabStyle({ + Key key, + Animation animation, + this.selected, + this.labelColor, + this.unselectedLabelColor, + this.labelStyle, + this.unselectedLabelStyle, + @required this.child, + }) : super(key: key, listenable: animation); + + final TextStyle labelStyle; + final TextStyle unselectedLabelStyle; + final bool selected; + final Color labelColor; + final Color unselectedLabelColor; + final Widget child; + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + final TabBarTheme tabBarTheme = TabBarTheme.of(context); + final Animation animation = listenable; + + // To enable TextStyle.lerp(style1, style2, value), both styles must have + // the same value of inherit. Force that to be inherit=true here. + final TextStyle defaultStyle = (labelStyle + ?? tabBarTheme.labelStyle + ?? themeData.primaryTextTheme.body2 + ).copyWith(inherit: true); + final TextStyle defaultUnselectedStyle = (unselectedLabelStyle + ?? tabBarTheme.unselectedLabelStyle + ?? labelStyle + ?? themeData.primaryTextTheme.body2 + ).copyWith(inherit: true); + final TextStyle textStyle = selected + ? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value) + : TextStyle.lerp(defaultUnselectedStyle, defaultStyle, animation.value); + + final Color selectedColor = labelColor + ?? tabBarTheme.labelColor + ?? themeData.primaryTextTheme.body2.color; + final Color unselectedColor = unselectedLabelColor + ?? tabBarTheme.unselectedLabelColor + ?? selectedColor.withAlpha(0xB2); // 70% alpha + final Color color = selected + ? Color.lerp(selectedColor, unselectedColor, animation.value) + : Color.lerp(unselectedColor, selectedColor, animation.value); + + return DefaultTextStyle( + style: textStyle.copyWith(color: color), + child: IconTheme.merge( + data: IconThemeData( + size: 24.0, + color: color, + ), + child: child, + ), + ); + } +} + +typedef _LayoutCallback = void Function(List xOffsets, TextDirection textDirection, double width); + +class _TabLabelBarRenderer extends RenderFlex { + _TabLabelBarRenderer({ + List children, + @required Axis direction, + @required MainAxisSize mainAxisSize, + @required MainAxisAlignment mainAxisAlignment, + @required CrossAxisAlignment crossAxisAlignment, + @required TextDirection textDirection, + @required VerticalDirection verticalDirection, + @required this.onPerformLayout, + }) : assert(onPerformLayout != null), + assert(textDirection != null), + super( + children: children, + direction: direction, + mainAxisSize: mainAxisSize, + mainAxisAlignment: mainAxisAlignment, + crossAxisAlignment: crossAxisAlignment, + textDirection: textDirection, + verticalDirection: verticalDirection, + ); + + _LayoutCallback onPerformLayout; + + @override + void performLayout() { + super.performLayout(); + // xOffsets will contain childCount+1 values, giving the offsets of the + // leading edge of the first tab as the first value, of the leading edge of + // the each subsequent tab as each subsequent value, and of the trailing + // edge of the last tab as the last value. + RenderBox child = firstChild; + final List xOffsets = []; + while (child != null) { + final FlexParentData childParentData = child.parentData; + xOffsets.add(childParentData.offset.dx); + assert(child.parentData == childParentData); + child = childParentData.nextSibling; + } + assert(textDirection != null); + switch (textDirection) { + case TextDirection.rtl: + xOffsets.insert(0, size.width); + break; + case TextDirection.ltr: + xOffsets.add(size.width); + break; + } + onPerformLayout(xOffsets, textDirection, size.width); + } +} + +// This class and its renderer class only exist to report the widths of the tabs +// upon layout. The tab widths are only used at paint time (see _IndicatorPainter) +// or in response to input. +class _TabLabelBar extends Flex { + _TabLabelBar({ + Key key, + List children = const [], + this.onPerformLayout, + }) : super( + key: key, + children: children, + direction: Axis.horizontal, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + verticalDirection: VerticalDirection.down, + ); + + final _LayoutCallback onPerformLayout; + + @override + RenderFlex createRenderObject(BuildContext context) { + return _TabLabelBarRenderer( + direction: direction, + mainAxisAlignment: mainAxisAlignment, + mainAxisSize: mainAxisSize, + crossAxisAlignment: crossAxisAlignment, + textDirection: getEffectiveTextDirection(context), + verticalDirection: verticalDirection, + onPerformLayout: onPerformLayout, + ); + } + + @override + void updateRenderObject(BuildContext context, _TabLabelBarRenderer renderObject) { + super.updateRenderObject(context, renderObject); + renderObject.onPerformLayout = onPerformLayout; + } +} + +double _indexChangeProgress(TabController controller) { + final double controllerValue = controller.animation.value; + final double previousIndex = controller.previousIndex.toDouble(); + final double currentIndex = controller.index.toDouble(); + + // The controller's offset is changing because the user is dragging the + // TabBarView's PageView to the left or right. + if (!controller.indexIsChanging) + return (currentIndex - controllerValue).abs().clamp(0.0, 1.0); + + // The TabController animation's value is changing from previousIndex to currentIndex. + return (controllerValue - currentIndex).abs() / (currentIndex - previousIndex).abs(); +} + +class _IndicatorPainter extends CustomPainter { + _IndicatorPainter({ + @required this.controller, + @required this.indicator, + @required this.indicatorSize, + @required this.tabKeys, + _IndicatorPainter old, + }) : assert(controller != null), + assert(indicator != null), + super(repaint: controller.animation) { + if (old != null) + saveTabOffsets(old._currentTabOffsets, old._currentTextDirection); + } + + final TabController controller; + final Decoration indicator; + final TabBarIndicatorSize indicatorSize; + final List tabKeys; + + List _currentTabOffsets; + TextDirection _currentTextDirection; + Rect _currentRect; + BoxPainter _painter; + bool _needsPaint = false; + void markNeedsPaint() { + _needsPaint = true; + } + + void dispose() { + _painter?.dispose(); + } + + void saveTabOffsets(List tabOffsets, TextDirection textDirection) { + _currentTabOffsets = tabOffsets; + _currentTextDirection = textDirection; + } + + // _currentTabOffsets[index] is the offset of the start edge of the tab at index, and + // _currentTabOffsets[_currentTabOffsets.length] is the end edge of the last tab. + int get maxTabIndex => _currentTabOffsets.length - 2; + + double centerOf(int tabIndex) { + assert(_currentTabOffsets != null); + assert(_currentTabOffsets.isNotEmpty); + assert(tabIndex >= 0); + assert(tabIndex <= maxTabIndex); + return (_currentTabOffsets[tabIndex] + _currentTabOffsets[tabIndex + 1]) / 2.0; + } + + Rect indicatorRect(Size tabBarSize, int tabIndex) { + assert(_currentTabOffsets != null); + assert(_currentTextDirection != null); + assert(_currentTabOffsets.isNotEmpty); + assert(tabIndex >= 0); + assert(tabIndex <= maxTabIndex); + double tabLeft, tabRight; + switch (_currentTextDirection) { + case TextDirection.rtl: + tabLeft = _currentTabOffsets[tabIndex + 1]; + tabRight = _currentTabOffsets[tabIndex]; + break; + case TextDirection.ltr: + tabLeft = _currentTabOffsets[tabIndex]; + tabRight = _currentTabOffsets[tabIndex + 1]; + break; + } + + if (indicatorSize == TabBarIndicatorSize.label) { + final double tabWidth = tabKeys[tabIndex].currentContext.size.width; + final double delta = ((tabRight - tabLeft) - tabWidth) / 2.0; + tabLeft += delta; + tabRight -= delta; + } + + return Rect.fromLTWH(tabLeft, 0.0, tabRight - tabLeft, tabBarSize.height); + } + + @override + void paint(Canvas canvas, Size size) { + _needsPaint = false; + _painter ??= indicator.createBoxPainter(markNeedsPaint); + + if (controller.indexIsChanging) { + // The user tapped on a tab, the tab controller's animation is running. + final Rect targetRect = indicatorRect(size, controller.index); + _currentRect = Rect.lerp(targetRect, _currentRect ?? targetRect, _indexChangeProgress(controller)); + } else { + // The user is dragging the TabBarView's PageView left or right. + final int currentIndex = controller.index; + final Rect previous = currentIndex > 0 ? indicatorRect(size, currentIndex - 1) : null; + final Rect middle = indicatorRect(size, currentIndex); + final Rect next = currentIndex < maxTabIndex ? indicatorRect(size, currentIndex + 1) : null; + final double index = controller.index.toDouble(); + final double value = controller.animation.value; + if (value == index - 1.0) + _currentRect = previous ?? middle; + else if (value == index + 1.0) + _currentRect = next ?? middle; + else if (value == index) + _currentRect = middle; + else if (value < index) + _currentRect = previous == null ? middle : Rect.lerp(middle, previous, index - value); + else + _currentRect = next == null ? middle : Rect.lerp(middle, next, value - index); + } + assert(_currentRect != null); + + final ImageConfiguration configuration = ImageConfiguration( + size: _currentRect.size, + textDirection: _currentTextDirection, + ); + _painter.paint(canvas, _currentRect.topLeft, configuration); + } + + static bool _tabOffsetsEqual(List a, List b) { + // TODO(shihaohong): The following null check should be replaced when a fix + // for https://github.com/flutter/flutter/issues/40014 is available. + if (a == null || b == null || a.length != b.length) + return false; + for (int i = 0; i < a.length; i += 1) { + if (a[i] != b[i]) + return false; + } + return true; + } + + @override + bool shouldRepaint(_IndicatorPainter old) { + return _needsPaint + || controller != old.controller + || indicator != old.indicator + || tabKeys.length != old.tabKeys.length + || (!_tabOffsetsEqual(_currentTabOffsets, old._currentTabOffsets)) + || _currentTextDirection != old._currentTextDirection; + } +} + +class _ChangeAnimation extends Animation with AnimationWithParentMixin { + _ChangeAnimation(this.controller); + + final TabController controller; + + @override + Animation get parent => controller.animation; + + @override + void removeStatusListener(AnimationStatusListener listener) { + if (parent != null) + super.removeStatusListener(listener); + } + + @override + void removeListener(VoidCallback listener) { + if (parent != null) + super.removeListener(listener); + } + + @override + double get value => _indexChangeProgress(controller); +} + +class _DragAnimation extends Animation with AnimationWithParentMixin { + _DragAnimation(this.controller, this.index); + + final TabController controller; + final int index; + + @override + Animation get parent => controller.animation; + + @override + void removeStatusListener(AnimationStatusListener listener) { + if (parent != null) + super.removeStatusListener(listener); + } + + @override + void removeListener(VoidCallback listener) { + if (parent != null) + super.removeListener(listener); + } + + @override + double get value { + assert(!controller.indexIsChanging); + return (controller.animation.value - index.toDouble()).abs().clamp(0.0, 1.0); + } +} + +// This class, and TabBarScrollController, only exist to handle the case +// where a scrollable TabBar has a non-zero initialIndex. In that case we can +// only compute the scroll position's initial scroll offset (the "correct" +// pixels value) after the TabBar viewport width and scroll limits are known. +class _TabBarScrollPosition extends ScrollPositionWithSingleContext { + _TabBarScrollPosition({ + ScrollPhysics physics, + ScrollContext context, + ScrollPosition oldPosition, + this.tabBar, + }) : super( + physics: physics, + context: context, + initialPixels: null, + oldPosition: oldPosition, + ); + + final _TabBarState tabBar; + + bool _initialViewportDimensionWasZero; + + @override + bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { + bool result = true; + if (_initialViewportDimensionWasZero != true) { + // If the viewport never had a non-zero dimension, we just want to jump + // to the initial scroll position to avoid strange scrolling effects in + // release mode: In release mode, the viewport temporarily may have a + // dimension of zero before the actual dimension is calculated. In that + // scenario, setting the actual dimension would cause a strange scroll + // effect without this guard because the super call below would starts a + // ballistic scroll activity. + assert(viewportDimension != null); + _initialViewportDimensionWasZero = viewportDimension != 0.0; + correctPixels(tabBar._initialScrollOffset(viewportDimension, minScrollExtent, maxScrollExtent)); + result = false; + } + return super.applyContentDimensions(minScrollExtent, maxScrollExtent) && result; + } +} + +// This class, and TabBarScrollPosition, only exist to handle the case +// where a scrollable TabBar has a non-zero initialIndex. +class _TabBarScrollController extends ScrollController { + _TabBarScrollController(this.tabBar); + + final _TabBarState tabBar; + + @override + ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition oldPosition) { + return _TabBarScrollPosition( + physics: physics, + context: context, + oldPosition: oldPosition, + tabBar: tabBar, + ); + } +} + +/// A material design widget that displays a horizontal row of tabs. +/// +/// Typically created as the [AppBar.bottom] part of an [AppBar] and in +/// conjunction with a [TabBarView]. +/// +/// If a [TabController] is not provided, then a [DefaultTabController] ancestor +/// must be provided instead. The tab controller's [TabController.length] must +/// equal the length of the [tabs] list and the length of the +/// [TabBarView.children] list. +/// +/// Requires one of its ancestors to be a [Material] widget. +/// +/// Uses values from [TabBarTheme] if it is set in the current context. +/// +/// To see a sample implementation, visit the [TabController] documentation. +/// +/// See also: +/// +/// * [TabBarView], which displays page views that correspond to each tab. +class NoShadowTabBar extends StatefulWidget implements PreferredSizeWidget { + /// Creates a material design tab bar. + /// + /// The [tabs] argument must not be null and its length must match the [controller]'s + /// [TabController.length]. + /// + /// If a [TabController] is not provided, then there must be a + /// [DefaultTabController] ancestor. + /// + /// The [indicatorWeight] parameter defaults to 2, and must not be null. + /// + /// The [indicatorPadding] parameter defaults to [EdgeInsets.zero], and must not be null. + /// + /// If [indicator] is not null, then [indicatorWeight], [indicatorPadding], and + /// [indicatorColor] are ignored. + const NoShadowTabBar({ + Key key, + @required this.tabs, + this.controller, + this.isScrollable = false, + this.indicatorColor, + this.indicatorWeight = 2.0, + this.indicatorPadding = EdgeInsets.zero, + this.indicator, + this.indicatorSize, + this.labelColor, + this.labelStyle, + this.labelPadding, + this.unselectedLabelColor, + this.unselectedLabelStyle, + this.dragStartBehavior = DragStartBehavior.start, + this.onTap, + }) : assert(tabs != null), + assert(isScrollable != null), + assert(dragStartBehavior != null), + assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)), + assert(indicator != null || (indicatorPadding != null)), + super(key: key); + + /// Typically a list of two or more [Tab] widgets. + /// + /// The length of this list must match the [controller]'s [TabController.length] + /// and the length of the [TabBarView.children] list. + final List tabs; + + /// This widget's selection and animation state. + /// + /// If [TabController] is not provided, then the value of [DefaultTabController.of] + /// will be used. + final TabController controller; + + /// Whether this tab bar can be scrolled horizontally. + /// + /// If [isScrollable] is true, then each tab is as wide as needed for its label + /// and the entire [TabBar] is scrollable. Otherwise each tab gets an equal + /// share of the available space. + final bool isScrollable; + + /// The color of the line that appears below the selected tab. + /// + /// If this parameter is null, then the value of the Theme's indicatorColor + /// property is used. + /// + /// If [indicator] is specified, this property is ignored. + final Color indicatorColor; + + /// The thickness of the line that appears below the selected tab. + /// + /// The value of this parameter must be greater than zero and its default + /// value is 2.0. + /// + /// If [indicator] is specified, this property is ignored. + final double indicatorWeight; + + /// The horizontal padding for the line that appears below the selected tab. + /// + /// For [isScrollable] tab bars, specifying [kTabLabelPadding] will align + /// the indicator with the tab's text for [Tab] widgets and all but the + /// shortest [Tab.text] values. + /// + /// The [EdgeInsets.top] and [EdgeInsets.bottom] values of the + /// [indicatorPadding] are ignored. + /// + /// The default value of [indicatorPadding] is [EdgeInsets.zero]. + /// + /// If [indicator] is specified, this property is ignored. + final EdgeInsetsGeometry indicatorPadding; + + /// Defines the appearance of the selected tab indicator. + /// + /// If [indicator] is specified, the [indicatorColor], [indicatorWeight], + /// and [indicatorPadding] properties are ignored. + /// + /// The default, underline-style, selected tab indicator can be defined with + /// [UnderlineTabIndicator]. + /// + /// The indicator's size is based on the tab's bounds. If [indicatorSize] + /// is [TabBarIndicatorSize.tab] the tab's bounds are as wide as the space + /// occupied by the tab in the tab bar. If [indicatorSize] is + /// [TabBarIndicatorSize.label], then the tab's bounds are only as wide as + /// the tab widget itself. + final Decoration indicator; + + /// Defines how the selected tab indicator's size is computed. + /// + /// The size of the selected tab indicator is defined relative to the + /// tab's overall bounds if [indicatorSize] is [TabBarIndicatorSize.tab] + /// (the default) or relative to the bounds of the tab's widget if + /// [indicatorSize] is [TabBarIndicatorSize.label]. + /// + /// The selected tab's location appearance can be refined further with + /// the [indicatorColor], [indicatorWeight], [indicatorPadding], and + /// [indicator] properties. + final TabBarIndicatorSize indicatorSize; + + /// The color of selected tab labels. + /// + /// Unselected tab labels are rendered with the same color rendered at 70% + /// opacity unless [unselectedLabelColor] is non-null. + /// + /// If this parameter is null, then the color of the [ThemeData.primaryTextTheme]'s + /// body2 text color is used. + final Color labelColor; + + /// The color of unselected tab labels. + /// + /// If this property is null, unselected tab labels are rendered with the + /// [labelColor] with 70% opacity. + final Color unselectedLabelColor; + + /// The text style of the selected tab labels. + /// + /// If [unselectedLabelStyle] is null, then this text style will be used for + /// both selected and unselected label styles. + /// + /// If this property is null, then the text style of the + /// [ThemeData.primaryTextTheme]'s body2 definition is used. + final TextStyle labelStyle; + + /// The padding added to each of the tab labels. + /// + /// If this property is null, then kTabLabelPadding is used. + final EdgeInsetsGeometry labelPadding; + + /// The text style of the unselected tab labels + /// + /// If this property is null, then the [labelStyle] value is used. If [labelStyle] + /// is null, then the text style of the [ThemeData.primaryTextTheme]'s + /// body2 definition is used. + final TextStyle unselectedLabelStyle; + + /// {@macro flutter.widgets.scrollable.dragStartBehavior} + final DragStartBehavior dragStartBehavior; + + /// An optional callback that's called when the [TabBar] is tapped. + /// + /// The callback is applied to the index of the tab where the tap occurred. + /// + /// This callback has no effect on the default handling of taps. It's for + /// applications that want to do a little extra work when a tab is tapped, + /// even if the tap doesn't change the TabController's index. TabBar [onTap] + /// callbacks should not make changes to the TabController since that would + /// interfere with the default tap handler. + final ValueChanged onTap; + + /// A size whose height depends on if the tabs have both icons and text. + /// + /// [AppBar] uses this size to compute its own preferred size. + @override + Size get preferredSize { + for (Widget item in tabs) { + if (item is Tab) { + final Tab tab = item; + if (tab.text != null && tab.icon != null) + return Size.fromHeight(_kTextAndIconTabHeight + indicatorWeight); + } + } + return Size.fromHeight(_kTabHeight + indicatorWeight); + } + + @override + _TabBarState createState() => _TabBarState(); +} + +class _TabBarState extends State { + ScrollController _scrollController; + TabController _controller; + _IndicatorPainter _indicatorPainter; + int _currentIndex; + double _tabStripWidth; + List _tabKeys; + + @override + void initState() { + super.initState(); + // If indicatorSize is TabIndicatorSize.label, _tabKeys[i] is used to find + // the width of tab widget i. See _IndicatorPainter.indicatorRect(). + _tabKeys = widget.tabs.map((Widget tab) => GlobalKey()).toList(); + } + + Decoration get _indicator { + if (widget.indicator != null) + return widget.indicator; + final TabBarTheme tabBarTheme = TabBarTheme.of(context); + if (tabBarTheme.indicator != null) + return tabBarTheme.indicator; + + Color color = widget.indicatorColor ?? Theme.of(context).indicatorColor; + // ThemeData tries to avoid this by having indicatorColor avoid being the + // primaryColor. However, it's possible that the tab bar is on a + // Material that isn't the primaryColor. In that case, if the indicator + // color ends up matching the material's color, then this overrides it. + // When that happens, automatic transitions of the theme will likely look + // ugly as the indicator color suddenly snaps to white at one end, but it's + // not clear how to avoid that any further. + // + // The material's color might be null (if it's a transparency). In that case + // there's no good way for us to find out what the color is so we don't. + if (color.value == Material.of(context).color?.value) + color = Colors.white; + + return UnderlineTabIndicator( + insets: widget.indicatorPadding, + borderSide: BorderSide( + width: widget.indicatorWeight, + color: color, + ), + ); + } + + // If the TabBar is rebuilt with a new tab controller, the caller should + // dispose the old one. In that case the old controller's animation will be + // null and should not be accessed. + bool get _controllerIsValid => _controller?.animation != null; + + void _updateTabController() { + final TabController newController = widget.controller ?? DefaultTabController.of(context); + assert(() { + if (newController == null) { + throw FlutterError( + 'No TabController for ${widget.runtimeType}.\n' + 'When creating a ${widget.runtimeType}, you must either provide an explicit ' + 'TabController using the "controller" property, or you must ensure that there ' + 'is a DefaultTabController above the ${widget.runtimeType}.\n' + 'In this case, there was neither an explicit controller nor a default controller.' + ); + } + return true; + }()); + + if (newController == _controller) + return; + + if (_controllerIsValid) { + _controller.animation.removeListener(_handleTabControllerAnimationTick); + _controller.removeListener(_handleTabControllerTick); + } + _controller = newController; + if (_controller != null) { + _controller.animation.addListener(_handleTabControllerAnimationTick); + _controller.addListener(_handleTabControllerTick); + _currentIndex = _controller.index; + } + } + + void _initIndicatorPainter() { + _indicatorPainter = !_controllerIsValid ? null : _IndicatorPainter( + controller: _controller, + indicator: _indicator, + indicatorSize: widget.indicatorSize ?? TabBarTheme.of(context).indicatorSize, + tabKeys: _tabKeys, + old: _indicatorPainter, + ); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + assert(debugCheckHasMaterial(context)); + _updateTabController(); + _initIndicatorPainter(); + } + + @override + void didUpdateWidget(NoShadowTabBar oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.controller != oldWidget.controller) { + _updateTabController(); + _initIndicatorPainter(); + } else if (widget.indicatorColor != oldWidget.indicatorColor || + widget.indicatorWeight != oldWidget.indicatorWeight || + widget.indicatorSize != oldWidget.indicatorSize || + widget.indicator != oldWidget.indicator) { + _initIndicatorPainter(); + } + + if (widget.tabs.length > oldWidget.tabs.length) { + final int delta = widget.tabs.length - oldWidget.tabs.length; + _tabKeys.addAll(List.generate(delta, (int n) => GlobalKey())); + } else if (widget.tabs.length < oldWidget.tabs.length) { + _tabKeys.removeRange(widget.tabs.length, oldWidget.tabs.length); + } + } + + @override + void dispose() { + _indicatorPainter.dispose(); + if (_controllerIsValid) { + _controller.animation.removeListener(_handleTabControllerAnimationTick); + _controller.removeListener(_handleTabControllerTick); + } + _controller = null; + // We don't own the _controller Animation, so it's not disposed here. + super.dispose(); + } + + int get maxTabIndex => _indicatorPainter.maxTabIndex; + + double _tabScrollOffset(int index, double viewportWidth, double minExtent, double maxExtent) { + if (!widget.isScrollable) + return 0.0; + double tabCenter = _indicatorPainter.centerOf(index); + switch (Directionality.of(context)) { + case TextDirection.rtl: + tabCenter = _tabStripWidth - tabCenter; + break; + case TextDirection.ltr: + break; + } + return (tabCenter - viewportWidth / 2.0).clamp(minExtent, maxExtent); + } + + double _tabCenteredScrollOffset(int index) { + final ScrollPosition position = _scrollController.position; + return _tabScrollOffset(index, position.viewportDimension, position.minScrollExtent, position.maxScrollExtent); + } + + double _initialScrollOffset(double viewportWidth, double minExtent, double maxExtent) { + return _tabScrollOffset(_currentIndex, viewportWidth, minExtent, maxExtent); + } + + void _scrollToCurrentIndex() { + final double offset = _tabCenteredScrollOffset(_currentIndex); + _scrollController.animateTo(offset, duration: kTabScrollDuration, curve: Curves.ease); + } + + void _scrollToControllerValue() { + final double leadingPosition = _currentIndex > 0 ? _tabCenteredScrollOffset(_currentIndex - 1) : null; + final double middlePosition = _tabCenteredScrollOffset(_currentIndex); + final double trailingPosition = _currentIndex < maxTabIndex ? _tabCenteredScrollOffset(_currentIndex + 1) : null; + + final double index = _controller.index.toDouble(); + final double value = _controller.animation.value; + double offset; + if (value == index - 1.0) + offset = leadingPosition ?? middlePosition; + else if (value == index + 1.0) + offset = trailingPosition ?? middlePosition; + else if (value == index) + offset = middlePosition; + else if (value < index) + offset = leadingPosition == null ? middlePosition : lerpDouble(middlePosition, leadingPosition, index - value); + else + offset = trailingPosition == null ? middlePosition : lerpDouble(middlePosition, trailingPosition, value - index); + + _scrollController.jumpTo(offset); + } + + void _handleTabControllerAnimationTick() { + assert(mounted); + if (!_controller.indexIsChanging && widget.isScrollable) { + // Sync the TabBar's scroll position with the TabBarView's PageView. + _currentIndex = _controller.index; + _scrollToControllerValue(); + } + } + + void _handleTabControllerTick() { + if (_controller.index != _currentIndex) { + _currentIndex = _controller.index; + if (widget.isScrollable) + _scrollToCurrentIndex(); + } + setState(() { + // Rebuild the tabs after a (potentially animated) index change + // has completed. + }); + } + + // Called each time layout completes. + void _saveTabOffsets(List tabOffsets, TextDirection textDirection, double width) { + _tabStripWidth = width; + _indicatorPainter?.saveTabOffsets(tabOffsets, textDirection); + } + + void _handleTap(int index) { + assert(index >= 0 && index < widget.tabs.length); + _controller.animateTo(index); + if (widget.onTap != null) { + widget.onTap(index); + } + } + + Widget _buildStyledTab(Widget child, bool selected, Animation animation) { + return _TabStyle( + animation: animation, + selected: selected, + labelColor: widget.labelColor, + unselectedLabelColor: widget.unselectedLabelColor, + labelStyle: widget.labelStyle, + unselectedLabelStyle: widget.unselectedLabelStyle, + child: child, + ); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMaterialLocalizations(context)); + assert(() { + if (_controller.length != widget.tabs.length) { + throw FlutterError( + 'Controller\'s length property (${_controller.length}) does not match the \n' + 'number of tabs (${widget.tabs.length}) present in TabBar\'s tabs property.' + ); + } + return true; + }()); + final MaterialLocalizations localizations = MaterialLocalizations.of(context); + if (_controller.length == 0) { + return Container( + height: _kTabHeight + widget.indicatorWeight, + ); + } + + final TabBarTheme tabBarTheme = TabBarTheme.of(context); + + final List wrappedTabs = List(widget.tabs.length); + for (int i = 0; i < widget.tabs.length; i += 1) { + wrappedTabs[i] = Center( + heightFactor: 1.0, + child: Padding( + padding: widget.labelPadding ?? tabBarTheme.labelPadding ?? kTabLabelPadding, + child: KeyedSubtree( + key: _tabKeys[i], + child: widget.tabs[i], + ), + ), + ); + + } + + // If the controller was provided by DefaultTabController and we're part + // of a Hero (typically the AppBar), then we will not be able to find the + // controller during a Hero transition. See https://github.com/flutter/flutter/issues/213. + if (_controller != null) { + final int previousIndex = _controller.previousIndex; + + if (_controller.indexIsChanging) { + // The user tapped on a tab, the tab controller's animation is running. + assert(_currentIndex != previousIndex); + final Animation animation = _ChangeAnimation(_controller); + wrappedTabs[_currentIndex] = _buildStyledTab(wrappedTabs[_currentIndex], true, animation); + wrappedTabs[previousIndex] = _buildStyledTab(wrappedTabs[previousIndex], false, animation); + } else { + // The user is dragging the TabBarView's PageView left or right. + final int tabIndex = _currentIndex; + final Animation centerAnimation = _DragAnimation(_controller, tabIndex); + wrappedTabs[tabIndex] = _buildStyledTab(wrappedTabs[tabIndex], true, centerAnimation); + if (_currentIndex > 0) { + final int tabIndex = _currentIndex - 1; + final Animation previousAnimation = ReverseAnimation(_DragAnimation(_controller, tabIndex)); + wrappedTabs[tabIndex] = _buildStyledTab(wrappedTabs[tabIndex], false, previousAnimation); + } + if (_currentIndex < widget.tabs.length - 1) { + final int tabIndex = _currentIndex + 1; + final Animation nextAnimation = ReverseAnimation(_DragAnimation(_controller, tabIndex)); + wrappedTabs[tabIndex] = _buildStyledTab(wrappedTabs[tabIndex], false, nextAnimation); + } + } + } + + // Add the tap handler to each tab. If the tab bar is not scrollable, + // then give all of the tabs equal flexibility so that they each occupy + // the same share of the tab bar's overall width. + final int tabCount = widget.tabs.length; + for (int index = 0; index < tabCount; index += 1) { + wrappedTabs[index] = GestureDetector( + onTap: () { _handleTap(index); }, + child: Container( + color: Colors.transparent, + padding: EdgeInsets.only(bottom: widget.indicatorWeight), + child: Stack( + children: [ + wrappedTabs[index], + Semantics( + selected: index == _currentIndex, + label: localizations.tabLabel(tabIndex: index + 1, tabCount: tabCount), + ), + ], + ), + ), + ); + if (!widget.isScrollable) + wrappedTabs[index] = Expanded(child: wrappedTabs[index]); + } + + Widget tabBar = CustomPaint( + painter: _indicatorPainter, + child: _TabStyle( + animation: kAlwaysDismissedAnimation, + selected: false, + labelColor: widget.labelColor, + unselectedLabelColor: widget.unselectedLabelColor, + labelStyle: widget.labelStyle, + unselectedLabelStyle: widget.unselectedLabelStyle, + child: _TabLabelBar( + onPerformLayout: _saveTabOffsets, + children: wrappedTabs, + ), + ), + ); + + if (widget.isScrollable) { + _scrollController ??= _TabBarScrollController(this); + tabBar = SingleChildScrollView( + dragStartBehavior: widget.dragStartBehavior, + scrollDirection: Axis.horizontal, + controller: _scrollController, + child: tabBar, + ); + } + + return tabBar; + } +} + + +final PageScrollPhysics _kTabBarViewPhysics = const PageScrollPhysics().applyTo(const ClampingScrollPhysics()); + +class _TabBarViewState extends State { + TabController _controller; + PageController _pageController; + List _children; + List _childrenWithKey; + int _currentIndex; + int _warpUnderwayCount = 0; + + // If the TabBarView is rebuilt with a new tab controller, the caller should + // dispose the old one. In that case the old controller's animation will be + // null and should not be accessed. + bool get _controllerIsValid => _controller?.animation != null; + + void _updateTabController() { + final TabController newController = widget.controller ?? DefaultTabController.of(context); + assert(() { + if (newController == null) { + throw FlutterError( + 'No TabController for ${widget.runtimeType}.\n' + 'When creating a ${widget.runtimeType}, you must either provide an explicit ' + 'TabController using the "controller" property, or you must ensure that there ' + 'is a DefaultTabController above the ${widget.runtimeType}.\n' + 'In this case, there was neither an explicit controller nor a default controller.' + ); + } + return true; + }()); + + if (newController == _controller) + return; + + if (_controllerIsValid) + _controller.animation.removeListener(_handleTabControllerAnimationTick); + _controller = newController; + if (_controller != null) + _controller.animation.addListener(_handleTabControllerAnimationTick); + } + + @override + void initState() { + super.initState(); + _updateChildren(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _updateTabController(); + _currentIndex = _controller?.index; + _pageController = PageController(initialPage: _currentIndex ?? 0); + } + + @override + void didUpdateWidget(TabBarView oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.controller != oldWidget.controller) + _updateTabController(); + if (widget.children != oldWidget.children && _warpUnderwayCount == 0) + _updateChildren(); + } + + @override + void dispose() { + if (_controllerIsValid) + _controller.animation.removeListener(_handleTabControllerAnimationTick); + _controller = null; + // We don't own the _controller Animation, so it's not disposed here. + super.dispose(); + } + + void _updateChildren() { + _children = widget.children; + _childrenWithKey = KeyedSubtree.ensureUniqueKeysForList(widget.children); + } + + void _handleTabControllerAnimationTick() { + if (_warpUnderwayCount > 0 || !_controller.indexIsChanging) + return; // This widget is driving the controller's animation. + + if (_controller.index != _currentIndex) { + _currentIndex = _controller.index; + _warpToCurrentIndex(); + } + } + + Future _warpToCurrentIndex() async { + if (!mounted) + return Future.value(); + + if (_pageController.page == _currentIndex.toDouble()) + return Future.value(); + + final int previousIndex = _controller.previousIndex; + if ((_currentIndex - previousIndex).abs() == 1) + return _pageController.animateToPage(_currentIndex, duration: kTabScrollDuration, curve: Curves.ease); + + assert((_currentIndex - previousIndex).abs() > 1); + final int initialPage = _currentIndex > previousIndex + ? _currentIndex - 1 + : _currentIndex + 1; + final List originalChildren = _childrenWithKey; + setState(() { + _warpUnderwayCount += 1; + + _childrenWithKey = List.from(_childrenWithKey, growable: false); + final Widget temp = _childrenWithKey[initialPage]; + _childrenWithKey[initialPage] = _childrenWithKey[previousIndex]; + _childrenWithKey[previousIndex] = temp; + }); + _pageController.jumpToPage(initialPage); + + await _pageController.animateToPage(_currentIndex, duration: kTabScrollDuration, curve: Curves.ease); + if (!mounted) + return Future.value(); + setState(() { + _warpUnderwayCount -= 1; + if (widget.children != _children) { + _updateChildren(); + } else { + _childrenWithKey = originalChildren; + } + }); + } + + // Called when the PageView scrolls + bool _handleScrollNotification(ScrollNotification notification) { + if (_warpUnderwayCount > 0) + return false; + + if (notification.depth != 0) + return false; + + _warpUnderwayCount += 1; + if (notification is ScrollUpdateNotification && !_controller.indexIsChanging) { + if ((_pageController.page - _controller.index).abs() > 1.0) { + _controller.index = _pageController.page.floor(); + _currentIndex =_controller.index; + } + _controller.offset = (_pageController.page - _controller.index).clamp(-1.0, 1.0); + } else if (notification is ScrollEndNotification) { + _controller.index = _pageController.page.round(); + _currentIndex = _controller.index; + } + _warpUnderwayCount -= 1; + + return false; + } + + @override + Widget build(BuildContext context) { + assert(() { + if (_controller.length != widget.children.length) { + throw FlutterError( + 'Controller\'s length property (${_controller.length}) does not match the \n' + 'number of tabs (${widget.children.length}) present in TabBar\'s tabs property.' + ); + } + return true; + }()); + return NotificationListener( + onNotification: _handleScrollNotification, + child: PageView( + dragStartBehavior: widget.dragStartBehavior, + controller: _pageController, + physics: widget.physics == null ? _kTabBarViewPhysics : _kTabBarViewPhysics.applyTo(widget.physics), + children: _childrenWithKey, + ), + ); + } +} + +/// Displays a single circle with the specified border and background colors. +/// +/// Used by [TabPageSelector] to indicate the selected page. +class TabPageSelectorIndicator extends StatelessWidget { + /// Creates an indicator used by [TabPageSelector]. + /// + /// The [backgroundColor], [borderColor], and [size] parameters must not be null. + const TabPageSelectorIndicator({ + Key key, + @required this.backgroundColor, + @required this.borderColor, + @required this.size, + }) : assert(backgroundColor != null), + assert(borderColor != null), + assert(size != null), + super(key: key); + + /// The indicator circle's background color. + final Color backgroundColor; + + /// The indicator circle's border color. + final Color borderColor; + + /// The indicator circle's diameter. + final double size; + + @override + Widget build(BuildContext context) { + return Container( + width: size, + height: size, + margin: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + color: backgroundColor, + border: Border.all(color: borderColor), + shape: BoxShape.circle, + ), + ); + } +} + +/// Displays a row of small circular indicators, one per tab. +/// +/// The selected tab's indicator is highlighted. Often used in conjunction with +/// a [TabBarView]. +/// +/// If a [TabController] is not provided, then there must be a +/// [DefaultTabController] ancestor. +class TabPageSelector extends StatelessWidget { + /// Creates a compact widget that indicates which tab has been selected. + const TabPageSelector({ + Key key, + this.controller, + this.indicatorSize = 12.0, + this.color, + this.selectedColor, + }) : assert(indicatorSize != null && indicatorSize > 0.0), + super(key: key); + + /// This widget's selection and animation state. + /// + /// If [TabController] is not provided, then the value of + /// [DefaultTabController.of] will be used. + final TabController controller; + + /// The indicator circle's diameter (the default value is 12.0). + final double indicatorSize; + + /// The indicator circle's fill color for unselected pages. + /// + /// If this parameter is null, then the indicator is filled with [Colors.transparent]. + final Color color; + + /// The indicator circle's fill color for selected pages and border color + /// for all indicator circles. + /// + /// If this parameter is null, then the indicator is filled with the theme's + /// accent color, [ThemeData.accentColor]. + final Color selectedColor; + + Widget _buildTabIndicator( + int tabIndex, + TabController tabController, + ColorTween selectedColorTween, + ColorTween previousColorTween, + ) { + Color background; + if (tabController.indexIsChanging) { + // The selection's animation is animating from previousValue to value. + final double t = 1.0 - _indexChangeProgress(tabController); + if (tabController.index == tabIndex) + background = selectedColorTween.lerp(t); + else if (tabController.previousIndex == tabIndex) + background = previousColorTween.lerp(t); + else + background = selectedColorTween.begin; + } else { + // The selection's offset reflects how far the TabBarView has / been dragged + // to the previous page (-1.0 to 0.0) or the next page (0.0 to 1.0). + final double offset = tabController.offset; + if (tabController.index == tabIndex) { + background = selectedColorTween.lerp(1.0 - offset.abs()); + } else if (tabController.index == tabIndex - 1 && offset > 0.0) { + background = selectedColorTween.lerp(offset); + } else if (tabController.index == tabIndex + 1 && offset < 0.0) { + background = selectedColorTween.lerp(-offset); + } else { + background = selectedColorTween.begin; + } + } + return TabPageSelectorIndicator( + backgroundColor: background, + borderColor: selectedColorTween.end, + size: indicatorSize, + ); + } + + @override + Widget build(BuildContext context) { + final Color fixColor = color ?? Colors.transparent; + final Color fixSelectedColor = selectedColor ?? Theme.of(context).accentColor; + final ColorTween selectedColorTween = ColorTween(begin: fixColor, end: fixSelectedColor); + final ColorTween previousColorTween = ColorTween(begin: fixSelectedColor, end: fixColor); + final TabController tabController = controller ?? DefaultTabController.of(context); + assert(() { + if (tabController == null) { + throw FlutterError( + 'No TabController for $runtimeType.\n' + 'When creating a $runtimeType, you must either provide an explicit TabController ' + 'using the "controller" property, or you must ensure that there is a ' + 'DefaultTabController above the $runtimeType.\n' + 'In this case, there was neither an explicit controller nor a default controller.' + ); + } + return true; + }()); + final Animation animation = CurvedAnimation( + parent: tabController.animation, + curve: Curves.fastOutSlowIn, + ); + return AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget child) { + return Semantics( + label: 'Page ${tabController.index + 1} of ${tabController.length}', + child: Row( + mainAxisSize: MainAxisSize.min, + children: List.generate(tabController.length, (int tabIndex) { + return _buildTabIndicator(tabIndex, tabController, selectedColorTween, previousColorTween); + }).toList(), + ), + ); + }, + ); + } +} diff --git a/lib/components/permanent/animated_text.dart b/lib/components/permanent/animated_text.dart new file mode 100644 index 0000000..c2edcba --- /dev/null +++ b/lib/components/permanent/animated_text.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class AnimatedText extends StatefulWidget { + final String text; + final int delayInMilliseconds; + final int durationInMilliseconds; + final TextStyle textStyle; + + AnimatedText(this.text, this.delayInMilliseconds, + {this.durationInMilliseconds: 2500, this.textStyle}); + + @override createState() => AnimatedTextState(); +} + +class AnimatedTextState extends State + with SingleTickerProviderStateMixin { + + String currentText = ''; + + AnimationController _controller; + + List get textRunes=> widget.text.runes.toList(); + int get value => _controller.value.toInt(); + + int curIndex = 0; + + + @override + void initState() { + super.initState(); + currentText = String.fromCharCode(textRunes[0]); + + _controller = AnimationController( + vsync: this, + value: 0.0, + lowerBound: 0.0, + upperBound: textRunes.length.toDouble(), + duration: Duration(milliseconds: widget.durationInMilliseconds)); + + _controller..addListener(_updateText)..forward(); + + } + + _updateText(){ + if (value > curIndex && value < textRunes.length) { + setState(() { + curIndex = value; + currentText += String.fromCharCode(textRunes[curIndex]); + }); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Text(currentText, textAlign: TextAlign.left, + style: widget.textStyle ?? + TextStyle(fontWeight: FontWeight.w600, fontSize: 20.0),); + } +} \ No newline at end of file diff --git a/lib/components/permanent/circle.dart b/lib/components/permanent/circle.dart new file mode 100644 index 0000000..5eb4b97 --- /dev/null +++ b/lib/components/permanent/circle.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class Circle extends StatelessWidget { + final Color color; + final double radius; + final bool showShadow; + final Widget child; + + Circle({this.color=Colors.blue, this.radius=6,this.showShadow=true,this.child}); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.center, + child: child==null?Container():child, + width: 2*radius, + height: 2*radius, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + boxShadow: [ + if (showShadow) + BoxShadow( + color: Colors.grey, + offset: Offset(.5,.5), + blurRadius: .5, + )] + ), + ); + } +} diff --git a/lib/components/permanent/circle_image.dart b/lib/components/permanent/circle_image.dart new file mode 100644 index 0000000..5b27783 --- /dev/null +++ b/lib/components/permanent/circle_image.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +class CircleImage extends StatelessWidget { + CircleImage( + {Key key, + @required this.image, + this.size = 70, + this.shadowColor, + this.roundColor}) + : super(key: key); + final ImageProvider image; //图片 + final double size; //大小 + final Color shadowColor; //阴影颜色 + final Color roundColor; //边框颜色 + @override + Widget build(BuildContext context) { + var headIcon = Container( + width: size, + height: size, + decoration: BoxDecoration( + shape: BoxShape.circle, //圆形装饰线 + color: roundColor ?? Colors.white, + boxShadow: [ + BoxShadow( + //阴影 + color: shadowColor ?? Colors.grey.withOpacity(0.3), + offset: Offset(0.0, 0.0), blurRadius: 3.0, spreadRadius: 0.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(3), + child: + CircleAvatar( + backgroundImage: image, + ), + ), + ); + return headIcon; + } +} diff --git a/lib/components/permanent/circle_text.dart b/lib/components/permanent/circle_text.dart new file mode 100644 index 0000000..aa7ad14 --- /dev/null +++ b/lib/components/permanent/circle_text.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; + +class CircleText extends StatelessWidget { + CircleText( + {Key key, + @required this.text, + this.size = 70, + this.fontSize = 24, + this.color = Colors.white, + this.shadowColor, + this.roundColor}) + : super(key: key); + final String text; //图片 + final double size; //大小 + final double fontSize; //大小 + final Color shadowColor; //阴影颜色 + final Color color; //阴影颜色 + final Color roundColor; //边框颜色 + @override + Widget build(BuildContext context) { + var headIcon = Container( + width: size, + height: size, + decoration: BoxDecoration( + shape: BoxShape.circle, //圆形装饰线 + color: roundColor ?? Colors.white, + boxShadow: [ + BoxShadow( + //阴影 + color: shadowColor ?? Colors.grey.withOpacity(0.3), + offset: Offset(0.0, 0.0), blurRadius: 3.0, spreadRadius: 0.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(3), + child: Container( + alignment: Alignment.center, + width: size, + height: size, + decoration: BoxDecoration( + shape: BoxShape.circle, //圆形装饰线 + color: Color(0xffD8F5FF), + ), + child: Text( + text.substring(0, 2), + style: TextStyle( + fontSize: fontSize, + color: color, + fontWeight: FontWeight.bold, + shadows: [ + Shadow( + //阴影 + color: Colors.grey, + offset: Offset(1.0, 1.0), blurRadius: 1.0, + ) + ], + ), + )), + ), + ); + return headIcon; + } +} diff --git a/lib/components/permanent/code/back/code_panel.dart b/lib/components/permanent/code/back/code_panel.dart new file mode 100755 index 0000000..f56cd38 --- /dev/null +++ b/lib/components/permanent/code/back/code_panel.dart @@ -0,0 +1,66 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import '../high_light_code.dart'; +import '../highlighter_style.dart'; + + +class CodeWidget extends StatelessWidget { + CodeWidget({ + Key key, + @required this.code, + this.style, + this.fontSize = 13, + this.fontFamily, + }) : super(key: key); + + final String code; + final HighlighterStyle style; + final double fontSize; + final String fontFamily; + @override + Widget build(BuildContext context) { + if (code == null) { + return Container(); + } + + Widget _codeWidget = FutureBuilder( + future: compute(_hightlight, _HightlightArgs(style, code)), + builder: (context, snapshot) { + if (snapshot.hasError) { + return Text(code); + } + if (snapshot.hasData) + return RichText( + text: TextSpan( + children: [snapshot.data], + ), + ); + // computing + return SizedBox.shrink(); + }, + ); + + return SingleChildScrollView( + child: Container( + child: DefaultTextStyle( + child: _codeWidget, + style: TextStyle(fontSize: fontSize, fontFamily: fontFamily), + ), + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: style.backgroundColor ?? Color(0xffF6F8FA), + borderRadius: BorderRadius.all(Radius.circular(5.0))), + ), + ); + } +} + +class _HightlightArgs { + final HighlighterStyle style; + final String code; + _HightlightArgs(this.style, this.code); +} + +TextSpan _hightlight(_HightlightArgs args) => + DartHighlighter(args.style).format(args.code); diff --git a/lib/components/permanent/code/code_widget.dart b/lib/components/permanent/code/code_widget.dart new file mode 100644 index 0000000..be8d647 --- /dev/null +++ b/lib/components/permanent/code/code_widget.dart @@ -0,0 +1,49 @@ + +/// create by 张风捷特烈 on 2020-04-15 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/material.dart'; + +import 'high_light_code.dart'; +import 'highlighter_style.dart'; + +class CodeWidget extends StatelessWidget { + CodeWidget({Key key, @required this.code, this.style, this.fontSize = 13,this.fontFamily}) + : super(key: key); + + final String code; + final HighlighterStyle style; + final double fontSize; + final String fontFamily; + + @override + Widget build(BuildContext context) { + Widget body; + if (code == null) { + return Container(); + } else { + Widget _codeWidget; + try { + _codeWidget = RichText( + text: TextSpan( + style: TextStyle(fontSize: fontSize,fontFamily: fontFamily), + children: [DartHighlighter(style).format(code)], + ), + ); + } catch (err) { + _codeWidget = Text(code); + } + body = SingleChildScrollView( + child: Container( + child: _codeWidget, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: style.backgroundColor ?? Color(0xffF6F8FA), + borderRadius: BorderRadius.all(Radius.circular(5.0))), + ), + ); + } + return body; + } +} \ No newline at end of file diff --git a/lib/components/permanent/code/high_light_code.dart b/lib/components/permanent/code/high_light_code.dart new file mode 100644 index 0000000..e3987e1 --- /dev/null +++ b/lib/components/permanent/code/high_light_code.dart @@ -0,0 +1,319 @@ +/// create by 张风捷特烈 on 2020-04-15 +/// contact me by email 1981462002@qq.com +/// 说明: + +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:string_scanner/string_scanner.dart'; + +import 'highlighter_style.dart'; + +/// final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle(); +/// DartSyntaxHighlighter(style).format(source) + + +abstract class Highlighter { // ignore: one_member_abstracts + TextSpan format(String src); +} + +//暗黑模式下的高亮样式 +class DartHighlighter extends Highlighter { + DartHighlighter([this._style]) { + _spans = <_HighlightSpan>[]; + _style ??= HighlighterStyle.fromColors(HighlighterStyle.lightColor); + } + + HighlighterStyle _style; + + static const List _keywords = [ + 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', + 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', + 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', + 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', + 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', + 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', + 'void', 'while', 'with', 'yield' + ]; + + static const List _builtInTypes = [ + 'int', 'double', 'num', 'bool' + ]; + + String _src; + StringScanner _scanner; + + List<_HighlightSpan> _spans; + + @override + TextSpan format(String src) { + _src = src; + _scanner = StringScanner(_src); + + if (_generateSpans()) { + // Successfully parsed the code + final List formattedText = []; + int currentPosition = 0; + + for (_HighlightSpan span in _spans) { + if (currentPosition != span.start) + formattedText.add(TextSpan(text: _src.substring(currentPosition, span.start))); + + formattedText.add(TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src))); + + currentPosition = span.end; + } + + if (currentPosition != _src.length) + formattedText.add(TextSpan(text: _src.substring(currentPosition, _src.length))); + + return TextSpan(style: _style.baseStyle, children: formattedText); + } else { + // Parsing failed, return with only basic formatting + return TextSpan(style: _style.baseStyle, text: src); + } + } + + bool _generateSpans() { + int lastLoopPosition = _scanner.position; + + while (!_scanner.isDone) { + // Skip White space + _scanner.scan(RegExp(r'\s+')); + + // Block comments + if (_scanner.scan(RegExp(r'/\*(.|\n)*\*/'))) { + _spans.add(_HighlightSpan( + _HighlightType.comment, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Line comments + if (_scanner.scan('//')) { + final int startComment = _scanner.lastMatch.start; + + bool eof = false; + int endComment; + if (_scanner.scan(RegExp(r'.*\n'))) { + endComment = _scanner.lastMatch.end - 1; + } else { + eof = true; + endComment = _src.length; + } + + _spans.add(_HighlightSpan( + _HighlightType.comment, + startComment, + endComment + )); + + if (eof) + break; + + continue; + } + + // Raw r"String" + if (_scanner.scan(RegExp(r'r".*"'))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Raw r'String' + if (_scanner.scan(RegExp(r"r'.*'"))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Multiline """String""" + if (_scanner.scan(RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Multiline '''String''' + if (_scanner.scan(RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // "String" + if (_scanner.scan(RegExp(r'"(?:[^"\\]|\\.)*"'))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // 'String' + if (_scanner.scan(RegExp(r"'(?:[^'\\]|\\.)*'"))) { + _spans.add(_HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Double + if (_scanner.scan(RegExp(r'\d+\.\d+'))) { + _spans.add(_HighlightSpan( + _HighlightType.number, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Integer + if (_scanner.scan(RegExp(r'\d+'))) { + _spans.add(_HighlightSpan( + _HighlightType.number, + _scanner.lastMatch.start, + _scanner.lastMatch.end) + ); + continue; + } + + // Punctuation + if (_scanner.scan(RegExp(r'[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]'))) { + _spans.add(_HighlightSpan( + _HighlightType.punctuation, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Meta data + if (_scanner.scan(RegExp(r'@\w+'))) { + _spans.add(_HighlightSpan( + _HighlightType.keyword, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Words + if (_scanner.scan(RegExp(r'\w+'))) { + _HighlightType type; + + String word = _scanner.lastMatch[0]; + if (word.startsWith('_')) + word = word.substring(1); + + if (_keywords.contains(word)) + type = _HighlightType.keyword; + else if (_builtInTypes.contains(word)) + type = _HighlightType.keyword; + else if (_firstLetterIsUpperCase(word)) + type = _HighlightType.klass; + else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1))) + type = _HighlightType.constant; + + if (type != null) { + _spans.add(_HighlightSpan( + type, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + } + } + + // Check if this loop did anything + if (lastLoopPosition == _scanner.position) { + // Failed to parse this file, abort gracefully + return false; + } + lastLoopPosition = _scanner.position; + } + + _simplify(); + return true; + } + + void _simplify() { + for (int i = _spans.length - 2; i >= 0; i -= 1) { + if (_spans[i].type == _spans[i + 1].type && _spans[i].end == _spans[i + 1].start) { + _spans[i] = _HighlightSpan( + _spans[i].type, + _spans[i].start, + _spans[i + 1].end + ); + _spans.removeAt(i + 1); + } + } + } + + bool _firstLetterIsUpperCase(String str) { + if (str.isNotEmpty) { + final String first = str.substring(0, 1); + return first == first.toUpperCase(); + } + return false; + } +} + +enum _HighlightType { + number, + comment, + keyword, + string, + punctuation, + klass, + constant +} + +class _HighlightSpan { + _HighlightSpan(this.type, this.start, this.end); + final _HighlightType type; + final int start; + final int end; + + String textForSpan(String src) { + return src.substring(start, end); + } + + TextStyle textStyle(HighlighterStyle style) { + if (type == _HighlightType.number) + return style.numberStyle; + else if (type == _HighlightType.comment) + return style.commentStyle; + else if (type == _HighlightType.keyword) + return style.keywordStyle; + else if (type == _HighlightType.string) + return style.stringStyle; + else if (type == _HighlightType.punctuation) + return style.punctuationStyle; + else if (type == _HighlightType.klass) + return style.classStyle; + else if (type == _HighlightType.constant) + return style.constantStyle; + else + return style.baseStyle; + } +} \ No newline at end of file diff --git a/lib/components/permanent/code/highlighter_style.dart b/lib/components/permanent/code/highlighter_style.dart new file mode 100644 index 0000000..3980bfc --- /dev/null +++ b/lib/components/permanent/code/highlighter_style.dart @@ -0,0 +1,139 @@ +/// create by 张风捷特烈 on 2020-04-15 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-11 +/// contact me by email 1981462002@qq.com +/// 说明: + +class HighlighterStyle { + //句法高亮样式 + const HighlighterStyle( + { //构造函数 + this.baseStyle, //基础样式 + this.numberStyle, //数字的样式 + this.commentStyle, //注释样式 + this.keywordStyle, //关键字样式 + this.stringStyle, //字符串样式 + this.punctuationStyle, //标点符号样式 + this.classStyle, //类名 + this.backgroundColor, + this.constantStyle}); + + static List get lightColor => [ + 0xFF000000, //基础 + 0xFF00b0e8, //数字 + 0xFF9E9E9E, //注释 + 0xFF9C27B0, //关键 + 0xFF43A047, //字符串 + 0xFF000000, //标点符号 + 0xFF3D62F5, //类名 + 0xFF795548, //常量 + 0xffF6F8FA, //背景 + ]; + + static List get darkColor => [ + 0xFFFFFFFF, //基础 + 0xFFDF935F, //数字 + 0xFF9E9E9E, //注释 + 0xFF80CBC4, //关键字 + 0xFFB9CA4A, //字符串 + 0xFFFFFFFF, //标点符号 + 0xFF7AA6DA, //类名 + 0xFF795548, //常量 + 0xFF1D1F21, //背景 + ]; + + static List get gitHub => + [ + 0xFF333333, //基础 + 0xFF008081, //数字 + 0xFF9D9D8D, //注释 + 0xFF009999, //关键字 + 0xFFDD1045, //字符串 + 0xFF333333, //标点符号 + 0xFF6F42C1, //类名 + 0xFF795548, //常量 + 0xFFF8F8F8, //背景 + ]; + + static List get zenburn => [ + 0xFFDCDCDC, //普通字 + 0xFF87C5C8, //数字 + 0xFF8F8F8F, //注释 + 0xFFE4CEAB, //关键字 + 0xFFCC9493, //字符串 + 0xFFDCDCDC, //标点符号 + 0xFFEFEF90, //类名 + 0xFFEF5350, //常量 + 0xFF3F3F3F, //背景 + ]; + + static List get mf =>[ + 0xFF707D95, //基础 + 0xFF6897BB, //数字 + 0xFF629755, //注释 + 0xFFCC7832, //关键 + 0xFFF14E9F, //字符串 + 0xFFFFBB33, //标点符号 + 0xFF66CCFF, //类名 + 0xFF9876AA, //常量 + 0xFF2B2B2B //背景 + ]; + + static List get solarized =>[ + 0xFF657B83, // 普通字 + 0xFFD33682, // 数字 + 0xFF93A1A1, // 注释 + 0xFF859900, // 关键字 + 0xFF2AA198, // 字符串 + 0xFF859900, // 标点符号 + 0xFF268BD2, // 类名 + 0xFF268BD2, //常量 + 0xFFDDD6C1, // 背景 + ]; + + factory HighlighterStyle.fromColors(List colors) => HighlighterStyle( + baseStyle: TextStyle( + color: Color(colors[0]), + ), + numberStyle: TextStyle( + color: Color(colors[1]), + ), + commentStyle: TextStyle( + color: Color( + colors[2], + ), + fontStyle: FontStyle.italic), + keywordStyle: TextStyle( + fontWeight: FontWeight.bold, + color: Color( + colors[3], + ), + ), + stringStyle: TextStyle( + color: Color(colors[4]), + ), + punctuationStyle: TextStyle( + color: Color(colors[5]), + ), + classStyle: TextStyle( + color: Color(colors[6]), + ), + constantStyle: TextStyle( + color: Color(colors[7]), + ), + backgroundColor: Color(colors[8]), + ); + final TextStyle baseStyle; + final TextStyle numberStyle; + final TextStyle commentStyle; + final TextStyle keywordStyle; + final TextStyle stringStyle; + final TextStyle punctuationStyle; + final TextStyle classStyle; + final TextStyle constantStyle; + final Color backgroundColor; +} \ No newline at end of file diff --git a/lib/components/permanent/feedback_widget.dart b/lib/components/permanent/feedback_widget.dart new file mode 100644 index 0000000..36a148e --- /dev/null +++ b/lib/components/permanent/feedback_widget.dart @@ -0,0 +1,82 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +enum FeedMode { + scale, + fade, + rotate, +} + +class FeedbackWidget extends StatefulWidget { + final Widget child; + final FeedMode mode; + final Duration duration; + final Function() onPressed; + final a; + + FeedbackWidget( + {@required this.child, + this.mode = FeedMode.scale, + this.a = 0.9, + this.duration = const Duration(milliseconds: 150), + @required this.onPressed}); + + @override + _FeedBackState createState() => _FeedBackState(); +} + +class _FeedBackState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + var rate = 1.0; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.duration) + ..addListener(() { + setState(() => rate = (widget.a - 1) * _controller.value + 1); + }) + ..addStatusListener((s) { + if (s == AnimationStatus.completed) { + _controller.reverse(); + } + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + _controller.forward(); + if(widget.onPressed!=null){ + widget.onPressed(); + } + }, + child: _buildByMode(widget.child, widget.mode), + ); + } + + Widget _buildByMode(Widget child, FeedMode mode) { + switch (mode) { + case FeedMode.scale: + return Transform.scale(scale: rate, child: widget.child); + case FeedMode.fade: + return Opacity(opacity: rate, child: widget.child); + case FeedMode.rotate: + return Transform.rotate(angle: rate * pi * 2, child: widget.child); + } + return Container(); + } +} diff --git a/lib/components/permanent/panel.dart b/lib/components/permanent/panel.dart new file mode 100644 index 0000000..a0481e0 --- /dev/null +++ b/lib/components/permanent/panel.dart @@ -0,0 +1,24 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +class Panel extends StatelessWidget { + final double radius; + final Color color; + final Widget child; + + Panel({this.radius = 5.0, this.color, this.child}); + + @override + Widget build(BuildContext context) { + return Container( + child: child, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: color ?? Color(0xffF6F8FA), + borderRadius: BorderRadius.all(Radius.circular(radius))), + ); + } +} + + diff --git a/lib/components/permanent/tag.dart b/lib/components/permanent/tag.dart new file mode 100644 index 0000000..d0444dd --- /dev/null +++ b/lib/components/permanent/tag.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; + +class Tag extends StatelessWidget { + final Size size; + final double shadowHeight; + final double tranRate; + final Color color; + + Tag({this.size = const Size(100, 150),this.shadowHeight=9.0,this.tranRate=0.25,this.color=Colors.red}); + + @override + Widget build(BuildContext context) { + return Container( + width: size.width, + height: size.height, + child: CustomPaint( + painter: _TagPaint( + color: color, + shadowHeight: shadowHeight, + tranRate: tranRate, + ), + ), + ); + } +} + +class _TagPaint extends CustomPainter { + Path path = Path(); + Path shadowPath = Path(); + Paint _paint; + final tranRate; + final double shadowHeight; + final Color color; + + final rate = 0.5; + + _TagPaint({this.tranRate, this.color ,this.shadowHeight}) + : _paint = Paint()..color = color; + + @override + void paint(Canvas canvas, Size size) { + canvas.clipRect(Offset.zero & size); + + path.moveTo(0, 0); + path.relativeLineTo(size.width-shadowHeight*rate, 0); + path.relativeLineTo(0, size.height); + path.relativeLineTo(-(size.width-shadowHeight*rate) / 2, -tranRate * size.height); + path.relativeLineTo(-(size.width-shadowHeight*rate) / 2, tranRate * size.height); + path.close(); + canvas.drawPath(path, _paint..color = color); + + shadowPath.moveTo(size.width-shadowHeight*rate, 0); + shadowPath.relativeLineTo(0, shadowHeight); + shadowPath.relativeLineTo(shadowHeight*rate, 0); + shadowPath.close(); + canvas.drawPath(shadowPath, _paint..color=color.withAlpha(88)); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/components/project/widget_node_panel.dart b/lib/components/project/widget_node_panel.dart new file mode 100644 index 0000000..6a6d44f --- /dev/null +++ b/lib/components/project/widget_node_panel.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_unit/app/style/TolyIcon.dart'; + +import 'package:flutter_unit/components/permanent/circle.dart'; +import 'package:flutter_unit/components/permanent/code/code_widget.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:share/share.dart'; +import 'package:toggle_rotate/toggle_rotate.dart'; + +import '../permanent/feedback_widget.dart'; +import '../permanent/code/highlighter_style.dart'; + +/// create by 张风捷特烈 on 2020-04-13 +/// contact me by email 1981462002@qq.com +/// 说明: + +class WidgetNodePanel extends StatefulWidget { + final String text; + final String subText; + final String code; + final Widget show; + final HighlighterStyle codeStyle; + final String codeFamily; + + WidgetNodePanel({this.text, this.subText, this.code, this.show,this.codeStyle,this.codeFamily}); + + @override + _WidgetNodePanelState createState() => _WidgetNodePanelState(); +} + +class _WidgetNodePanelState extends State + with SingleTickerProviderStateMixin { + bool _showCode = false; + + var _crossFadeState = CrossFadeState.showFirst; + + bool get isFirst => _crossFadeState == CrossFadeState.showFirst; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Circle( + color: Theme.of(context).primaryColor, + radius: 5, + ), + ), + Expanded( + child: Text( + '${widget.text}', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + FeedbackWidget( + mode: FeedMode.fade, + a: 0.4, + onPressed: () async { +// await Clipboard.setData(ClipboardData(text: widget.code)); +// Toast.toast(context, '复制成功!'); + Share.share(widget.code); + }, + child: Padding( + padding: const EdgeInsets.only( + right: 10, + ), + child: Icon( + TolyIcon.icon_share, + size: 20, + color: Theme.of(context).primaryColor, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(right: 10.0), + child: ToggleRotate( + durationMs: 300, + child: Icon( + TolyIcon.icon_code, + color: Theme.of(context).primaryColor, + ), + onTap: () { + setState(() { + _crossFadeState = _showCode + ? CrossFadeState.showFirst + : CrossFadeState.showSecond; + _showCode = !_showCode; + }); + }, + ), + ) + ], + ), + SizedBox( + height: 20, + ), + _buildCode(context), + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 20), + child: widget.show, + ), + Container( + width: double.infinity, + child: Panel( + child: Text( + '${widget.subText}', + style: TextStyle(fontSize: 14), + )), + ), + Divider(), + ], + ), + ); + } + + Widget _buildCode(BuildContext context) => AnimatedCrossFade( + firstCurve: Curves.easeInCirc, + secondCurve: Curves.easeInToLinear, + firstChild: Container(), + secondChild: Container( + width: MediaQuery.of(context).size.width, + child: CodeWidget( + fontFamily: widget.codeFamily, + code: widget.code, + style: widget.codeStyle??HighlighterStyle.fromColors( + HighlighterStyle.lightColor), + ), + ), + duration: Duration(milliseconds: 500), + crossFadeState: _crossFadeState, + ); +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..da34e94 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/search/search_bloc.dart'; +import 'package:flutter_unit/repositorys/widget_db_repository.dart'; +import 'package:flutter_unit/storage/app_storage.dart'; +import 'package:flutter_unit/views/pages/splash/unit_splash.dart'; + +//import 'tools/initial.dart'; +import 'blocs/collect/collect_bloc.dart'; +import 'blocs/detail/detail_bloc.dart'; +import 'blocs/global/global_bloc.dart'; +import 'blocs/global/global_event.dart'; +import 'blocs/global/global_state.dart'; +import 'blocs/widgets/home_bloc.dart'; +import 'blocs/widgets/home_event.dart'; + +import 'app/router.dart'; + +void main() async { +// await Initial.init(); +// runApp(BlocWrapper( +// child: ColorFiltered( +// colorFilter: ColorFilter.mode(Colors.white, BlendMode.color), +// child: FlutterApp()))); + runApp(BlocWrapper(child: FlutterApp())); +} + +final storage = AppStorage(); + +class BlocWrapper extends StatelessWidget { + final Widget child; + + BlocWrapper({this.child}); + + final repository = WidgetDbRepository(storage); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider(//使用MultiBlocProvider包裹 + providers: [ + //Bloc提供器 + BlocProvider( + create: (_) => GlobalBloc(storage)..add(EventInitApp())), + BlocProvider( + create: (_) => HomeBloc(repository: repository) + ..add(EventTabTap(WidgetFamily.statelessWidget))), + + BlocProvider( + create: (_) => DetailBloc(repository: repository)), + + BlocProvider( + create: (_) => + CollectBloc(repository: repository)..add(EventSetCollectData())), + BlocProvider( + create: (_) => SearchBloc(repository: repository)), + ], child: child); + } +} + +class FlutterApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BlocBuilder(builder: (_, state) { + return MaterialApp( + title: 'Flutter Demo', + debugShowCheckedModeBanner: false, + onGenerateRoute: Router.generateRoute, + theme: ThemeData( + primarySwatch: state.themeColor, + fontFamily: state.fontFamily, + ), + home: +// NavPage() + UnitSplash() +// UnitNavigation(), + ); + }); + } +} +//NavPage() diff --git a/lib/model/collect_model.dart b/lib/model/collect_model.dart new file mode 100644 index 0000000..74e3a8a --- /dev/null +++ b/lib/model/collect_model.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-17 +/// contact me by email 1981462002@qq.com +/// 说明: + +class CollectModel { + final String name; + final String info; + final String createDate; + final String imageCover; + final int count; + final Color color; + + CollectModel( + {this.name, + this.info, + this.createDate, + this.imageCover, + this.count, + this.color}); +} diff --git a/lib/model/node_model.dart b/lib/model/node_model.dart new file mode 100644 index 0000000..c68fa51 --- /dev/null +++ b/lib/model/node_model.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; + +/// create by 张风捷特烈 on 2020-03-04 +/// contact me by email 1981462002@qq.com +/// 说明: + + +class NodeModel extends Equatable { + final String name; + final String subtitle; + final String code; + + const NodeModel({this.name, this.subtitle, this.code}); + + @override + List get props => [name, subtitle, code]; + + factory NodeModel.fromJson(Map map) { + return NodeModel( + name: map['name'], + subtitle: map["subtitle"], + code: map["code"]); + } + + @override + String toString() { + return 'Node{name: $name, subtitle: $subtitle, code: $code}'; + } +} \ No newline at end of file diff --git a/lib/model/widget_model.dart b/lib/model/widget_model.dart new file mode 100644 index 0000000..8e604fc --- /dev/null +++ b/lib/model/widget_model.dart @@ -0,0 +1,81 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_unit/app/convert.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/storage/po/widget_po.dart'; + +enum WidgetType { + singe_show, //单一展示型 0 + structure, //结构型 1 + shape, //可形变 2 + event, //事件型 3 + ability, //功能型 4 + layout, //布局型 5 + scroll, //滚动型 +} + +class WidgetModel extends Equatable { + final int id; + final String name; + final String nameCN; + final WidgetFamily family; + final bool collected; + final WidgetType type; + final List links; + final double lever; + final ImageProvider image; + final String info; + + Color get color => Color(Cons.tabColors[family.index]); + + const WidgetModel( + {this.id, + this.name, + this.nameCN, + this.family, + this.collected, + this.links, + this.type, + this.lever, + this.image, + this.info}); + + @override + List get props => [id]; + + static WidgetModel fromPo(WidgetPo po) { + return WidgetModel( + id: po.id, + name: po.name, + nameCN: po.nameCN, + family: Convert.toFamily(po.family), + image: convertImage(po.image), + lever: po.lever, + collected: po.collected == 1, + info: po.info, + links: formatLinkTo(po.linkWidget), + ); + } + + static convertImage(String image) { + return image.isEmpty ? null : AssetImage(image); + } + + @override + String toString() { + return 'WidgetModel{id: $id, name: $name,collected: $collected}'; + } + + static List formatLinkTo(String links) { + if(links.isEmpty){ + return []; + } + if(!links.contains(',')){ + return [int.parse(links)]; + } + return links.split(',').map((e)=>int.parse(e)).toList(); + } + + +} diff --git a/lib/repositorys/widget_db_repository.dart b/lib/repositorys/widget_db_repository.dart new file mode 100644 index 0000000..0624e35 --- /dev/null +++ b/lib/repositorys/widget_db_repository.dart @@ -0,0 +1,70 @@ + + + +import 'package:flutter_unit/storage/app_storage.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/storage/node_dao.dart'; +import 'package:flutter_unit/storage/po/widget_po.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; +import 'package:flutter_unit/model/node_model.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/repositorys/widget_repository.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明 : Widget数据仓库 + +class WidgetDbRepository implements WidgetRepository { + final AppStorage storage; + + WidgetDao _widgetDao; + NodeDao _nodeDao; + + + WidgetDbRepository(this.storage){ + _widgetDao = WidgetDao(storage); + _nodeDao = NodeDao(storage); + } + + @override + Future> loadWidgets(WidgetFamily family) async { + var data = await _widgetDao.queryByFamily(family); + var widgets = data.map((e) => WidgetPo.fromJson(e)).toList(); + return widgets.map(WidgetModel.fromPo).toList(); + } + + @override + Future> loadCollectWidgets() async { + var data = await _widgetDao.queryCollect(); + var widgets = data.map((e) => WidgetPo.fromJson(e)).toList(); + var list = widgets.map(WidgetModel.fromPo).toList(); + return list; + } + + @override + Future> searchWidgets(SearchArgs args) async { + var data = await _widgetDao.search(args); + var widgets = data.map((e) => WidgetPo.fromJson(e)).toList(); + return widgets.map(WidgetModel.fromPo).toList(); + } + + @override + Future> loadNode(WidgetModel widgetModel) async{ + var data = await _nodeDao.queryById(widgetModel.id); + var nodes = data.map((e) => NodeModel.fromJson(e)).toList(); + return nodes; + } + + @override + Future> loadWidget(List id) async{ + var data = await _widgetDao.queryByIds(id); + var widgets = data.map((e) => WidgetPo.fromJson(e)).toList(); + if(widgets.length>0) return widgets.map(WidgetModel.fromPo).toList(); + return null; + } + + @override + Future toggleCollect(int id,) { + return _widgetDao.toggleCollect(id); + } +} diff --git a/lib/repositorys/widget_repository.dart b/lib/repositorys/widget_repository.dart new file mode 100644 index 0000000..f8fb8cb --- /dev/null +++ b/lib/repositorys/widget_repository.dart @@ -0,0 +1,24 @@ + + +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; +import 'package:flutter_unit/model/node_model.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com + +abstract class WidgetRepository { + + Future> loadWidgets(WidgetFamily family); + + Future> loadWidget(List ids); + + + Future> searchWidgets(SearchArgs args); + Future> loadNode(WidgetModel widgetModel); + + Future toggleCollect(int id); + Future> loadCollectWidgets(); + +} \ No newline at end of file diff --git a/lib/storage/app_storage.dart b/lib/storage/app_storage.dart new file mode 100644 index 0000000..68c1896 --- /dev/null +++ b/lib/storage/app_storage.dart @@ -0,0 +1,69 @@ + +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/services.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/res/sp.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart' as path; +/// create by 张风捷特烈 on 2020-03-04 +/// contact me by email 1981462002@qq.com +/// 说明: + +class AppStorage { + SharedPreferences _sp; + Database _database; + + Future get sp async { + _sp = _sp ?? await SharedPreferences.getInstance(); + return _sp; + } + + Future get db async { + _database = _database ?? await initDb(); + return _database; + } + + // 初始化 App 固化的配置数据 + Future initApp() async { + var prefs = await sp; + _database = await initDb(); + var showBg = prefs.getBool(SP.showBackground) ?? true; + var themeIndex = prefs.getInt(SP.themeColorIndex) ?? 4; + var fontIndex = prefs.getInt(SP.fontFamily) ?? 1; + var codeIndex = prefs.getInt(SP.codeStyleIndex) ?? 0; + var itemStyleIndex = prefs.getInt(SP.itemStyleIndex) ?? 0; + + return GlobalState( + showBackGround: showBg, + themeColor: Cons.themeColorSupport.keys.toList()[themeIndex], + fontFamily: Cons.fontFamilySupport[fontIndex], + itemStyleIndex: itemStyleIndex, + codeStyleIndex: codeIndex); + } + + // 初始化数据库 + Future initDb() async { + var databasesPath = await getDatabasesPath(); + var dbPath = path.join(databasesPath, "flutter.db"); + var exists = await databaseExists(dbPath); + if (!exists) { + print("Creating new copy from asset"); + try { + await Directory(path.dirname(dbPath)).create(recursive: true); + } catch (_) {} + + ByteData data = await rootBundle.load(path.join("assets", "flutter.db")); + List bytes = + data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + await File(dbPath).writeAsBytes(bytes, flush: true); + + } else { + print("Opening existing database"); + } + return await openDatabase(dbPath, readOnly: false); + } +} diff --git a/lib/storage/node_dao.dart b/lib/storage/node_dao.dart new file mode 100644 index 0000000..db51365 --- /dev/null +++ b/lib/storage/node_dao.dart @@ -0,0 +1,43 @@ +import 'package:flutter_unit/storage/app_storage.dart'; + +import 'po/node_po.dart'; + +class NodeDao { + + final AppStorage storage; + + NodeDao(this.storage); + + Future insert(NodePo widget) async { + //插入方法 + final db = await storage.db; + String addSql = //插入数据 + "INSERT INTO " + "node(widgetId,name,priority,subtitle,code) " + "VALUES (?,?,?,?,?);"; + return await db.transaction((tran) async => await tran.rawInsert(addSql, [ + widget.widgetId, + widget.name, + widget.priority, + widget.subtitle, + widget.code + ])); + } + + Future>> queryAll() async { + //插入方法 + final db = await storage.db; + return await db.rawQuery("SELECT * " + "FROM node"); + } + + //根据 id 查询组件 node + Future>> queryById(int id) async { + final db = await storage.db; + return await db.rawQuery( + "SELECT name,subtitle,code " + "FROM node " + "WHERE widgetId = ?", + [id]); + } +} diff --git a/lib/storage/po/collect_po.dart b/lib/storage/po/collect_po.dart new file mode 100644 index 0000000..da60968 --- /dev/null +++ b/lib/storage/po/collect_po.dart @@ -0,0 +1,38 @@ +import 'package:equatable/equatable.dart'; + +/// create by 张风捷特烈 on 2020-04-17 +/// contact me by email 1981462002@qq.com +/// 说明: + +//1 动画组件集 ff000000 收录动画相关组件 2020-04-17 + +class CollectPo extends Equatable { + final int id; + final String name; + final int color; + final String info; + final DateTime created; + final String image; + + const CollectPo({this.id, this.name, this.color, this.created, this.info,this.image}); + + factory CollectPo.fromJson(Map map) { + return CollectPo( + id: map['id'], + name: map['name'], + color: map["color"], + created: map["created"], + image: map["image"], + info: map["info"]); + } + + + @override + String toString() { + return 'CollectPo{id: $id, name: $name, color: $color, info: $info, created: $created, image: $image}'; + } + + @override + List get props => + [id, name, color, created, image, info]; +} diff --git a/lib/storage/po/node_po.dart b/lib/storage/po/node_po.dart new file mode 100644 index 0000000..1d5a750 --- /dev/null +++ b/lib/storage/po/node_po.dart @@ -0,0 +1,35 @@ +//persistent object 持久层对象, +// 用于与数据库中记录对用的对象 + +class NodePo { + final int id; + final int widgetId; + final String name; + final int priority; + final String subtitle; + final String code; + + const NodePo( + {this.id, + this.widgetId, + this.name, + this.priority, + this.subtitle, + this.code}); + + factory NodePo.fromJson(Map map) { + return NodePo( + id: map['id'], + name: map['name'], + widgetId: map["widgetId"], + priority: map["priority"], + subtitle: map["subtitle"], + code: map["code"]); + } + + @override + String toString() { + return 'NodePo{id: $id, widgetId: $widgetId, name: $name, priority: $priority, subtitle: $subtitle, code: $code}'; + } + +} diff --git a/lib/storage/po/widget_po.dart b/lib/storage/po/widget_po.dart new file mode 100644 index 0000000..507e0fe --- /dev/null +++ b/lib/storage/po/widget_po.dart @@ -0,0 +1,49 @@ +//persistent object 持久层对象, +// 用于与数据库中记录对用的对象 + +import 'package:equatable/equatable.dart'; + +class WidgetPo extends Equatable { + final int id; + final String name; + final String nameCN; + final int collected; + final int family; + final double lever; + final String image; + final String info; + final String linkWidget; + + const WidgetPo( + {this.id, + this.name, + this.nameCN, + this.collected, + this.family, + this.lever, + this.linkWidget, + this.image, + this.info}); + + factory WidgetPo.fromJson(Map map) { + return WidgetPo( + id: map['id'], + name: map['name'], + nameCN: map["nameCN"], + family: map["family"], + collected: map["collected"]??0, + lever: map["lever"].toDouble(), + image: map["image"], + linkWidget: map["linkWidget"], + info: map["info"]); + } + + @override + String toString() { + return 'WidgetPo{id: $id, name: $name, nameCN: $nameCN, collected: $collected, family: $family, lever: $lever, image: $image, info: $info}'; + } + + @override + List get props => + [id, name, nameCN, collected, family, lever, image, info]; +} diff --git a/lib/storage/widget_dao.dart b/lib/storage/widget_dao.dart new file mode 100644 index 0000000..4be1239 --- /dev/null +++ b/lib/storage/widget_dao.dart @@ -0,0 +1,88 @@ +import 'package:flutter_unit/storage/app_storage.dart'; +import 'package:flutter_unit/app/enums.dart'; + +import 'po/widget_po.dart'; + + +class WidgetDao { + + final AppStorage storage; + + + WidgetDao(this.storage); + + Future insert(WidgetPo widget) async { + //插入方法 + final db = await storage.db; + String addSql = //插入数据 + "INSERT INTO " + "widget(id,name,nameCN,collected,family,lever,image,linkWidget,info) " + "VALUES (?,?,?,?,?,?,?,?,?);"; + return await db.transaction((tran) async => await tran.rawInsert(addSql, [ + widget.id, + widget.name, + widget.nameCN, + widget.collected, + widget.family, + widget.lever, + widget.image, + widget.linkWidget, + widget.info + ])); + } + + Future>> queryAll() async { + final db = await storage.db; + return await db.rawQuery("SELECT * " + "FROM widget"); + } + + Future>> queryByFamily(WidgetFamily family) async { + final db = await storage.db; + return await db.rawQuery( + "SELECT * " + "FROM widget WHERE family = ? ORDER BY lever DESC", + [family.index]); + } + + Future>> queryByIds(List ids) async { + final db = await storage.db; + + var sql = "SELECT * " + "FROM widget WHERE id in (${'?,' * (ids.length - 1)}?) "; + + return await db.rawQuery(sql, [...ids]); + } + + Future>> search(SearchArgs arguments) async { + final db = await storage.db; + return await db.rawQuery( + "SELECT * " + "FROM widget WHERE name like ? AND lever IN(?,?,?,?,?) ORDER BY lever DESC", + ["%${arguments.name}%", ...arguments.stars]); + } + + Future>> toggleCollect(int id) async { + final db = await storage.db; + var data = await db.rawQuery('SELECT collected FROM widget WHERE id = ?', [id]); + var collected = data.toList()[0]['collected']==1; + print('collected:$collected'); + return await db.rawQuery( + "UPDATE widget SET collected = ? " + "WHERE id = ?", + [collected ? 0 : 1, id]); + } + + Future>> queryCollect() async { + final db = await storage.db; + return await db.rawQuery("SELECT * " + "FROM widget WHERE collected = 1 ORDER BY family,lever DESC"); + } +} + +class SearchArgs { + final String name; + final List stars; + + const SearchArgs({this.name = '', this.stars = const [-1, -1, -1, -1, -1]}); +} diff --git a/lib/views/dialogs/dialog_about.dart b/lib/views/dialogs/dialog_about.dart new file mode 100644 index 0000000..0be88d3 --- /dev/null +++ b/lib/views/dialogs/dialog_about.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; + +class DialogAbout extends StatelessWidget { + static show(BuildContext context){ + showDialog(//内置方法,创建对话弹框 + context: context, + builder: (_) => DialogAbout()); + } + @override + Widget build(BuildContext context) { + var title = Row( + //标题 + children: [ + Image.asset( + "assets/images/icon_head.png", + width: 30, + height: 30, + ), + SizedBox( + width: 10, + ), + Expanded(child: Text("关于",style: TextStyle(fontSize: 18),)), + InkWell( + child: Icon(Icons.close), + onTap: ()=>Navigator.of(context).pop(), + ) + ], + ); + var content = Column( + //内容 + mainAxisSize: MainAxisSize.min, + children: [ +// Image.asset( +// "assets/images/icon_flutter.png", +// width: 50, +// ), + FlutterLogo(size: 50,), + SizedBox( + height: 20, + ), + Text( + "Flutter Unit ${Cons.version}", + ), + ]); + return AlertDialog(title: title, content: content, actions: [ + //左下角 + Padding( + padding: const EdgeInsets.only(right:15.0,bottom: 10,top: 10), + child: Column( + children: [ + Text( + "Power By GF·J·Toly\n张风捷特烈", + textAlign: TextAlign.center, + ), + ], + )) + ]); + } +} diff --git a/lib/views/items/collect_widget_list_item.dart b/lib/views/items/collect_widget_list_item.dart new file mode 100644 index 0000000..efed1d6 --- /dev/null +++ b/lib/views/items/collect_widget_list_item.dart @@ -0,0 +1,121 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_star/flutter_star.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/style/shape/techno_shape.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/components/permanent/circle_text.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +class CollectWidgetListItem extends StatelessWidget { + final WidgetModel data; + final Function(WidgetModel) onDelectItemClick; + CollectWidgetListItem({this.data,this.onDelectItemClick}); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Material( + color: itemColor.withAlpha(66), + shape: TechnoShapeBorder(color: itemColor), + child: Container( + height: 95, + padding: EdgeInsets.only(top: 10, left: 5, right: 10, bottom: 5), + child: Row( + children: [ + _buildLeading(), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTitle(), + _buildSummary(), + StarScore( + star: Star( + emptyColor: Colors.white, + size: 12, + fillColor: itemColor), + score: data.lever, + ) + ], + ), + ), + ], + ), + ), + ), + Positioned( + bottom: 5, + right: 5, + child: FeedbackWidget( + onPressed: (){ + if(onDelectItemClick!=null){ + onDelectItemClick(data); + } + }, + child: Icon( + CupertinoIcons.delete_solid, + color: Colors.red, + ), + )) + ], + ); + } + + Widget _buildLeading() => Padding( + padding: const EdgeInsets.only(left: 5, right: 5), + child: data.image == null + ? Material( + color: Colors.transparent, + child: CircleText( + text: data.name, + size: 50, + color: itemColor, + ), + ) + : CircleImage( + image: data.image, + size: 50, + ), + ); + + Color get itemColor => Color(Cons.tabColors[data.family.index]); + + Widget _buildTitle() { + return Row( + children: [ +// SizedBox(width: 10), + Expanded( + child: Text(data.name, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + shadows: [ + Shadow(color: Colors.white, offset: Offset(.3, .3)) + ])), + ), + ], + ); + } + + Widget _buildSummary() { + return Padding( + padding: const EdgeInsets.only(left: 5, bottom: 10, top: 5), + child: Container( + child: Text( + data.nameCN, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.grey[600], + fontSize: 14, + shadows: [Shadow(color: Colors.white, offset: Offset(.5, .5))]), + ), + ), + ); + } +} diff --git a/lib/views/items/coupon_widget_list_item.dart b/lib/views/items/coupon_widget_list_item.dart new file mode 100644 index 0000000..cce3f66 --- /dev/null +++ b/lib/views/items/coupon_widget_list_item.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_star/flutter_star.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/style/shape/coupon_shape_border.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/components/permanent/circle_text.dart'; +import 'package:flutter_unit/components/permanent/tag.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +class CouponWidgetListItem extends StatelessWidget { + final WidgetModel data; + final bool hasTopHole; + final bool hasBottomHole; + + CouponWidgetListItem( + {this.data, this.hasTopHole = true, this.hasBottomHole = false}); + + final List colors = Cons.tabColors; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + ClipPath( + clipper: ShapeBorderClipper( + shape: CouponShapeBorder( + hasTopHole: hasTopHole, + hasBottomHole: hasBottomHole, + hasLine: false, + edgeRadius: 25, + lineRate: 0.20)), + child: Container( + color: Color(colors[data.family.index]).withAlpha(66), + height: 95, + padding: EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 5), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(5.0), + child: Hero( + tag: "hero_widget_image_${data.id}", + child: data.image == null + ? Material( + color: Colors.transparent, + child: CircleText( + text: data.name, + size: 60, + color: invColor, + ), + ) + : CircleImage( + image: data.image, + size: 60, + ), + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [_buildTitle(), _buildSummary()], + ), + ), + ], + ), + ), + ), + _buildCollectTag(Theme.of(context).primaryColor) + ], + ); + } + + Color get invColor { + return Color(colors[data.family.index]); + } + + Widget _buildCollectTag(Color color) { + return Positioned( + top: 0, + left: 20, + child: BlocBuilder(builder: (_, s) { + var show = s.widgets.contains(data); + return Opacity( + opacity: show ? 1.0 : 0.0, + child: SizedOverflowBox( + alignment: Alignment.bottomCenter, + size: Size(0, 30 - 8.0), + child: Tag( + color: color, + shadowHeight: 8.0, + size: Size(20, 30), + ), + ), + ); + })); + } + + Widget _buildTitle() { + return Expanded( + child: Row( + children: [ + SizedBox(width: 10), + Expanded( + child: Text(data.name, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + shadows: [ + Shadow(color: Colors.white, offset: Offset(.3, .3)) + ])), + ), + StarScore( + star: Star(emptyColor: Colors.white, size: 15, fillColor: invColor), + score: data.lever, + ), + ], + ), + ); + } + + Widget _buildSummary() { + return Padding( + padding: const EdgeInsets.only(left: 10, bottom: 10, top: 5), + child: Container( + child: Text( + //尾部摘要 + data.info, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.grey[600], + fontSize: 14, + shadows: [Shadow(color: Colors.white, offset: Offset(.5, .5))]), + ), + ), + ); + } +} diff --git a/lib/views/items/techno_widget_list_item.dart b/lib/views/items/techno_widget_list_item.dart new file mode 100644 index 0000000..7aa7112 --- /dev/null +++ b/lib/views/items/techno_widget_list_item.dart @@ -0,0 +1,139 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_star/flutter_star.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/style/shape/techno_shape.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/components/permanent/circle_text.dart'; +import 'package:flutter_unit/components/permanent/tag.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +class TechnoWidgetListItem extends StatelessWidget { + final WidgetModel data; + + TechnoWidgetListItem({this.data}); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Material( + color: itemColor.withAlpha(66), + shape: TechnoShapeBorder(color: itemColor), + child: Container( + height: 95, + padding: EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 5), + child: Row( + children: [ + Wrap( + spacing: 5, + direction: Axis.vertical, + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + _buildLeading(), + StarScore( + star: Star( + emptyColor: Colors.white, + size: 12, + fillColor: itemColor), + score: data.lever, + ) + ], + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [_buildTitle(), _buildSummary()], + ), + ), + ], + ), + ), + ), + _buildCollectTag(Theme.of(context).primaryColor) + ], + ); + } + + Widget _buildCollectTag(Color color) { + return Positioned( + top: 0, + right: 40, + child: BlocBuilder(builder: (_, s) { + var show = s.widgets.contains(data); + return Opacity( + opacity: show ? 1.0 : 0.0, + child: SizedOverflowBox( + alignment: Alignment.bottomCenter, + size: Size(0, 30 - 8.0), + child: Tag( + color: color, + shadowHeight: 8.0, + size: Size(20, 30), + ), + ), + ); + })); + } + + Widget _buildLeading() => Padding( + padding: const EdgeInsets.only(left: 5, right: 5), + child: Hero( + tag: "hero_widget_image_${data.id}", + child: data.image == null + ? Material( + color: Colors.transparent, + child: CircleText( + text: data.name, + size: 60, + color: itemColor, + ), + ) + : CircleImage( + image: data.image, + size: 55, + ), + ), + ); + + Color get itemColor => Color(Cons.tabColors[data.family.index]); + + Widget _buildTitle() { + return Row( + children: [ + SizedBox(width: 10), + Expanded( + child: Text(data.name, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + shadows: [ + Shadow(color: Colors.white, offset: Offset(.3, .3)) + ])), + ), + ], + ); + } + + Widget _buildSummary() { + return Container( + padding: EdgeInsets.only(left: 10), + child: Text( + //尾部摘要 + data.info, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.grey[600], + fontSize: 14, + shadows: [Shadow(color: Colors.white, offset: Offset(.5, .5))]), + ), + ); + } +} diff --git a/lib/views/pages/about/about_app_page.dart b/lib/views/pages/about/about_app_page.dart new file mode 100644 index 0000000..01287e1 --- /dev/null +++ b/lib/views/pages/about/about_app_page.dart @@ -0,0 +1,242 @@ +import 'package:flutter/cupertino.dart'; +/// create by 张风捷特烈 on 2020-04-13 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AboutAppPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Stack( + children: [ + Column( + children: [ + Container( + height: 150, + width: MediaQuery.of(context).size.width, + margin: EdgeInsets.only(bottom: 50), + child: Image.asset( + 'assets/images/sabar.jpg', + fit: BoxFit.cover, + ), + ), + ], + ), + _buildBar(context), + Positioned( + bottom: 0, + left: 50, + child: CircleImage( + size: 100, + shadowColor: Theme.of(context).primaryColor, + image: AssetImage('assets/images/icon_head.png'), + )), + ], + ), + ), + Expanded( + child: SingleChildScrollView( + child: Container( + margin: EdgeInsets.all(24), + child: _buildInfo(), + ), + ), + ), + ], + ), + ); + } + + Widget _buildBar(BuildContext context) { + return Container( + height: kToolbarHeight, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + padding: EdgeInsets.only(left: 10), + child: Icon( + Icons.arrow_back, + size: 30, + color: Theme.of(context).primaryColor, + ), + ), + ), + Spacer(), + FeedbackWidget( + onPressed: () => + _launchURL("mailto:1981462002@qq.com?subject=来自Flutter Unit"), + child: Icon( + TolyIcon.icon_email, + size: 20, + color: Theme.of(context).primaryColor, + ), + ), + SizedBox( + width: 20, + ) + ], + ), + ); + } + + _launchURL(String url) async { + if (await canLaunch(url)) { + await launch(url); + } else { + debugPrint('Could not launch $url'); + } + } + + Widget _buildInfo() { + return Stack( + children: [ + Positioned( + right: 10, + top: 0, + child: Wrap( + spacing: 20, + children: [ +// FeedbackWidget( +// onPressed: () => _launchURL( +// "https://juejin.im/user/5b42c0656fb9a04fe727eb37"), +// child: Wrap( +// direction: Axis.vertical, +// crossAxisAlignment: WrapCrossAlignment.center, +// children: [ +// Icon( +// TolyIcon.icon_juejin, +// size: 35, +// color: Colors.blue, +// ), +// Text('掘金') +// ], +// )), + FeedbackWidget( + onPressed: () => + _launchURL("https://github.com/toly1994328/FlutterUnit"), + child: Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Icon( + TolyIcon.icon_github, + size: 35, + ), + Text('Github') + ], + )), + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Flutter Unit', + style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + ), + SizedBox(height: 20), + Text( + 'The Unity Of Flutter, The Unity Of Coder.', + style: TextStyle(fontSize: 16), + ), + SizedBox(height: 10), + Text( + 'Flutter的联合,编程者的联合。', + style: TextStyle(fontSize: 16), + ), + Divider( + height: 20, + ), + InfoPanel( + title: '项目简介', + info: ' Flutter Unit 是一个非盈利性的开源项目,' + '旨在提供全面的Flutter学习指南及编程者的交流技术的接口。' + '由【张风捷特烈】提供技术支持和全权维护。唯一开源网站网址: ' + 'https://github.com/toly1994328/FlutterUnit', + ), + Divider( + height: 20, + ), + InfoPanel( + title: 'Flutter Unit 1.0', + info: 'Flutter Unit 1.0 核心计划是收录widget,即widget集录。' + '目前收录组件204个,均可在app中进行查看。' + '项目中提供widget图鉴文件可供下载参考。功能主要如下:\n' + '○ 200+的Flutter 组件收录和详情介绍。\n' + '○ 对一些重要的组件提供操作体验。\n' + '○ link to功能,查看组件时可以切换到相关组件。\n' + '○ 组件收藏和取消收藏功能。\n' + '○ 主题、字体设置,代码风格等全局状态管理。\n' + '○ 搜索功能和组件星级分类。', + ), + Divider( + height: 20, + ), + InfoPanel( + title: 'Flutter Unit 2.0 计划', + info: 'Flutter Unit 2.0 尚在计划之中,如果说1.0是本王单枪匹马,' + '那2.0将是Flutter爱好者的共同努力。后面陆续会发布一些征集方案,' + '包括属性、布局、绘制、bug、要点集录等。吾想让Unit 成为一个Flutter的圣地,纯粹而强大,期待与你的共同携手。', + ) + ], + ), + ], + ); + } +} + +class InfoPanel extends StatelessWidget { + final String title; + final String info; + + + InfoPanel({this.title, this.info}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Circle(color: Theme.of(context).primaryColor,), Padding( + padding: const EdgeInsets.only(left: 15,top: 15,bottom: 15), + child: Text('$title',style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold),), + ) + ], + ), + Panel( + color: Theme.of(context).primaryColor.withAlpha(33), + child: Text( + '$info', + style: TextStyle(color: Colors.grey, + fontSize: 13, + shadows: [ + Shadow( + color: Colors.white, + offset: Offset(1,1) + ) + ]), + ), + ), + ], + ); + } +} diff --git a/lib/views/pages/about/about_me_page.dart b/lib/views/pages/about/about_me_page.dart new file mode 100644 index 0000000..894bfa1 --- /dev/null +++ b/lib/views/pages/about/about_me_page.dart @@ -0,0 +1,204 @@ +/// create by 张风捷特烈 on 2020-04-13 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AboutMePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + Column( + children: [ + Container( + height: 180, + width: MediaQuery.of(context).size.width, + margin: EdgeInsets.only(bottom: 50), + child: Image.asset( + 'assets/images/sabar.jpg', + fit: BoxFit.cover, + ), + ), + ], + ), + _buildBar(context), + Positioned( + bottom: 0, + left: 50, + child: CircleImage( + size: 100, + shadowColor: Theme.of(context).primaryColor, + image: AssetImage('assets/images/icon_head.png'), + )), + ], + ), + Expanded( + child: Container( + margin: EdgeInsets.all(24), + child: Stack(children: [ + Positioned( + right: 10, + top: 0, + child: _buildLinkIcon(), + ), + _buildInfo() + ]), + ), + ), + ], + ), + ); + } + + Widget _buildBar(BuildContext context) { + return Container( + height: kToolbarHeight, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + padding: EdgeInsets.only(left: 10), + child: Icon( + Icons.arrow_back, + size: 30, + color: Theme.of(context).primaryColor, + ), + ), + ), + Spacer(), + FeedbackWidget( + onPressed: () => + _launchURL("mailto:1981462002@qq.com?subject=来自Flutter Unit"), + child: Icon( + TolyIcon.icon_email, + size: 20, + color: Theme.of(context).primaryColor, + ), + ), + SizedBox( + width: 20, + ) + ], + ), + ); + } + + _launchURL(String url) async { + if (await canLaunch(url)) { + await launch(url); + } else { + debugPrint('Could not launch $url'); + } + } + + Widget _buildInfo() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '张风捷特烈', + style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), + ), + SizedBox(height: 20), + Text( + 'The King Of Coder. 「编程之王」', + style: TextStyle(fontSize: 16), + ), + SizedBox(height: 10), + Text( + '海的彼岸有我未曾见证的风采。', + style: TextStyle(fontSize: 16), + ), + Divider( + height: 18, + ), + + Text( + '微信群: 编程技术交流圣地-【Flutter群】\n' + '愿青梅煮酒,与君天涯共话。', + style: TextStyle(color: Colors.grey), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + width: 190, + child: Column( + children: [ + Image.asset('assets/images/wechat.jpg'), + Text( + '我的微信', + style: TextStyle(fontSize: 16), + ), + ], + ), + ), +// Container( +// width: 160, +// child: Column( +// children: [ +// Image.asset('assets/images/wei_x.jpg'), +// Text( +// '请我喝茶(慎扫)', +// style: TextStyle(fontSize: 16), +// ), +// ], +// ), +// ), + ], + ), + ], + ); + } + + Wrap _buildLinkIcon() { + return Wrap( + spacing: 20, + children: [ + FeedbackWidget( + onPressed: () => + _launchURL("https://juejin.im/user/5b42c0656fb9a04fe727eb37"), + child: Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Icon( + TolyIcon.icon_juejin, + size: 35, + color: Colors.blue, + ), + Text('掘金') + ], + )), + FeedbackWidget( + onPressed: () => + _launchURL("https://github.com/toly1994328"), + child: Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Icon( + TolyIcon.icon_github, + size: 35, + ), + SizedBox(height: 4,), + Text('Github') + ], + )), + ], + ); + } +} diff --git a/lib/views/pages/collect/collect_page.dart b/lib/views/pages/collect/collect_page.dart new file mode 100644 index 0000000..159a21d --- /dev/null +++ b/lib/views/pages/collect/collect_page.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/collect_widget_list_item.dart'; + + +class CollectPage extends StatelessWidget { + + + final gridDelegate = const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + childAspectRatio: 1 / 0.5, + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('收藏集'), + actions: [ + IconButton(icon: Icon(Icons.add,size: 30,), onPressed: (){ + + }) + + ], + ), + body: BlocBuilder(builder: (_, state) { + return GridView.builder( + padding: EdgeInsets.all(10), + itemCount: state.widgets.length, + itemBuilder: (_, index) => Container( + child: GestureDetector( + onTap: () => _toDetailPage(context, state.widgets[index]), + child: CollectWidgetListItem( + data: state.widgets[index], + onDelectItemClick: (model) => _deleteCollect(context, model), + )), + ), + gridDelegate: gridDelegate, + ); + }), + ); + } + + _deleteCollect(BuildContext context, WidgetModel model) => + BlocProvider.of(context) + .add(ToggleCollectEvent(id: model.id)); + + _toDetailPage(BuildContext context, WidgetModel model) { + BlocProvider.of(context).add(FetchWidgetDetail(model)); + Navigator.pushNamed(context, Router.widget_detail); + } +} diff --git a/lib/views/pages/common/empty_page.dart b/lib/views/pages/common/empty_page.dart new file mode 100644 index 0000000..5b1fafe --- /dev/null +++ b/lib/views/pages/common/empty_page.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-07 +/// contact me by email 1981462002@qq.com +/// 说明: + +class EmptyPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + height: 300, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.style, color: Colors.grey, size: 80.0), + Container( + padding: EdgeInsets.only(top: 16.0), + child: Text( + "暂无数据", + style: TextStyle( + color: Colors.grey, + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/views/pages/detail/widget_detail_page.dart b/lib/views/pages/detail/widget_detail_page.dart new file mode 100644 index 0000000..d4e107c --- /dev/null +++ b/lib/views/pages/detail/widget_detail_page.dart @@ -0,0 +1,217 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_star/flutter_star.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/app/utils/Toast.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/blocs/detail/detail_state.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:flutter_unit/components/project/widget_node_panel.dart'; +import 'package:flutter_unit/model/node_model.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/widgets/widgets_map.dart'; + +class WidgetDetailPage extends StatefulWidget { + @override + _WidgetDetailPageState createState() => _WidgetDetailPageState(); +} + +class _WidgetDetailPageState extends State { + @override + void deactivate() { + BlocProvider.of(context).add(ResetDetailState()); + super.deactivate(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder(builder: (_, state) { + if (state is DetailWithData) { + return WillPopScope( + onWillPop: () async { +// Future.delayed(Duration(milliseconds: 500)).then((v){ +// BlocProvider.of(context).add(ResetDetailState()); +// }); + return true; + }, + child: Scaffold( + appBar: AppBar( + title: Text(state.widgetModel.name), + actions: [ + buildCollectButton(state.widgetModel, context), + ], + ), + body: SingleChildScrollView( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + _buildLeft(state.widgetModel), + _buildRight(state.widgetModel), + ], + ), + Divider(), + Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 15, right: 5), + child: Icon( + Icons.link, + color: Colors.blue, + ), + ), + Text( + '相关组件', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ), + ], + ), + _buildLinkTo( + context, + state.links, + ), + Divider(), + _buildNodes(state.nodes, state.widgetModel.name) + ], + ), + )), + ), + ); + } + return Container(); + }); + } + + Widget buildCollectButton(WidgetModel model, BuildContext context) { + //监听 CollectBloc 伺机弹出toast + return BlocListener( + listener: (ctx, st) { + bool collected = st.widgets.contains(model); + Toast.toast(ctx, + collected ? "收藏【${model.name}】组件成功!" : "已取消【${model.name}】组件收藏!"); + }, + child: FeedbackWidget( + onPressed: () => BlocProvider.of(context) + .add(ToggleCollectEvent(id: model.id)), + child: BlocBuilder(builder: (_, s) { + return Padding( + padding: const EdgeInsets.only(right: 20.0), + child: Icon( + s.widgets.contains(model) + ? TolyIcon.icon_star_ok + : TolyIcon.icon_star_add, + size: 25, + ), + ); + }), + )); + } + + final List colors = Cons.tabColors; + + Widget _buildLeft(WidgetModel model) => Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 20.0, left: 20), + child: Text( + model.nameCN, + style: TextStyle( + fontSize: 20, + color: Color(0xff1EBBFD), + fontWeight: FontWeight.bold), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Panel(child: Text(model.info)), + ) + ], + ), + ); + + Widget _buildRight(WidgetModel model) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 100, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Hero( + tag: "hero_widget_image_${model.id}", + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(8)), + child: model.image == null + ? Image.asset('assets/images/caver.jpeg') + : Image(image: model.image))), + ), + ), + StarScore( + score: model.lever, + star: Star(size: 15, fillColor: Colors.blue), + ) + ], + ); + + Widget _buildNodes(List nodes, String name) { + var globalState = BlocProvider.of(context).state; + + return Column( + children: nodes + .asMap() + .keys + .map((i) => WidgetNodePanel( + codeStyle: Cons.codeThemeSupport.keys + .toList()[globalState.codeStyleIndex], + codeFamily: 'Inconsolata', + text: nodes[i].name, + subText: nodes[i].subtitle, + code: nodes[i].code, + show: WidgetsMap.map(name)[i], + )) + .toList()); + } + + _buildLinkTo(BuildContext context, List links) { + if (links == null || links.isEmpty) { + return Padding( + padding: EdgeInsets.only(left: 10), + child: Chip( + backgroundColor: Colors.grey.withAlpha(120), + labelStyle: TextStyle(fontSize: 12, color: Colors.white), + label: Text('暂无链接组件'), + )); + } else { + return Padding( + padding: const EdgeInsets.only(left: 10.0, top: 10), + child: Wrap( + spacing: 5, + children: links + .map((e) => ActionChip( + onPressed: () { + BlocProvider.of(context) + .add(FetchWidgetDetail(e)); + }, + elevation: 2, + shadowColor: Colors.orange, + backgroundColor: Theme.of(context).primaryColor, + labelStyle: TextStyle(fontSize: 12, color: Colors.white), + label: Text('${e.name}'), + )) + .toList(), + ), + ); + } + } +} diff --git a/lib/views/pages/home/background.dart b/lib/views/pages/home/background.dart new file mode 100644 index 0000000..e0efe3b --- /dev/null +++ b/lib/views/pages/home/background.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class Background extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Opacity( + opacity: 0.05, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/sabar.jpg'), + fit: BoxFit.cover), + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(400), + topLeft: Radius.circular(400))), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/pages/home/home_page.dart b/lib/views/pages/home/home_page.dart new file mode 100644 index 0000000..277235a --- /dev/null +++ b/lib/views/pages/home/home_page.dart @@ -0,0 +1,125 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/convert.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/widgets/home_bloc.dart'; +import 'package:flutter_unit/blocs/widgets/home_event.dart'; +import 'package:flutter_unit/blocs/widgets/home_state.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/pages/common/empty_page.dart'; +import 'package:flutter_unit/views/items/coupon_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; +import 'package:flutter_unit/views/pages/home/toly_app_bar.dart'; + +import 'background.dart'; + +class HomePage extends StatefulWidget { + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + ScrollController _ctrl; + double _limitY = 35; + double _height = kToolbarHeight * 2 - 20; + + @override + void initState() { + _ctrl = ScrollController()..addListener(_updateAppBarHeight); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: TolyAppBar( + preferredSize: Size.fromHeight(_height), + onItemClick: _switchTab, + ), + body: Stack( + children: [ + if (BlocProvider.of(context).state.showBackGround) + Background(), + BlocBuilder( + builder: (_, state) => _buildContent(state)) + ], + ), + ); + } + + Widget _buildContent(HomeState state) { + if (state is WidgetsLoaded) { + var items = state.widgets; + if (items.isEmpty) return EmptyPage(); + return ListView.builder( + controller: _ctrl, + itemBuilder: (_, index) => Container( + margin: EdgeInsets.symmetric(horizontal: 15, vertical: 8), + child: FeedbackWidget( + duration: Duration(milliseconds: 200), + onPressed: () => _toDetailPage(items[index]), + child: _mapItemByType(items[index])), + ), + itemCount: items.length); + } + if (state is WidgetsLoadFailed) { + return Container( + child: Text('加载数据异常'), + ); + } + return Container(); + } + + Widget _mapItemByType(WidgetModel model) { + var index = BlocProvider.of(context).state.itemStyleIndex; + switch (index) { + case 0: + return TechnoWidgetListItem( + data: model, + ); + case 1: + return CouponWidgetListItem( + data: model, + ); + case 2: + return CouponWidgetListItem( + hasTopHole:false, + data: model, + ); + case 3: + return CouponWidgetListItem( + hasTopHole:true,hasBottomHole:true, + data: model, + ); + + } + return TechnoWidgetListItem( + data: model, + ); + } + + _updateAppBarHeight() { + if (_ctrl.offset < _limitY * 4) { + setState(() { + _height = kToolbarHeight * 2 - 20 - _ctrl.offset / 4; + }); + } + } + + _switchTab(int index, Color color) { + if (_ctrl.hasClients) _ctrl.jumpTo(0); + BlocProvider.of(context) + .add(EventTabTap(Convert.toFamily(index))); + } + + _toDetailPage(WidgetModel model) async{ + BlocProvider.of(context).add(FetchWidgetDetail(model)); + await Future.delayed(Duration(milliseconds: 200)); + Navigator.pushNamed(context, Router.widget_detail); + } +} diff --git a/lib/views/pages/home/toly_app_bar.dart b/lib/views/pages/home/toly_app_bar.dart new file mode 100644 index 0000000..89b2d84 --- /dev/null +++ b/lib/views/pages/home/toly_app_bar.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; + +class TolyAppBar extends StatefulWidget implements PreferredSizeWidget { + final Function(int, Color) onItemClick; + + @override + _TolyAppBarState createState() => _TolyAppBarState(); + + final Size preferredSize; + + TolyAppBar({this.onItemClick, this.preferredSize,}); +} + +class _TolyAppBarState extends State + with SingleTickerProviderStateMixin { + double _width = 0; + int _selectIndex = 0; + double factor = 1.0; + + List colors = Cons.tabColors; + List info = Cons.tabs; + + AnimationController _controller; + + @override + void initState() { + _controller = + AnimationController(duration: Duration(milliseconds: 300), vsync: this) + ..addListener(() => setState(() => factor = _controller.value)) + ..addStatusListener((s) { + if (s == AnimationStatus.completed) { + setState(() {}); + } + }); + + super.initState(); + } + + int get nextIndex => (_selectIndex + 1) % colors.length; + + @override + Widget build(BuildContext context) { + _width = MediaQuery.of(context).size.width / colors.length; + + return Container( + alignment: Alignment.center, + child: Flow( + delegate: TolyAppBarDelegate( + _selectIndex, factor, widget.preferredSize.height), + children: [ + ...colors.map((e) { + var isSelected = _selectIndex == colors.indexOf(e); + return GestureDetector( + onTap: () { + setState(() { + _controller.reset(); + _controller.forward(); + _selectIndex = colors.indexOf(e); + if (widget.onItemClick != null) + widget.onItemClick(_selectIndex, Color(e)); + }); + }, + child: Container( + alignment: Alignment(0, 0.4), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: isSelected + ? Colors.transparent + : Color(colors[_selectIndex]), + offset: Offset(1, 1), + blurRadius: 2) + ], + color: Color(e), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(15), + bottomRight: Radius.circular(15), + )), + height: widget.preferredSize.height + 20, + width: _width, + child: Text( + info[colors.indexOf(e)], + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(0.5, 0.5), + blurRadius: 0.5) + ]), + ), + )); + }).toList(), + ...colors.map((e) => Circle( + color: Color(e), + radius: 6, + )) + ]), + ); + } +} + +class TolyAppBarDelegate extends FlowDelegate { + final int selectIndex; + final double factor; + final double height; + + TolyAppBarDelegate(this.selectIndex, this.factor, this.height); + + @override + void paintChildren(FlowPaintingContext context) { + double ox = 0; + double obx = 0; + + for (int i = 0; i < context.childCount / 2; i++) { + var cSize = context.getChildSize(i); + if (i == selectIndex) { + context.paintChild(i, + transform: Matrix4.translationValues(ox, 20.0 * factor - 20, 0.0)); + ox += cSize.width; + } else { + context.paintChild(i, + transform: Matrix4.translationValues(ox, -20, 0.0)); + ox += cSize.width; + } + } + for (int i = (context.childCount / 2).floor(); + i < context.childCount; + i++) { + if (i - (context.childCount / 2).floor() == selectIndex) { + obx += context.getChildSize(0).width; + } else { + context.paintChild(i, + transform: Matrix4.translationValues( + obx + context.getChildSize(0).width / 2 - 5, height + 5, 0)); + obx += context.getChildSize(0).width; + } + } + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) { + return true; + } +} diff --git a/lib/views/pages/navigation/unit_bottom_bar.dart b/lib/views/pages/navigation/unit_bottom_bar.dart new file mode 100644 index 0000000..9b81abe --- /dev/null +++ b/lib/views/pages/navigation/unit_bottom_bar.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-11 +/// contact me by email 1981462002@qq.com +/// 说明: + +class UnitBottomBar extends StatefulWidget { + final Color color; + final Map itemData; + final Function(int) onItemClick; + + UnitBottomBar( + {this.color = Colors.blue, + @required this.itemData, + @required this.onItemClick}); + + @override + _UnitBottomBarState createState() => _UnitBottomBarState(); +} + +class _UnitBottomBarState extends State { + int _position = 0; + + @override + Widget build(BuildContext context) { + return BottomAppBar( + elevation: 0, + shape: CircularNotchedRectangle(), + notchMargin: 5, + color: widget.color, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: widget.itemData.keys + .map((e) => _buildChild(info.indexOf(e), widget.color)) + .toList(), + )); + } + + List get info => widget.itemData.keys.toList(); + + Widget _buildChild(int i, Color color) { + var active = i == _position; + bool left = i == 0; + return GestureDetector( + onTap: () => setState(() { + _position = i; + if (widget.onItemClick != null) { + widget.onItemClick(_position); + } + }), + child: Material( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: left + ? BorderRadius.only(topRight: Radius.circular(10)) + : BorderRadius.only(topLeft: Radius.circular(10))), + child: Container( + margin: left + ? EdgeInsets.only(top: 2, right: 2) + : EdgeInsets.only(top: 2, left: 2), + alignment: Alignment.center, + decoration: BoxDecoration( + color: color.withAlpha(88), + borderRadius: left + ? BorderRadius.only(topRight: Radius.circular(10)) + : BorderRadius.only(topLeft: Radius.circular(10))), + height: 45, + width: 100, + child: Icon( + widget.itemData[info[i]], + color: active ? color : Colors.white, + size: active ? 28 : 24, + )), + ), + ); + } +} diff --git a/lib/views/pages/navigation/unit_navigation.dart b/lib/views/pages/navigation/unit_navigation.dart new file mode 100644 index 0000000..3fca728 --- /dev/null +++ b/lib/views/pages/navigation/unit_navigation.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/blocs/widgets/home_bloc.dart'; +import 'package:flutter_unit/blocs/widgets/home_state.dart'; +import 'package:flutter_unit/views/pages/navigation/unit_bottom_bar.dart'; +import '../collect/collect_page.dart'; +import '../home/home_page.dart'; +import '../setting/home_drawer.dart'; + +class UnitNavigation extends StatefulWidget { + @override + _UnitNavigationState createState() => _UnitNavigationState(); +} + +class _UnitNavigationState extends State { + PageController _controller; //页面控制器,初始0 + + @override + void initState() { + _controller = PageController(); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); //释放控制器 + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (_, state) => + Scaffold( + drawer: HomeDrawer(), + //左滑页 + endDrawer: HomeDrawer(), + //右滑页 + floatingActionButtonLocation: + FloatingActionButtonLocation.centerDocked, + floatingActionButton: FloatingActionButton( + backgroundColor: state.homeColor, + child: Icon(Icons.search), + onPressed: () => Navigator.of(context).pushNamed(Router.search), + ), + body: PageView( + physics: NeverScrollableScrollPhysics(), + //使用PageView实现页面的切换 + controller: _controller, + children: [ + HomePage(), + CollectPage(), + ], + ), + bottomNavigationBar: UnitBottomBar( + color: state.homeColor, + itemData: Cons.ICONS_MAP, + onItemClick: _onTapNav) + ) + ); + } + + _onTapNav(int index) { + _controller.animateToPage(index, + duration: Duration(milliseconds: 200), curve: Curves.linear); + if (index == 1) { + BlocProvider.of(context).add(EventSetCollectData()); + } + } +} + diff --git a/lib/views/pages/search/app_search_bar.dart b/lib/views/pages/search/app_search_bar.dart new file mode 100644 index 0000000..8285482 --- /dev/null +++ b/lib/views/pages/search/app_search_bar.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/blocs/search/search_bloc.dart'; +import 'package:flutter_unit/blocs/search/search_event.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; + + +class AppSearchBar extends StatefulWidget { + + + @override + _AppSearchBarState createState() => _AppSearchBarState(); +} + +class _AppSearchBarState extends State { + var _controller=TextEditingController();//文本控制器 + + @override + Widget build(BuildContext context) => Container( + height: 35, + child: + TextField( + autofocus: false, //自动聚焦,闪游标 + controller: _controller, + maxLines: 1, + decoration: InputDecoration(//输入框装饰 + filled: true,//填满 + fillColor: Colors.white,//白色 + prefixIcon: Icon(Icons.search),//前标 + contentPadding: EdgeInsets.only(top: 0),//调整文字边距 + border: UnderlineInputBorder( + borderSide: BorderSide.none,//去边线 + borderRadius: BorderRadius.all(Radius.circular(15)), + ), + hintText: "搜点啥...",//提示 + hintStyle: TextStyle(fontSize: 14)//提示样式 + ), + onChanged: (str) => BlocProvider.of(context) + .add(EventTextChanged(args:SearchArgs(name: str,stars: [1,2,3,4,5]))), + + onSubmitted: (str) {//提交后 + FocusScope.of(context).requestFocus(FocusNode()); //收起键盘 +// _controller.clear(); + }, + )); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } +} diff --git a/lib/views/pages/search/empty_page.dart b/lib/views/pages/search/empty_page.dart new file mode 100644 index 0000000..7b6efd6 --- /dev/null +++ b/lib/views/pages/search/empty_page.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class EmptyPage extends StatelessWidget { + + + @override + Widget build(BuildContext context) { + return Center(child: Container( + alignment: FractionalOffset.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.event_busy, color: Colors.orangeAccent, size: 120.0), + Container( + padding: EdgeInsets.only(top: 16.0), + child: Text( + "没数据,哥也没办法,(≡ _ ≡)/~┴┴", + style: TextStyle( + fontSize: 20, + color: Colors.orangeAccent, + ), + ), + ) + ], + ), + ),); + } +} diff --git a/lib/views/pages/search/error_page.dart b/lib/views/pages/search/error_page.dart new file mode 100644 index 0000000..b90fd94 --- /dev/null +++ b/lib/views/pages/search/error_page.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class ErrorPage extends StatelessWidget { + + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.error_outline, color: Colors.red[300], size: 120.0), + Container( + padding: EdgeInsets.only(top: 16.0), + child: Text( + "好像有些小错误,ε=(#>д<)ノ", + style: TextStyle( + fontSize: 20, + color: Colors.red[300], + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/views/pages/search/loading_page.dart b/lib/views/pages/search/loading_page.dart new file mode 100644 index 0000000..f092842 --- /dev/null +++ b/lib/views/pages/search/loading_page.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class LoadingPage extends StatelessWidget { + + + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + alignment: Alignment.center, + child: CircularProgressIndicator(backgroundColor: Colors.blue,valueColor:AlwaysStoppedAnimation(Colors.orangeAccent) ,), + ); + } +} diff --git a/lib/views/pages/search/not_search_page.dart b/lib/views/pages/search/not_search_page.dart new file mode 100644 index 0000000..cc4fd9e --- /dev/null +++ b/lib/views/pages/search/not_search_page.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class NotSearchPage extends StatelessWidget { + + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.search, color: Colors.blue, size: 120.0), + Container( + padding: EdgeInsets.only(top: 16.0), + child: Text( + "哥们,搜点啥...≧◔◡◔≦", + style: TextStyle( + fontSize: 20, + color: Colors.blue, + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/views/pages/search/serach_page.dart b/lib/views/pages/search/serach_page.dart new file mode 100644 index 0000000..d98f00b --- /dev/null +++ b/lib/views/pages/search/serach_page.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/blocs/search/search_bloc.dart'; +import 'package:flutter_unit/blocs/search/search_event.dart'; +import 'package:flutter_unit/blocs/search/search_state.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; +import 'package:flutter_unit/views/pages/search/app_search_bar.dart'; +import 'package:flutter_unit/views/pages/search/error_page.dart'; +import 'package:flutter_unit/views/pages/search/loading_page.dart'; +import 'package:flutter_unit/views/pages/search/not_search_page.dart'; +import 'package:flutter_unit/views/pages/search/start_filter.dart'; + +import 'empty_page.dart'; + + +class SearchPage extends StatefulWidget { + @override + _SearchPageState createState() => _SearchPageState(); +} + +class _SearchPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: WillPopScope( + onWillPop: () async { + //返回时 情空搜索 + BlocProvider.of(context).add(EventTextChanged(args: SearchArgs())); + return true; + }, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + SliverToBoxAdapter(child: _buildStarFilter()), + BlocBuilder(builder: (_, state) => _buildBodyByState(state)) + ], + ), + ), + ); + } + + Widget _buildSliverAppBar() { + return SliverAppBar( + pinned: true, + title: AppSearchBar(), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 15.0), + child: Icon(TolyIcon.icon_sound), + ) + ], + ); + } + + Widget _buildStarFilter() => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 10.0, left: 20, bottom: 5), + child: Wrap( + spacing: 5, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Circle( + radius: 5, + color: Colors.orange, + ), + Text( + '星级查询', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold), + ), + ], + ), + ), + MultiChipFilter( + data: [1, 2, 3, 4, 5], + avatarBuilder: (_, index) => + CircleAvatar(child: Text((index + 1).toString())), + labelBuilder: (_, selected) => Icon( + Icons.star, + color: selected ? Colors.blue : Colors.grey, + size: 18, + ), + onChange: _doSelectStart, + ), + Divider() + ], + ); + + Widget _buildBodyByState(SearchState state) { + if (state is SearchStateNoSearch) return SliverToBoxAdapter(child: NotSearchPage(),); + if (state is SearchStateLoading) return SliverToBoxAdapter(child: LoadingPage()); + if (state is SearchStateError) return SliverToBoxAdapter(child: ErrorPage()); + if (state is SearchStateSuccess) return _buildSliverList(state.result); + if (state is SearchStateEmpty) return SliverToBoxAdapter(child: EmptyPage()); + return NotSearchPage(); + } + + Widget _buildSliverList(List models) => SliverList( + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + margin: EdgeInsets.symmetric(horizontal: 15, vertical: 5), + child: InkWell( + onTap: () => _toDetailPage(models[index]), + child: TechnoWidgetListItem( + data: models[index], + ))), + childCount: models.length), + ); + + _doSelectStart(List select) { + var temp = select.map((e)=>e+1).toList(); + if (temp.length < 5) { + temp.addAll(List.generate(5 - temp.length, (e) => -1)); + } + BlocProvider.of(context) + .add(EventTextChanged(args: SearchArgs(name: '', stars: temp))); + } + + _toDetailPage(WidgetModel model) { + BlocProvider.of(context).add(FetchWidgetDetail(model)); +// BlocProvider.of(context).add(EventSetCollect(collect:model.collected)); + Navigator.pushNamed(context, Router.widget_detail); + } +} diff --git a/lib/views/pages/search/start_filter.dart b/lib/views/pages/search/start_filter.dart new file mode 100644 index 0000000..eb5d691 --- /dev/null +++ b/lib/views/pages/search/start_filter.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/blocs/search/search_bloc.dart'; +import 'package:flutter_unit/blocs/search/search_event.dart'; +import 'package:flutter_unit/storage/widget_dao.dart'; + +/// create by 张风捷特烈 on 2020-04-07 +/// contact me by email 1981462002@qq.com +/// 说明: + +typedef BoolWidgetBuilder = Widget Function(BuildContext context, bool selected); + +class MultiChipFilter extends StatefulWidget { + final List data; + final BoolWidgetBuilder labelBuilder; + final IndexedWidgetBuilder avatarBuilder; + final Function(List) onChange; + + MultiChipFilter({@required this.data,@required this.labelBuilder,this.avatarBuilder,@required this.onChange}); + + @override + _MultiChipFilterState createState() => _MultiChipFilterState(); +} + +class _MultiChipFilterState extends State> { + List _selected = []; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: widget.data.map((e) => + _buildChild(context,widget.data.indexOf(e))).toList(), + ); + } + + Widget _buildChild(BuildContext context,int index) { + bool selected = _selected.contains(index); + return FilterChip( + selectedColor: Colors.orange.withAlpha(55), + labelPadding: EdgeInsets.only(left: 5,right: 5), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + pressElevation: 5, + elevation: 3, + avatar: widget.avatarBuilder==null?null:widget.avatarBuilder(context,index), + label: widget.labelBuilder(context,selected), + selected: selected, + onSelected: (bool value) { + setState(() { + if (value) { + _selected.add(index); + } else { + _selected.removeWhere((i) => i == index); + } + if(widget.onChange!=null) widget.onChange(_selected); + }); + }, + ); + } +} + +//class StartFilter extends StatefulWidget { +// @override +// _StartFilterState createState() => _StartFilterState(); +//} +// +//class _StartFilterState extends State { +// List data = [1,2,3,4,5]; +// List _selected = []; +// +// @override +// Widget build(BuildContext context) { +// return Row( +// mainAxisAlignment: MainAxisAlignment.spaceEvenly, +// children: data.map((e) => +// _buildChild(e)).toList(), +// ); +// } +// +// Widget _buildChild(int e) { +// bool selected = _selected.contains(e); +// return FilterChip( +// selectedColor: Colors.orange.withAlpha(55), +// labelPadding: EdgeInsets.only(left: 5,right: 5), +// selectedShadowColor: Colors.blue, +// shadowColor: Colors.orangeAccent, +// pressElevation: 5, +// elevation: 3, +// avatar: CircleAvatar(child: Text((data.indexOf(e)+1).toString())), +// label: Icon(Icons.star,color: selected?Colors.blue:Colors.grey,size: 18,), +// selected: selected, +// onSelected: (bool value) { +// setState(() { +// if (value) { +// _selected.add(e); +// } else { +// _selected.removeWhere((name) => name == e); +// } +// var args = _selected.map((e)=>e).toList(); +// if(args.length<5){ +// args.addAll(List.generate(5-args.length, (e)=>-1)); +// } +// BlocProvider.of(context) +// .add(EventTextChanged(args:SearchArgs(name: '',stars: args))); +// }); +// }, +// ); +// } +//} + + + diff --git a/lib/views/pages/setting/code_style_setting.dart b/lib/views/pages/setting/code_style_setting.dart new file mode 100644 index 0000000..164286a --- /dev/null +++ b/lib/views/pages/setting/code_style_setting.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_event.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/components/permanent/code/code_widget.dart'; +import 'package:flutter_unit/components/permanent/code/highlighter_style.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; + +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +class CodeStyleSettingPage extends StatelessWidget { + final code = """ +const String _kCounty = 'China'; + +class Hello { + final String name;//言语 + final String county;//国家 + final int age;//年龄 + + Hello({ + this.name = "张风捷特烈", + this.age = 26, + this.county = _kCounty + }); +}"""; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('代码高亮样式'), + ), + body: BlocBuilder( + builder: (_, state) => _buildFontCell(context, + Cons.codeThemeSupport.keys.toList(), state.codeStyleIndex)), + ); + } + + Widget _buildFontCell( + BuildContext context, List styles, int index) { + return ListView.builder( + itemCount: styles.length, + itemBuilder: (_ctx, i) => FeedbackWidget( + a: 0.95, + duration: Duration(milliseconds: 200), + onPressed: (){ + BlocProvider.of(context).add(EventSwitchCoderTheme(i)); + }, + child: Stack( + fit: StackFit.passthrough, + children: [ + Card( + margin: EdgeInsets.all(10), + child: CodeWidget( + code: code, + style: styles[i], + ), + ), + + Positioned( + right: 20, + bottom: 20, + child: Text(Cons.codeThemeSupport.values.toList()[i],style: TextStyle( + fontSize: 14, + color: styles[i].stringStyle.color, + shadows: [Shadow( + color: Colors.white, + offset: Offset(.5,.5), + blurRadius: 1 + ),] + ),), + ), + + if(index == i) + Positioned( + right: 20, + top: 20, + child: Circle(radius: 10, + color: Theme.of(context).primaryColor, + child: Icon(Icons.check,color:Colors.white,size: 15,),), + ) + ], + ), + )); + } +} diff --git a/lib/views/pages/setting/font_setting.dart b/lib/views/pages/setting/font_setting.dart new file mode 100644 index 0000000..4532564 --- /dev/null +++ b/lib/views/pages/setting/font_setting.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_event.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; + +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +class FontSettingPage extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('字体设置 - font setting'), + ), + body: BlocBuilder( + builder: (_, state) => _buildFontCell( + context, Cons.fontFamilySupport, state.fontFamily)), + ); + } + + Widget _buildFontCell( + BuildContext context, List fontFamilySupport, String fontFamily) { + return GridView.count( + padding: EdgeInsets.only(top: 20, left: 10, right: 10), + shrinkWrap: true, + crossAxisCount: 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + childAspectRatio: 1.5, + children: fontFamilySupport + .map((e) => FeedbackWidget( + a: 0.95, + duration: Duration(milliseconds: 200), + onPressed: () { + BlocProvider.of(context) + .add(EventSwitchFontFamily(e)); + }, + child: Card( + child: GridTile( + header: Container( + padding: EdgeInsets.only(left: 10, right: 5), + height: 30, + color: fontFamily == e + ? Colors.blue.withAlpha(88) + : Colors.grey.withAlpha(88), + child: Row( + children: [ + Text(e, + style: TextStyle( + color: Colors.black, + fontFamily: e, + )), + Spacer(), + if (fontFamily == e) Circle(color: Theme.of(context).primaryColor,) + ], + ), + ), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Colors.blueAccent.withAlpha(22), + Colors.blueAccent.withAlpha(22), + Theme.of(context).primaryColor.withAlpha(88) + ])), + alignment: Alignment(0, 0.4), + child: Text( + '张风捷特烈\n@toly1994', + style: TextStyle(fontFamily: e, fontSize: 16), + )), + ), + ))) + .toList(), + ); + } +} diff --git a/lib/views/pages/setting/home_drawer.dart b/lib/views/pages/setting/home_drawer.dart new file mode 100644 index 0000000..a4cfddb --- /dev/null +++ b/lib/views/pages/setting/home_drawer.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/blocs/widgets/home_bloc.dart'; +import 'package:flutter_unit/blocs/widgets/home_state.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +class HomeDrawer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Drawer( + elevation: 3, + child: _buildChild(context), + ); + } + + Widget _buildChild(BuildContext context) => + BlocBuilder( + builder: (_, state) => Container( + color: state.homeColor.withAlpha(33), + child: ListView( + padding: EdgeInsets.zero, + children: [ + _buildDrawerHeader(state.homeColor), + ListTile( + leading: Icon( + TolyIcon.icon_them, + color: Theme.of(context).primaryColor, + ), + trailing: _nextIcon(context), + title: Text('我的主题'), + onTap: () { + Navigator.of(context).pushNamed(Router.setting); + }, + ), + ListTile( + leading: Icon( + TolyIcon.icon_star, + color: Theme.of(context).primaryColor, + ), + title: Text('我的收藏'), + trailing: _nextIcon(context), + onTap: () { + Navigator.of(context).pushNamed(Router.collect); + }, + ), + Divider( + height: 1, + ), + _buildFlutterUnit(context), + ListTile( + leading: Icon( + TolyIcon.icon_code, + color: Theme.of(context).primaryColor, + ), + title: Text('Dart 手册'), + trailing: _nextIcon(context), + onTap: () {}, + ), + Divider( + height: 1, + ), + ListTile( + leading: Icon( + TolyIcon.icon_layout, + color: Theme.of(context).primaryColor, + ), + title: Text('数据统计'), + trailing: _nextIcon(context), + onTap: () {}, + ), + ListTile( + leading: Icon( + Icons.info, + color: Theme.of(context).primaryColor, + ), + title: Text('关于应用'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.about_app), + ), + ListTile( + leading: Icon( + TolyIcon.icon_kafei, + color: Theme.of(context).primaryColor, + ), + title: Text('联系本王'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.about_me), + ), + ], + ), + )); + + Widget _buildFlutterUnit(BuildContext context) => ExpansionTile( + backgroundColor: Colors.white70, + leading: Icon( + Icons.extension, + color: Theme.of(context).primaryColor, + ), + title: Text('Flutter 集录'), + children: [ + ListTile( + leading: Icon( + TolyIcon.icon_tag, + color: Theme.of(context).primaryColor, + ), + title: Text('属性集录'), + trailing: _nextIcon(context), + onTap: () { + Navigator.of(context).pushNamed(Router.attr); + }, + ), + ListTile( + leading: Icon( + Icons.palette, + color: Theme.of(context).primaryColor, + ), + title: Text('绘画集录'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.paint), + ), + ListTile( + leading: Icon( + Icons.widgets, + color: Theme.of(context).primaryColor, + ), + title: Text('布局集录'), + trailing: _nextIcon(context), + onTap: () { + Navigator.of(context).pushNamed(Router.layout); + }, + ), + ListTile( + leading: Icon( + TolyIcon.icon_bug, + color: Theme.of(context).primaryColor, + ), + trailing: _nextIcon(context), + title: Text('bug/feature 集录'), + onTap: () { + Navigator.of(context).pushNamed(Router.bug); + }, + ), + ], + ); + + Widget _buildDrawerHeader(Color color) => DrawerHeader( + padding: EdgeInsets.only(top: 10, left: 15), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/wy_300x200_filter.jpg'), + fit: BoxFit.cover), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Wrap( + spacing: 10, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + FlutterLogo( + colors: Colors.orange, + size: 35, + ), + Text( + 'Flutter Unit', + style: TextStyle(fontSize: 24, color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 3) + ]), + ), + ], + ), + SizedBox( + height: 15, + ), + Text( + 'The Unity Of Flutter, The Unity Of Coder.', + style: TextStyle(fontSize: 15, color: Colors.white, shadows: [ + Shadow( + color: color, offset: Offset(.5, .5), blurRadius: 1) + ]), + ), + SizedBox( + height: 5, + ), + Text( + 'Flutter的联合,编程者的联合。', + style: TextStyle(fontSize: 15, color: Colors.white, shadows: [ + Shadow( + color: color, offset: Offset(.5, .5), blurRadius: 1) + ]), + ), + SizedBox( + height: 10, + ), + Row( + children: [ + Spacer( + flex: 5, + ), + Text( + '—— 张风捷特烈', + style: TextStyle(fontSize: 15, color: Colors.white, shadows: [ + Shadow( + color: Colors.orangeAccent, + offset: Offset(.5, .5), + blurRadius: 1) + ]), + ), + Spacer( + flex: 1, + ), + ], + ), + ], + ), + ); + + Widget _nextIcon(BuildContext context) => + Icon(Icons.chevron_right, color: Theme.of(context).primaryColor); +} diff --git a/lib/views/pages/setting/item_style_setting.dart b/lib/views/pages/setting/item_style_setting.dart new file mode 100644 index 0000000..815f255 --- /dev/null +++ b/lib/views/pages/setting/item_style_setting.dart @@ -0,0 +1,82 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/enums.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_event.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/coupon_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; + +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +class ItemStyleSettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('item样式设置'), + ), + body: BlocBuilder(builder: (_, state) { + print('EventChangeItemStyle${state.itemStyleIndex}'); + return _buildFontCell(context, state.itemStyleIndex); + }), + ); + } + + final items = [ + TechnoWidgetListItem(data: getContainer()), + CouponWidgetListItem(data: getContainer()), + CouponWidgetListItem(hasTopHole: false, data: getContainer()), + CouponWidgetListItem( + hasTopHole: true, hasBottomHole: true, data: getContainer()), + ]; + + static WidgetModel getContainer() => WidgetModel( + id: Random().nextInt(10000), + name: 'Container', + nameCN: "", + lever: 5, + family: WidgetFamily.statelessWidget, + info: '用于容纳单个子组件的容器组件。集成了若干个单子组件的功能,如内外边距、形变、装饰、约束等...'); + + Widget _buildFontCell(BuildContext context, int index) { + return ListView.builder( + itemCount: items.length, + itemBuilder: (_, i) => Padding( + padding: EdgeInsets.only(left: 20, top: 20, right: 20), + child: FeedbackWidget( + a: 0.95, + duration: Duration(milliseconds: 200), + onPressed: () { + BlocProvider.of(context) + .add(EventChangeItemStyle(i)); + }, + child: Stack( + children: [ + items[i], + if (index == i) + Positioned( + left: 15, + top: 15, + child: Circle( + color: Theme.of(context).primaryColor, + radius: 10, + child: Icon( + Icons.check, + color: Colors.white, + size: 15, + ), + ), + ) + ], + )))); + } +} diff --git a/lib/views/pages/setting/setting_page.dart b/lib/views/pages/setting/setting_page.dart new file mode 100644 index 0000000..7ccc375 --- /dev/null +++ b/lib/views/pages/setting/setting_page.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_event.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; + +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('主题设置'), + ), + body: ListView( + children: [ + ListTile( + leading: Icon( + Icons.palette, + color: Theme.of(context).primaryColor, + ), + title: Text('主题色设置'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.theme_color_setting), + ), + Divider(), + ListTile( + leading: Icon( + Icons.translate, + color: Theme.of(context).primaryColor, + ), + title: Text('字体设置'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.font_setting), + ), + Divider(), + ListTile( + leading: Icon( + TolyIcon.icon_item, + color: Theme.of(context).primaryColor, + ), + title: Text('item样式设置'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.item_style_setting), + ), + Divider(), + ListTile( + leading: Icon( + TolyIcon.icon_code, + color: Theme.of(context).primaryColor, + ), + title: Text('代码高亮样式'), + trailing: _nextIcon(context), + onTap: () => Navigator.of(context).pushNamed(Router.code_style_setting), + ), + Divider(), + _buildShowBg(context), + ], + ), + ); + } + + Widget _buildShowBg(BuildContext context) => + BlocBuilder( + builder: (_, state) => SwitchListTile( + value: state.showBackGround, + secondary: Icon( + TolyIcon.icon_background, + color: Theme.of(context).primaryColor, + ), + title: Text('显示背景'), + onChanged: (show) { + BlocProvider.of(context) + .add(EventSwitchShowBg(show)); + }, + )); + + Widget _nextIcon(BuildContext context) => + Icon(Icons.chevron_right, color: Theme.of(context).primaryColor); +} diff --git a/lib/views/pages/setting/theme_color_setting.dart b/lib/views/pages/setting/theme_color_setting.dart new file mode 100644 index 0000000..7e4511f --- /dev/null +++ b/lib/views/pages/setting/theme_color_setting.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/blocs/global/global_bloc.dart'; +import 'package:flutter_unit/blocs/global/global_event.dart'; +import 'package:flutter_unit/blocs/global/global_state.dart'; +import 'package:flutter_unit/components/permanent/feedback_widget.dart'; +import 'package:flutter_unit/components/permanent/circle.dart'; + +/// create by 张风捷特烈 on 2020-04-10 +/// contact me by email 1981462002@qq.com +/// 说明: + +class ThemeColorSettingPage extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('主题色设置'), + ), + body: BlocBuilder( + builder: (_, state) => _buildFontCell( + context, Cons.themeColorSupport.keys.toList(), state.themeColor)), + ); + } + + Widget _buildFontCell( + BuildContext context, List themeColorSupport, MaterialColor color) { + return GridView.count( + padding: EdgeInsets.only(top: 20, left: 10, right: 10), + shrinkWrap: true, + crossAxisCount: 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + childAspectRatio: 1.5, + children: themeColorSupport + .map((e) => FeedbackWidget( + a: 0.95, + duration: Duration(milliseconds: 200), + onPressed: () => BlocProvider.of(context).add(EventSwitchThemeColor(e)), + child: GridTile( + header: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10),topRight: Radius.circular(10)), + color: color == e + ? Colors.blue.withAlpha(88): + Colors.grey.withAlpha(55), + ), + padding: EdgeInsets.only(left: 10, right: 5), + height: 30, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Spacer(), + Text(colorString(e), + style: TextStyle( + color: Colors.white, + )), + Spacer(), + if (color == e) Padding( + padding: const EdgeInsets.only(right:8.0), + child: Circle(color: Colors.white,radius: 7,), + ) + ], + ), + ), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10)), + gradient: LinearGradient(colors: [ + e[50], + e[100], + e[200], + e[300], + e[400], + e[500], + e[600], + e[700], + e[800], + e[900], + ])), + alignment: Alignment(0,0.35), + child: Text( + Cons.themeColorSupport [e], + style: TextStyle(fontSize: 18,color: Colors.white,fontWeight: FontWeight.bold), + )), + ))) + .toList(), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/pages/splash/unit_paint.dart b/lib/views/pages/splash/unit_paint.dart new file mode 100644 index 0000000..121c40d --- /dev/null +++ b/lib/views/pages/splash/unit_paint.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; + +class UnitPainter extends CustomPainter { + Paint _paint; + double width; + double factor; + Color color; + Path _path1 = Path(); + Path _path2 = Path(); + Path _path3 = Path(); + Path _path4 = Path(); + + UnitPainter({this.width = 200.0, this.factor,this.color=Colors.blue}) { + _paint = Paint(); + } + + @override + void paint(Canvas canvas, Size size) { + + + canvas.translate( + size.width / 2 - width * 0.5, size.height / 2 - width * 0.5); + + canvas.save(); + canvas.translate( + -size.width / 2 * (1 - factor), -size.width / 2 * (1 - factor)); + drawColor1(canvas); + canvas.restore(); + + canvas.save(); + + canvas.translate( + size.width / 2 * (1 - factor), -size.width / 2 * (1 - factor)); + drawColor2(canvas); + canvas.restore(); + + canvas.save(); + canvas.translate( + size.width / 2 * (1 - factor), size.width / 2 * (1 - factor)); + drawColor3(canvas); + canvas.restore(); + + canvas.save(); + canvas.translate( + -size.width / 2 * (1 - factor), size.width / 2 * (1 - factor)); + drawColor4(canvas); + canvas.restore(); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } + + void drawColor1(Canvas canvas) { + _path1.moveTo(0, 0); + _path1.lineTo(width * 0.618 * factor - 1, 0); + _path1.lineTo(width * 0.5 - 1, width * 0.5 - 1); + _path1.lineTo(0, width * (1 - 0.618) * factor - 1); + + canvas.drawPath(_clipAngle(_path1), _paint..color = Colors.red); + } + + void drawColor2(Canvas canvas) { + _path2.moveTo(width * 0.618 * factor, 0); + _path2.lineTo(width, 0); + _path2.lineTo(width, width * 0.618 * factor); + _path2.lineTo(width * 0.5, width * 0.5); + + canvas.drawPath(_clipAngle(_path2), _paint..color = Colors.blue); + } + + void drawColor3(Canvas canvas) { + _path3.moveTo(width * 0.5 + 1, width * 0.5 + 1); + _path3.lineTo(width, width * 0.618 * factor + 1); + _path3.lineTo(width, width); + _path3.lineTo(width * (1 - 0.618) * factor + 1, width); + canvas.drawPath(_clipAngle(_path3), _paint..color = Colors.green); + } + + void drawColor4(Canvas canvas) { + _path4.moveTo(0, width * (1 - 0.618) * factor); + _path4.lineTo(width * 0.5, width * 0.5); + _path4.lineTo(width * (1 - 0.618) * factor, width); + _path4.lineTo(0, width); + canvas.drawPath(_clipAngle(_path4), _paint..color = Colors.yellow); + } + + Path _clipAngle(Path path) { + return Path.combine( + PathOperation.difference, + path, + Path() + ..addOval(Rect.fromCircle( + center: Offset(width * 0.5, width * 0.5), radius: 25.0))); + } +} \ No newline at end of file diff --git a/lib/views/pages/splash/unit_splash.dart b/lib/views/pages/splash/unit_splash.dart new file mode 100644 index 0000000..4f418f1 --- /dev/null +++ b/lib/views/pages/splash/unit_splash.dart @@ -0,0 +1,216 @@ +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'unit_paint.dart'; +import 'package:flutter_unit/app/router.dart'; + +/// create by 张风捷特烈 on 2020-03-07 +/// contact me by email 1981462002@qq.com +/// 说明: app 闪屏页 + +class UnitSplash extends StatefulWidget { + final double size; + + UnitSplash({this.size = 200}); + + @override + _UnitSplashState createState() => _UnitSplashState(); +} + +class _UnitSplashState extends State with TickerProviderStateMixin { + AnimationController _controller; + AnimationController _secondController; + double _factor; + double _secondFactor = 0.0; + Animation _curveAnim; + Animation _curveAnim2; + Animation _bouncAnim; + bool _animEnd = false; + + @override + void initState() { +// SystemUiOverlayStyle systemUiOverlayStyle = +// SystemUiOverlayStyle(statusBarColor: Colors.red); +// SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); +// SystemChrome.setSystemUIOverlayStyle( +// SystemUiOverlayStyle(statusBarColor: Colors.blue)); + SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle( +// systemNavigationBarColor: Colors.transparent, + statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); +// SystemChrome.setEnabledSystemUIOverlays([]); + + _controller = + AnimationController(duration: Duration(milliseconds: 1000), vsync: this) + ..addListener(() => setState(() { + return _factor = _curveAnim.value; + })) + ..addStatusListener((s) { + if (s == AnimationStatus.completed) { + setState(() { + _animEnd = true; + _secondController.forward(); + }); + } + }); + _secondController = + AnimationController(duration: Duration(milliseconds: 600), vsync: this) + ..addListener(() => setState(() { + return _secondFactor = _curveAnim2.value; + })) + ..addStatusListener((s) { + if (s == AnimationStatus.completed) { + Navigator.of(context).pushReplacementNamed(Router.nav); + } + }); + _curveAnim = + CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn); + _bouncAnim = + CurvedAnimation(parent: _secondController, curve: Curves.bounceOut); + _curveAnim2 = + CurvedAnimation(parent: _secondController, curve: Curves.fastOutSlowIn); + _controller.forward(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + var winH = MediaQuery.of(context).size.height; + var winW = MediaQuery.of(context).size.width; + + return +// GestureDetector( +// onTap: () { +// _controller.reset(); +// _controller.forward(); +// }, +// child: + Scaffold( + body: Stack( + alignment: Alignment.center, + children: [ + buildLogo(Colors.blue), + Container( + width: winW, + height: winH, + child: CustomPaint( + painter: UnitPainter(factor: _factor), + ), + ), + buildText(winH, winW), + buildHead(), + buildPower(), + ], + ), +// ), + ); + } + + Positioned buildText(double winH, double winW) { + final shadowStyle = TextStyle( + fontSize: 45, + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + shadows: [ + Shadow( + //阴影 + color: Colors.grey, + offset: Offset(1.0, 1.0), blurRadius: 1.0, + ) + ], + ); + + return Positioned( + top: winH / 1.55, + child: Container( + height: 150, + width: winW, + child: AlignTransition( + alignment: + AlignmentTween(begin: Alignment(-1, 0), end: Alignment.center) + .animate(_secondController), + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: _animEnd ? 1.0 : 0.0, + child: ShaderMask( + shaderCallback: _buildShader, + child: Text( + 'Flutter Unit', + style: shadowStyle, + ))), + ), + ), + ); + } + + final colors = [Colors.red, Colors.yellow, Colors.blue]; + + Shader _buildShader(Rect bounds) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: colors) + .createShader(bounds); + + Widget buildLogo(Color primaryColor) { + return SlideTransition( + position: Tween( + begin: Offset(0, 0), + end: Offset(0, -1.5), + ).animate(_controller), + child: RotationTransition( + turns: _controller, + child: ScaleTransition( + scale: Tween(begin: 2.0, end: 1.0).animate(_controller), + child: FadeTransition( + opacity: _controller, + child: Container( + height:120, + child: FlutterLogo( + colors: primaryColor, + style: _animEnd + ? FlutterLogoStyle.horizontal + : FlutterLogoStyle.markOnly, + size: _animEnd ? 150 : 45, + ), + )), + )), + ); + } + + Widget buildHead() { + return SlideTransition( + position: Tween( + end: Offset(0, 0), + begin: Offset(0, -5), + ).animate(_controller), + child: Container( + height: 45, + width: 45, + child: Image.asset('assets/images/icon_head.png'), + )); + } + + Widget buildPower() { + return Positioned( + bottom: 30, + right: 30, + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: _animEnd ? 1.0 : 0.0, + child: Text("Power By 张风捷特烈", + style: TextStyle( + color: Colors.grey, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 1, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16))), + ); + } +} diff --git a/lib/views/pages/unit_todo/attr_unit_page.dart b/lib/views/pages/unit_todo/attr_unit_page.dart new file mode 100644 index 0000000..f002f1c --- /dev/null +++ b/lib/views/pages/unit_todo/attr_unit_page.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/components/permanent/animated_text.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/collect_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; + +import '../common/empty_page.dart'; + +class AttrUnitPage extends StatelessWidget { + final info = '【Flutter属性集录】是Unit项目计划的第二阶段的功能之一。' + '会对所有Widget的所有属性进行收录整理到数据库,进行数据分析和组件关联。' + '并且对一些重要属性,进行全面讲解。'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('属性集录'), + ), + body: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 50, + child: Column( + children: [ + CircleImage( + image: AssetImage('assets/images/icon_head.png'), + size: 80, + ), + SizedBox(height: 10,), + Text( + 'Flutter Unit 2.0 计划', + style: TextStyle( + color: Colors.green, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ) + ], + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.all(20), + child: ShaderMask( + shaderCallback: (rect) => + _buildShader(rect, Theme.of(context).primaryColor), + child: AnimatedText( + info, + 0, + durationInMilliseconds: 10000, + textStyle: TextStyle( + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 1) + ], + color: Colors.white, +// color: Theme.of(context).primaryColor, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + buildPower() + ], + ), + ); + } + + Shader _buildShader(Rect bounds, Color color) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: [color.withAlpha(88), color.withAlpha(136), color]) + .createShader(bounds); + + Widget buildPower() { + return Positioned( + bottom: 30, + right: 30, + child: + Text("Power By 张风捷特烈", + style: TextStyle( + color: Colors.grey, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 1, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } +} diff --git a/lib/views/pages/unit_todo/bug_unit_page.dart b/lib/views/pages/unit_todo/bug_unit_page.dart new file mode 100644 index 0000000..9ee5284 --- /dev/null +++ b/lib/views/pages/unit_todo/bug_unit_page.dart @@ -0,0 +1,127 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/components/permanent/animated_text.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/collect_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; + +import '../common/empty_page.dart'; + +class BugUnitPage extends StatelessWidget { + final info = '【Flutter异常集录】是Unit项目计划的第二阶段的功能之一。' + '将收录Flutter的常见异常及解决方案,也可以是Flutter中的特点或注意点,' + '以供学习参考。本集录将支持异常/特色征集,愿开发者共同集录。'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('bug/feature 集录'), + ), + body: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 50, + child: Column( + children: [ + CircleImage( + image: AssetImage('assets/images/icon_head.png'), + size: 80, + ), + SizedBox(height: 10,), + Text( + 'Flutter Unit 2.0 计划', + style: TextStyle( + color: Colors.green, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ) + ], + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.all(20), + child: ShaderMask( + shaderCallback: (rect) => + _buildShader(rect, Theme.of(context).primaryColor), + child: AnimatedText( + info, + 0, + durationInMilliseconds: 10000, + textStyle: TextStyle( + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 1) + ], + color: Colors.white, +// color: Theme.of(context).primaryColor, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + buildPlan(), + buildPower() + ], + ), + ); + } + + Shader _buildShader(Rect bounds, Color color) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: [color.withAlpha(88), color.withAlpha(136), color]) + .createShader(bounds); + + Widget buildPlan() { + return Positioned( + bottom: 80, + child: + Text("Flutter Unit 异常/特色 征集方案(待完成)", + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: .5, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } + + Widget buildPower() { + return Positioned( + bottom: 30, + right: 30, + child: + Text("Power By 张风捷特烈", + style: TextStyle( + color: Colors.grey, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 1, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } +} \ No newline at end of file diff --git a/lib/views/pages/unit_todo/layout_unit_page.dart b/lib/views/pages/unit_todo/layout_unit_page.dart new file mode 100644 index 0000000..152f6df --- /dev/null +++ b/lib/views/pages/unit_todo/layout_unit_page.dart @@ -0,0 +1,127 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/components/permanent/animated_text.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/collect_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; + +import '../common/empty_page.dart'; + +class LayoutUnitPage extends StatelessWidget { + final info = '【Flutter布局集录】是Unit项目计划的第二阶段的功能之一。' + '将收录大量的布局样板,一者,方便直接使用;二者,方便布局的学习。' + '本集录将支持布局征集,愿开发者共同集录。'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('布局集录'), + ), + body: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 50, + child: Column( + children: [ + CircleImage( + image: AssetImage('assets/images/icon_head.png'), + size: 80, + ), + SizedBox(height: 10,), + Text( + 'Flutter Unit 2.0 计划', + style: TextStyle( + color: Colors.green, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ) + ], + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.all(20), + child: ShaderMask( + shaderCallback: (rect) => + _buildShader(rect, Theme.of(context).primaryColor), + child: AnimatedText( + info, + 0, + durationInMilliseconds: 10000, + textStyle: TextStyle( + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 1) + ], + color: Colors.white, +// color: Theme.of(context).primaryColor, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + buildPlan(), + buildPower() + ], + ), + ); + } + + Shader _buildShader(Rect bounds, Color color) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: [color.withAlpha(88), color.withAlpha(136), color]) + .createShader(bounds); + + Widget buildPlan() { + return Positioned( + bottom: 80, + child: + Text("Flutter Unit 布局征集方案(待完成)", + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: .5, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } + + Widget buildPower() { + return Positioned( + bottom: 30, + right: 30, + child: + Text("Power By 张风捷特烈", + style: TextStyle( + color: Colors.grey, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 1, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } +} diff --git a/lib/views/pages/unit_todo/paint_unit_page.dart b/lib/views/pages/unit_todo/paint_unit_page.dart new file mode 100644 index 0000000..ed6ee8e --- /dev/null +++ b/lib/views/pages/unit_todo/paint_unit_page.dart @@ -0,0 +1,127 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/blocs/collect/collect_bloc.dart'; +import 'package:flutter_unit/blocs/collect/collect_event.dart'; +import 'package:flutter_unit/blocs/collect/collect_state.dart'; +import 'package:flutter_unit/blocs/detail/detail_bloc.dart'; +import 'package:flutter_unit/blocs/detail/detail_event.dart'; +import 'package:flutter_unit/components/permanent/animated_text.dart'; +import 'package:flutter_unit/components/permanent/circle_image.dart'; +import 'package:flutter_unit/model/widget_model.dart'; +import 'package:flutter_unit/views/items/collect_widget_list_item.dart'; +import 'package:flutter_unit/views/items/techno_widget_list_item.dart'; + +import '../common/empty_page.dart'; + +class PaintUnitPage extends StatelessWidget { + final info = '【Flutter绘制集录】是Unit项目计划的第二阶段的功能之一。' + '将收录大量绘制作品,展现Flutter强大的绘制表现力,' + '以供学习绘制技能。本集录将支持绘制征集,愿开发者共同集录。'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('绘制集录'), + ), + body: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 50, + child: Column( + children: [ + CircleImage( + image: AssetImage('assets/images/icon_head.png'), + size: 80, + ), + SizedBox(height: 10,), + Text( + 'Flutter Unit 2.0 计划', + style: TextStyle( + color: Colors.green, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ) + ], + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.all(20), + child: ShaderMask( + shaderCallback: (rect) => + _buildShader(rect, Theme.of(context).primaryColor), + child: AnimatedText( + info, + 0, + durationInMilliseconds: 10000, + textStyle: TextStyle( + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 1) + ], + color: Colors.white, +// color: Theme.of(context).primaryColor, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + buildPlan(), + buildPower() + ], + ), + ); + } + + Shader _buildShader(Rect bounds, Color color) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: [color.withAlpha(88), color.withAlpha(136), color]) + .createShader(bounds); + + Widget buildPlan() { + return Positioned( + bottom: 80, + child: + Text("Flutter Unit 绘制征集方案(待完成)", + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: .5, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } + + Widget buildPower() { + return Positioned( + bottom: 30, + right: 30, + child: + Text("Power By 张风捷特烈", + style: TextStyle( + color: Colors.grey, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 1, + offset: Offset(0.3, 0.3)) + ], + fontSize: 16)), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/ProxyWidget/DropdownButtonHideUnderline.dart b/lib/views/widgets/ProxyWidget/DropdownButtonHideUnderline.dart new file mode 100644 index 0000000..cc97cf3 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/DropdownButtonHideUnderline.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 181, +// "name": 'DropDownButtonHideUnderline使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n", +// } +class CustomDropDownButtonHideUnderline extends StatefulWidget { + @override + _CustomDropDownButtonHideUnderlineState createState() => + _CustomDropDownButtonHideUnderlineState(); +} + +class _CustomDropDownButtonHideUnderlineState + extends State { + Color _color = Colors.red; + final _colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + final _info = ["红色", "黄色", "蓝色", "绿色"]; + + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + margin: EdgeInsets.symmetric(horizontal: 20), + width: 50, + height: 50, + color: _color, + ), + DropdownButtonHideUnderline( + child: DropdownButton( + value: _color, + elevation: 1, + icon: Icon( + Icons.expand_more, + size: 20, + color: _color, + ), + items: _buildItems(), + onChanged: (v) => setState(() => _color = v)), + ), + ], + ); + } + + List> _buildItems() => _colors + .map((e) => DropdownMenuItem( + value: e, + child: Text( + _info[_colors.indexOf(e)], + style: TextStyle(color: e), + ))) + .toList(); +} diff --git a/lib/views/widgets/ProxyWidget/Expended.dart b/lib/views/widgets/ProxyWidget/Expended.dart new file mode 100644 index 0000000..89165b7 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/Expended.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 106, +// "name": 'Expanded基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子 【Widget】\n" +// "【flex】 : 剩余空间分配占比 【int】", +// } +class CustomExpended extends StatefulWidget { + @override + _CustomExpendedState createState() => _CustomExpendedState(); +} + +class _CustomExpendedState extends State { + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + buildRow([0, 0, 0]), + SizedBox(height: 10,), + buildRow([0, 0, 1]), + SizedBox(height: 10,), + buildRow([1, 1, 1]), + SizedBox(height: 10,), + buildRow([2, 3, 3]), + ], + ), + ); + } + + Widget buildRow(List num) { + return Row( + children: num.map((e) => Expanded( + flex: e, + child: Container( + alignment: Alignment.center, + width: 50, + height: 50, + color: ColorUtils.randomColor(), + child: Text( + 'flex=$e', + style: TextStyle(color: Colors.white), + ), + ), + )).toList()); + } +} diff --git a/lib/views/widgets/ProxyWidget/Flexible.dart b/lib/views/widgets/ProxyWidget/Flexible.dart new file mode 100644 index 0000000..8451be1 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/Flexible.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 109, +// "name": 'Flexible基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子 【Widget】\n" +// "【fit】 : 适应模式*2 【FlexFit】\n" +// "【flex】 : 剩余空间分配占比 【int】", +// } +class CustomFlexible extends StatefulWidget { + @override + _CustomFlexibleState createState() => _CustomFlexibleState(); +} + +class _CustomFlexibleState extends State { + double _width = 300.0; + bool _loose = false; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container( + color: Colors.grey.withAlpha(33), + width: _width, + padding: EdgeInsets.all(8.0), + child: Row( + children: [ + Flexible( + flex: 2, + child: Container( + alignment: Alignment.center, + height: 50, + color: Colors.red, + child: Text( + 'flex=2', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 3, + child: Container( + alignment: Alignment.center, + height: 50, + color: Colors.blue, + child: Text( + 'flex=3', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 4, + fit: _loose?FlexFit.loose:FlexFit.tight, + child: Container( + constraints: BoxConstraints(maxWidth: 60), + alignment: Alignment.center, + height: 50, + color: Colors.green, + child: Text( + 'flex=4 \nfit:${_loose?'loose':'tight'}', + style: TextStyle(color: Colors.white), + ), + ), + ) + ], + )), + _buildOp() + ]); + } + + Widget _buildOp() { + return Row( + children: [ + Switch( + value: _loose, + onChanged: (v) => setState(() => _loose = v)), + Expanded( + child: Slider( + divisions: 10, + min: 100, + max: 350, + value: _width, + onChanged: (v) => setState(() => _width = v)), + ), + ], + ); + } +} diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/ButtonTheme.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/ButtonTheme.dart new file mode 100644 index 0000000..5fdda2f --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/ButtonTheme.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 326, +// "name": 'ButtonTheme使用', +// "priority": 1, +// "subtitle": +// "属性参数同MaterialButton,可以通过ButtonTheme.of获取按钮主题数据," +// "也可以为ButtonTheme【后代】的按钮组件设置默认样式,包括颜色、形状、尺寸等。", +// } + + +class ButtonThemeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ButtonTheme( + buttonColor: Colors.orange, + splashColor: Colors.blue, + minWidth: 40, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + child: Wrap( + spacing: 10, + children: [ + RaisedButton(onPressed: (){},child: Icon(Icons.add)), + FlatButton(onPressed: (){},child: Icon(Icons.add)), + OutlineButton(onPressed: (){},child: Icon(Icons.add)), + MaterialButton(onPressed: (){},child: Icon(Icons.add)), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/DefaultTextStyle.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/DefaultTextStyle.dart new file mode 100644 index 0000000..decbd62 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/DefaultTextStyle.dart @@ -0,0 +1,35 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 324, +// "name": 'DefaultTextStyle使用', +// "priority": 1, +// "subtitle": +// "各属性同Text,详见之。\n" +// "其功能是: 设置默认的文字样式应用于【后代组件】,注意后代组件也可以指定自身的样式", +// } +class DefaultTextStyleDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return DefaultTextStyle( + style: TextStyle( + fontSize: 18, + color: Colors.blue, + decoration: TextDecoration.underline), + child: Wrap( + spacing: 5, + children: [ + Text("Hello,",), + FlutterLogo(), + Text("Flutter",style: TextStyle(color: Colors.red),), + Text("Unit."), + ], + ), + ); + } +} diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/DividerTheme.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/DividerTheme.dart new file mode 100644 index 0000000..3af636e --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/DividerTheme.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 329, +// "name": 'DividerTheme使用', +// "priority": 1, +// "subtitle": +// "属性参数与Divider类似,可以通过DividerTheme.of获取分割线主题数据," +// "也可以为DividerTheme【后代】的分割线设置默认样式,包括颜色、粗细、高度等。", +// } + + +class DividerThemeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return DividerTheme( + data: DividerThemeData( + color: Colors.orange, + thickness: 2, + space: 10, + indent: 10, + endIndent: 10, + + ), + child: Wrap( + spacing: 10, + children: [ + Divider(), + Divider(), + Divider(), + Divider(), + Divider(), + Container( + height: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + VerticalDivider(), + VerticalDivider(), + VerticalDivider(), + VerticalDivider(), + VerticalDivider(), + ], + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/IconTheme.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/IconTheme.dart new file mode 100644 index 0000000..1307df5 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/IconTheme.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 325, +// "name": 'IconTheme使用', +// "priority": 1, +// "subtitle": +// "可以通过IconTheme.of获取图标主题数据,也可以为IconTheme【后代】的图标组件设置默认样式,包括颜色、透明度、尺寸。", +// } +class IconThemeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return IconTheme( + data: IconThemeData( + color: Colors.purple, + opacity: 1.0, + size: 30 + ), + child: Wrap( + spacing: 10, + children: [ + Icon(Icons.add), + Icon(Icons.ac_unit), + Icon(Icons.g_translate), + Icon(Icons.remove) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/MediaQuery.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/MediaQuery.dart new file mode 100644 index 0000000..818b2e1 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/MediaQuery.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 167, +// "name": 'MediaQuery获取数据信息', +// "priority": 1, +// "subtitle": +// "MediaQuery.of(context)可以获取MediaQueryData", +// } + +class CustomMediaQuery extends StatelessWidget { + @override + Widget build(BuildContext context) { + var queryData = MediaQuery.of(context); + var data = { + "size": queryData.size, + "devicePixelRatio": queryData.devicePixelRatio.toStringAsFixed(1), + "textScaleFactor": queryData.textScaleFactor.toStringAsFixed(1), + "platformBrightness": queryData.platformBrightness, + "padding": queryData.padding, + "viewInsets": queryData.viewInsets, + "systemGestureInsets": queryData.padding, + "viewPadding": queryData.padding, + "physicalDepth": queryData.padding, + "alwaysUse24HourFormat": queryData.padding, + "accessibleNavigation": queryData.alwaysUse24HourFormat, + "invertColors": queryData.invertColors, + "highContrast": queryData.highContrast, + "disableAnimations": queryData.disableAnimations, + "boldText": queryData.boldText, + }; + + return Container( + height: 200, + color: Colors.grey.withAlpha(11), + child:ListView( + children: data.keys.map((e) => buildItem(e, data)).toList(), + ), + ); + } + + Widget buildItem(String e, Map data) => Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + data[e].toString(), + style: TextStyle(fontSize: 16, color: Colors.orange), + ) + ], + ), + ), + Divider( + height: 1, + ) + ], + ); +} + + diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/ScrollConfiguration.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/ScrollConfiguration.dart new file mode 100644 index 0000000..a8bb6e5 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/ScrollConfiguration.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 180, +// "name": 'ScrollConfiguration基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【behavior】 : 滑动行为 【ScrollBehavior】\n" +// " 可以使用ScrollConfiguration让ListView无蓝色阴影", +// } +class CustomScrollConfiguration extends StatelessWidget { + final data = [ + Colors.cyan[50], + Colors.cyan[100], + Colors.cyan[200], + Colors.cyan[300], + Colors.cyan[400], + Colors.cyan[500], + Colors.cyan[600], + Colors.cyan[700], + Colors.cyan[800], + Colors.cyan[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ScrollConfiguration( + behavior: NoScrollBehavior(), child: _buildListView()), + ); + } + + Widget _buildListView() => ListView( + padding: EdgeInsets.symmetric(horizontal: 5), + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +class NoScrollBehavior extends ScrollBehavior { + @override + Widget buildViewportChrome( + BuildContext context, Widget child, AxisDirection axisDirection) => + child; +} diff --git a/lib/views/widgets/ProxyWidget/InheritedWidget/SliderTheme.dart b/lib/views/widgets/ProxyWidget/InheritedWidget/SliderTheme.dart new file mode 100644 index 0000000..025a223 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/InheritedWidget/SliderTheme.dart @@ -0,0 +1,217 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 331, +// "name": 'SliderTheme使用', +// "priority": 1, +// "subtitle": +// "可通过SliderTheme.of获取Slider主题数据对象,其中包含大量属性用于对Slider的设定。" +// "可以为ButtonTheme【后代】的按钮组件设置默认样式,包括颜色、形状、尺寸等。", +// } + +class SliderThemeDemo extends StatefulWidget { + @override + _SliderThemeDemoState createState() => _SliderThemeDemoState(); +} + +class _SliderThemeDemoState extends State { + var _bliss = 0.5; + + @override + Widget build(BuildContext context) { + return SliderTheme( + data: SliderTheme.of(context).copyWith(activeTrackColor: Colors.orange), + child: Slider( + min: 0.0, + max: 200.0, + divisions: 10, + label: "${_bliss.toStringAsFixed(1)}", + onChanged: (double value) { + setState(() { + _bliss = value; + }); + }, + value: _bliss, + ), + ); + ; + } +} + +// { +// "widgetId": 331, +// "name": 'SliderTheme对Slider的样式定制', +// "priority": 2, +// "subtitle": +// "通过thumbShape和valueIndicatorShape可以对Slider进行样式定制。注: 本例参考flutter-gallery中的SlideDemo", +// } + +class DIYSliderTheme extends StatefulWidget { + @override + _DIYSliderThemeState createState() => _DIYSliderThemeState(); +} + +class _DIYSliderThemeState extends State { + var _bliss = 0.5; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + + return SliderTheme( + data: theme.sliderTheme.copyWith( + activeTrackColor: Colors.deepPurple, + inactiveTrackColor: Colors.blue.withAlpha(55), + activeTickMarkColor: theme.colorScheme.onSurface.withOpacity(0.7), + inactiveTickMarkColor: theme.colorScheme.surface.withOpacity(0.7), + overlayColor: theme.colorScheme.onSurface.withOpacity(0.12), + thumbColor: Colors.deepPurple, + valueIndicatorColor: Colors.deepPurpleAccent, + thumbShape: _CustomThumbShape(), + valueIndicatorShape: _CustomValueIndicatorShape(), + valueIndicatorTextStyle: theme.accentTextTheme.body2 + .copyWith(color: theme.colorScheme.onSurface), + ), + child: Slider( + min: 0.0, + max: 200.0, + divisions: 10, + label: "${_bliss.toStringAsFixed(1)}", + onChanged: (double value) { + setState(() { + _bliss = value; + }); + }, + value: _bliss, + ), + ); + } +} + +class _CustomThumbShape extends SliderComponentShape { + static const double _thumbSize = 4.0; + static const double _disabledThumbSize = 3.0; + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return isEnabled + ? const Size.fromRadius(_thumbSize) + : const Size.fromRadius(_disabledThumbSize); + } + + static final Animatable sizeTween = Tween( + begin: _disabledThumbSize, + end: _thumbSize, + ); + + @override + void paint( + PaintingContext context, + Offset thumbCenter, { + Animation activationAnimation, + Animation enableAnimation, + bool isDiscrete, + TextPainter labelPainter, + RenderBox parentBox, + SliderThemeData sliderTheme, + TextDirection textDirection, + double value, + }) { + final Canvas canvas = context.canvas; + final ColorTween colorTween = ColorTween( + begin: sliderTheme.disabledThumbColor, + end: sliderTheme.thumbColor, + ); + final double size = _thumbSize * sizeTween.evaluate(enableAnimation); + final Path thumbPath = _downTriangle(size, thumbCenter); + canvas.drawPath( + thumbPath, Paint()..color = colorTween.evaluate(enableAnimation)); + } +} + +Path _upTriangle(double size, Offset thumbCenter) => + _downTriangle(size, thumbCenter, invert: true); + +Path _downTriangle(double size, Offset thumbCenter, {bool invert = false}) { + final Path thumbPath = Path(); + final double height = sqrt(3.0) / 2.0; + final double centerHeight = size * height / 3.0; + final double halfSize = size / 2.0; + final double sign = invert ? -1.0 : 1.0; + thumbPath.moveTo( + thumbCenter.dx - halfSize, thumbCenter.dy + sign * centerHeight); + thumbPath.lineTo(thumbCenter.dx, thumbCenter.dy - 2.0 * sign * centerHeight); + thumbPath.lineTo( + thumbCenter.dx + halfSize, thumbCenter.dy + sign * centerHeight); + thumbPath.close(); + return thumbPath; +} + +class _CustomValueIndicatorShape extends SliderComponentShape { + static const double _indicatorSize = 4.0; + static const double _disabledIndicatorSize = 3.0; + static const double _slideUpHeight = 30.0; + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return Size.fromRadius(isEnabled ? _indicatorSize : _disabledIndicatorSize); + } + + static final Animatable sizeTween = Tween( + begin: _disabledIndicatorSize, + end: _indicatorSize, + ); + + @override + void paint( + PaintingContext context, + Offset thumbCenter, { + Animation activationAnimation, + Animation enableAnimation, + bool isDiscrete, + TextPainter labelPainter, + RenderBox parentBox, + SliderThemeData sliderTheme, + TextDirection textDirection, + double value, + }) { + final Canvas canvas = context.canvas; + final ColorTween enableColor = ColorTween( + begin: sliderTheme.disabledThumbColor, + end: sliderTheme.valueIndicatorColor, + ); + final Tween slideUpTween = Tween( + begin: 0.0, + end: _slideUpHeight, + ); + final double size = _indicatorSize * sizeTween.evaluate(enableAnimation); + final Offset slideUpOffset = + Offset(0.0, -slideUpTween.evaluate(activationAnimation)); + final Path thumbPath = _upTriangle(size, thumbCenter + slideUpOffset); + final Color paintColor = enableColor + .evaluate(enableAnimation) + .withAlpha((255.0 * activationAnimation.value).round()); + canvas.drawPath( + thumbPath, + Paint()..color = paintColor, + ); + canvas.drawLine( + thumbCenter, + thumbCenter + slideUpOffset, + Paint() + ..color = paintColor + ..style = PaintingStyle.stroke + ..strokeWidth = 2.0); + labelPainter.paint( + canvas, + thumbCenter + + slideUpOffset + + Offset(-labelPainter.width / 2.0, -labelPainter.height - 4.0)); + } +} diff --git a/lib/views/widgets/ProxyWidget/Positioned.dart b/lib/views/widgets/ProxyWidget/Positioned.dart new file mode 100644 index 0000000..51f7026 --- /dev/null +++ b/lib/views/widgets/ProxyWidget/Positioned.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 108, +// "name": 'Positioned基本使用', +// "priority": 2, +// "subtitle": +// "【child】 : 组件 【Widget】\n" +// "【top】 : 到父顶距离 【double】\n" +// "【right】 : 到父右距离 【double】\n" +// "【left】 : 到父左距离 【double】\n" +// "【bottom】 : 到父底距离 【double】", +// } +class CustomPositioned extends StatelessWidget { + @override + Widget build(BuildContext context) { + var yellowBox = Container( + color: Colors.yellow, + height: 100, + width: 100, + ); + + var redBox = Container( + color: Colors.red, + height: 90, + width: 90, + ); + + var greenBox = Container( + color: Colors.green, + height: 80, + width: 80, + ); + + var cyanBox = Container( + color: Colors.cyanAccent, + height: 70, + width: 70, + ); + + return Container( + width: 200, + height: 120, + color: Colors.grey.withAlpha(33), + child: Stack( + children: [ + yellowBox, + redBox, + Positioned(top: 20, left: 20, child: greenBox), + Positioned( + child: cyanBox, + bottom: 10, + right: 10, + ) + ], + )); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/ErrorWidget.dart b/lib/views/widgets/RenderObjectWidget/ErrorWidget.dart new file mode 100644 index 0000000..7dce9ac --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/ErrorWidget.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 197, +// "name": 'ErrorWidget基本使用', +// "priority": 1, +// "subtitle": +// "入参 : 显示信息 【Object】", +// } +class ErrorWidgetDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ErrorWidget( + 'I am Error ErrorWidget\n' + 'But now, there has no error.' + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Column.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Column.dart new file mode 100644 index 0000000..bd3b370 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Column.dart @@ -0,0 +1,66 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 95, +// "name": 'Column基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【mainAxisAlignment】 : 主轴对齐 【MainAxisAlignment】\n" +// "【crossAxisAlignment】 : 交叉轴对齐 【CrossAxisAlignment】\n" +// "【textBaseline】 : 文字基线 【TextBaseline】\n" +// "【verticalDirection】 : 竖直方向 【VerticalDirection】\n" +// "【mainAxisSize】 : 主轴尺寸 【MainAxisSize】", +// } + +class CustomColumn extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildTitle(), + _buildContent(context), + ], + ); + } + + Widget _buildTitle() { + return Container( + height: 70, + color: Color(0x4484FFFF), + child: Row( + children: [ + Padding( + child: Icon( + Icons.add_location, + size: 30, + color: Colors.pink, + ), + padding: EdgeInsets.only(left: 25, right: 20), + ), + Expanded( + child: Text( + "附近", + style: TextStyle(fontSize: 18), + ), + ), + Padding( + child: Icon(Icons.keyboard_arrow_right, color: Colors.black38), + padding: EdgeInsets.only(right: 25), + ), + ], + )); + } + + Widget _buildContent(ctx) => Container( + width: MediaQuery.of(ctx).size.width, + color: Colors.orangeAccent, + height: 100, + child: Icon( + Icons.android, + size: 50, + color: Colors.white, + ), + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flex.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flex.dart new file mode 100644 index 0000000..e42962e --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flex.dart @@ -0,0 +1,463 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + + +// { +// "widgetId": 94, +// "name": 'Flex的排布方向基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【direction】 : 方向 【Axis】", +// } +class DirectionFlex extends StatelessWidget { + + final redBox= Container( + color: Colors.red, + height: 30, + width: 40, + ); + + final blueBox= Container( + color: Colors.blue, + height: 20, + width: 30, + ); + + final greenBox= Container( + color: Colors.green, + height: 20, + width: 20, + ); + + @override + Widget build(BuildContext context) { + return Wrap( + children: Axis.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 80, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + _buildItem(mode) => Flex( + direction: mode, + children: [ + blueBox, redBox, greenBox + ], + ); +} + +// { +// "widgetId": 94, +// "name": 'Flex主轴对齐方式', +// "priority": 2, +// "subtitle": +// "【mainAxisAlignment】 : 主轴对齐 【MainAxisAlignment】", +// } +class MainAxisAlignmentFlex extends StatelessWidget { + + final redBox= Container( + color: Colors.red, + height: 30, + width: 40, + ); + + final blueBox= Container( + color: Colors.blue, + height: 20, + width: 30, + ); + + final greenBox= Container( + color: Colors.green, + height: 20, + width: 20, + ); + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 5, + children: MainAxisAlignment.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 80, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + _buildItem(mode) => Flex( + direction: Axis.horizontal, + mainAxisAlignment: mode, + children: [ + blueBox, redBox, greenBox + ], + ); +} + + +// { +// "widgetId": 94, +// "name": 'Flex交叉轴对齐方式', +// "priority": 3, +// "subtitle": +// "【crossAxisAlignment】 : 交叉轴对齐 【CrossAxisAlignment】", +// } +class CrossAxisAlignmentFlex extends StatelessWidget { + + final redBox= Container( + color: Colors.red, + height: 30, + width: 40, + ); + + final blueBox= Container( + color: Colors.blue, + height: 20, + width: 30, + ); + + final greenBox= Container( + color: Colors.green, + height: 20, + width: 20, + ); + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 5, + children: CrossAxisAlignment.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 80, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + _buildItem(mode) => Flex( + direction: Axis.horizontal, + crossAxisAlignment: mode, + textBaseline: TextBaseline.alphabetic, + children: [ + blueBox, redBox, greenBox + ], + ); +} +// { +// "widgetId": 94, +// "name": 'Flex垂直方向顺序', +// "priority": 4, +// "subtitle": +// "【verticalDirection】 : 垂直方向顺序 【VerticalDirection】", +// } +class VerticalDirectionFlex extends StatelessWidget { + + final redBox= Container( + color: Colors.red, + height: 30, + width: 40, + ); + + final blueBox= Container( + color: Colors.blue, + height: 20, + width: 30, + ); + + final greenBox= Container( + color: Colors.green, + height: 20, + width: 20, + ); + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 5, + children: VerticalDirection.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 80, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + _buildItem(mode) => Flex( + direction: Axis.vertical, + verticalDirection: mode, + children: [ + blueBox, redBox, greenBox + ], + ); +} +// { +// "widgetId": 94, +// "name": 'Flex水平方向顺序', +// "priority": 5, +// "subtitle": +// "【textDirection】 : 水平方向顺序 【TextDirection】", +// } +class TextDirectionFlex extends StatelessWidget { + + final redBox= Container( + color: Colors.red, + height: 30, + width: 40, + ); + + final blueBox= Container( + color: Colors.blue, + height: 20, + width: 30, + ); + + final greenBox= Container( + color: Colors.green, + height: 20, + width: 20, + ); + + @override + Widget build(BuildContext context) { + return Wrap( + runSpacing: 5, + children: TextDirection.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 80, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + _buildItem(mode) => Flex( + direction: Axis.horizontal, + textDirection: mode, + children: [ + blueBox, redBox, greenBox + ], + ); +} + + +// { +// "widgetId": 94, +// "name": 'Flex主轴对齐方式', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【direction】 : 方向 【Axis】\n" +// "【mainAxisAlignment】 : 主轴对齐 【MainAxisAlignment】\n" +// "【crossAxisAlignment】 : 交叉轴对齐 【CrossAxisAlignment】\n" +// "【textBaseline】 : 文字基线 【TextBaseline】\n" +// "【verticalDirection】 : 竖直方向 【VerticalDirection】\n" +// "【mainAxisSize】 : 主轴尺寸 【MainAxisSize】", +// } +class PlayFlex extends StatefulWidget { + @override + _PlayFlexState createState() => _PlayFlexState(); +} + +class _PlayFlexState extends State { + final redBox = Container( + color: Colors.red, + height: 50, + width: 50, + ); + final blueBox = Container( + color: Colors.blue, + width: 60, + height: 60, + ); + final yellowBox = Container( + color: Colors.yellow, + height: 10, + width: 10, + ); + final greenBox = Container( + color: Colors.green, + height: 30, + width: 20, + ); + var _direction = Axis.horizontal; + var _mainAxisAlignment = MainAxisAlignment.start; + var _crossAxisAlignment = CrossAxisAlignment.center; + var _verticalDirection = VerticalDirection.up; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildDirectionSelector(), + _buildMainAxisAlignmentSelector(), + _buildCrossAxisAlignmentSelector(), + _buildVerticalDirectionSelector(), + Container( + width: 300, + height: 300 * 0.618, + color: Colors.grey.withAlpha(33), + child: Flex( + textBaseline: TextBaseline.alphabetic, + direction: _direction, + mainAxisAlignment: _mainAxisAlignment, + crossAxisAlignment: _crossAxisAlignment, + verticalDirection: _verticalDirection, + children: [redBox, blueBox, yellowBox, greenBox], + ), + ), + ], + ); + } + + Widget _buildDirectionSelector() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "direction", + style: TextStyle( + fontSize: 16, color: Colors.blue, fontWeight: FontWeight.bold), + ), + DropdownButton( + elevation: 1, + underline: Container(), + value: _direction, + items: Axis.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.toString()), + )) + .toList(), + onChanged: (e) { + setState(() { + _direction = e; + }); + }), + ], + ), + ); + } + + Widget _buildMainAxisAlignmentSelector() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "mainAxisAlignment", + style: TextStyle( + fontSize: 16, color: Colors.blue, fontWeight: FontWeight.bold), + ), + DropdownButton( + elevation: 1, + underline: Container(), + value: _mainAxisAlignment, + items: MainAxisAlignment.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.toString().split('.')[1]), + )) + .toList(), + onChanged: (e) { + setState(() { + _mainAxisAlignment = e; + }); + }), + ], + ), + ); + } + + Widget _buildCrossAxisAlignmentSelector() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "crossAxisAlignment", + style: TextStyle( + fontSize: 16, color: Colors.blue, fontWeight: FontWeight.bold), + ), + DropdownButton( + elevation: 1, + underline: Container(), + value: _crossAxisAlignment, + items: CrossAxisAlignment.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.toString().split('.')[1]), + )) + .toList(), + onChanged: (e) { + setState(() { + _crossAxisAlignment = e; + }); + }), + ], + ), + ); + } + + Widget _buildVerticalDirectionSelector() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "MainAxisSize", + style: TextStyle( + fontSize: 16, color: Colors.blue, fontWeight: FontWeight.bold), + ), + DropdownButton( + elevation: 1, + underline: Container(), + value: _verticalDirection, + items: VerticalDirection.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.toString().split('.')[1]), + )) + .toList(), + onChanged: (e) { + setState(() { + _verticalDirection = e; + }); + }), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flow.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flow.dart new file mode 100644 index 0000000..bdc9848 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Flow.dart @@ -0,0 +1,171 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 99, +// "name": 'Flow圆形排布', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【delegate】 : 代理 【FlowDelegate】", +// } +class CircleFlow extends StatelessWidget { + final data = List.generate( + 16, + (index) => index.isEven + ? "assets/images/icon_head.png" + : "assets/images/wy_300x200.jpg"); + + @override + Widget build(BuildContext context) { + return Container( + width: 300, + height: 300, + alignment: Alignment.center, + child: Flow( + delegate: _CircleFlowDelegate(), + children: data + .map((e) => CircleAvatar(backgroundImage: AssetImage(e))) + .toList(), + ), + ); + } +} + +class _CircleFlowDelegate extends FlowDelegate { + @override //绘制孩子的方法 + void paintChildren(FlowPaintingContext context) { + double radius = context.size.shortestSide / 2; + print(context.getChildSize(0)); + var count = context.childCount; + var perRad = 2 * pi / count; + for (int i = 0; i < count; i++) { + var cSizeX = context.getChildSize(i).width / 2; + var cSizeY = context.getChildSize(i).height / 2; + + var offsetX = (radius - cSizeX) * cos(i * perRad) + radius; + var offsetY = (radius - cSizeY) * sin(i * perRad) + radius; + context.paintChild(i, + transform: Matrix4.translationValues( + offsetX - cSizeX, offsetY - cSizeY, 0.0)); + } + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) { + return true; + } +} + +// { +// "widgetId": 99, +// "name": 'Flow圆形与动画结合', +// "priority": 2, +// "subtitle": +// "通过动画来更改周围组件的位置实现效果", +// } + +class BurstFlow extends StatefulWidget { + static final data = List.generate( + 16, + (index) => index.isEven + ? "assets/images/icon_head.png" + : "assets/images/wy_300x200.jpg"); + static final show = Container( + width: 300, + height: 300, + alignment: Alignment.center, + child: BurstFlow( + children: data + .map((e) => CircleAvatar(backgroundImage: AssetImage(e))) + .toList(), + menu: CircleAvatar( + backgroundImage: AssetImage('assets/images/icon_head.png'), + ))); + + final List children; + final Widget menu; + + BurstFlow({@required this.children, @required this.menu}); + + @override + _BurstFlowState createState() => _BurstFlowState(); +} + +class _BurstFlowState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + double _rad = 0.0; + bool _closed = true; + + @override + void initState() { + _controller = AnimationController( + duration: Duration(milliseconds: 1000), vsync: this) + ..addListener(() => setState( + () => _rad = (_closed ? (_controller.value) : 1 - _controller.value))) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _closed = !_closed; + } + }); + + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Flow( + delegate: _BurstFlowDelegate(_rad), + children: [ + ...widget.children, + InkWell( + onTap: () { + _controller.reset(); + _controller.forward(); + }, + child: widget.menu) + ], + ); + } +} + +class _BurstFlowDelegate extends FlowDelegate { + final double rad; + + _BurstFlowDelegate(this.rad); + + @override //绘制孩子的方法 + void paintChildren(FlowPaintingContext context) { + double radius = context.size.shortestSide / 2; + var count = context.childCount - 1; + var perRad = 2 * pi / count; + for (int i = 0; i < count; i++) { + print(i); + var cSizeX = context.getChildSize(i).width / 2; + var cSizeY = context.getChildSize(i).height / 2; + var offsetX = rad * (radius - cSizeX) * cos(i * perRad) + radius; + var offsetY = rad * (radius - cSizeY) * sin(i * perRad) + radius; + context.paintChild(i, + transform: Matrix4.translationValues( + offsetX - cSizeX, offsetY - cSizeY, 0.0)); + } + context.paintChild(context.childCount - 1, + transform: Matrix4.translationValues( + radius - context.getChildSize(context.childCount - 1).width / 2, + radius - context.getChildSize(context.childCount - 1).height / 2, + 0.0)); + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) { + return true; + } +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/IndexedStack.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/IndexedStack.dart new file mode 100644 index 0000000..28a0600 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/IndexedStack.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 161, +// "name": 'IndexedStack基本使用', +// "priority":1 , +// "subtitle": +// "【children】 : 子组件列表 【Lis】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】\n" +// "【index】 : 当前显示组件 【int】", +// } +class CustomIndexedStack extends StatefulWidget { + @override + _CustomIndexedStackState createState() => _CustomIndexedStackState(); +} + +class _CustomIndexedStackState extends State { + var _index = 1; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + width: 200, + height: 100, + color: Colors.grey.withAlpha(33), + child: IndexedStack( + index: _index, + children: [ + Container( + color: Colors.red, + width: 80, + height: 80, + ), + Positioned( + bottom: 10, + right: 10, + child: Container( + color: Colors.blue, + width: 80, + height: 80, + ), + ) + ], + ), + ), + ], + ); + } + + Widget _buildSwitch() => Switch( + value: _index == 0, + onChanged: (v) => setState(() => _index = v ? 0 : 1), + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/RichText.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/RichText.dart new file mode 100644 index 0000000..5887037 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/RichText.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +// { +// "widgetId": 101, +// "name": 'RichText基本使用', +// "priority": 1, +// "subtitle": +// "【text】 : 文字 【TextSpan】\n" +// " 其他属性与Text相同,详见之。", +// } +class CustomRichText extends StatelessWidget { + final str = " 发光强度简称光强,国际单位是(坎德拉)简写cd。" + "1cd是指光源在指定方向的单位立体角内发出的光通量。" + "光源辐射是均匀时,则光强为I=F/Ω,Ω为立体角,单位为球面度(sr),F为光通量," + "单位是流明,对于点光源由I=F/4π 。光亮度是表示发光面明亮程度的," + "指发光表面在指定方向的发光强度与垂直且指定方向的发光面的面积之比," + "单位是坎德拉/平方米。对于一个漫散射面,尽管各个方向的光强和光通量不同," + "但各个方向的亮度都是相等的。电视机的荧光屏就是近似于这样的漫散射面," + "所以从各个方向上观看图像,都有相同的亮度感。"; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only( + left: 10.0, + right: 10, + ), + child: RichText( + text: TextSpan( + children: str + .split("") + .map((str) => TextSpan( + text: str, + style: TextStyle( + fontSize: 14, color: ColorUtils.randomColor()))) + .toList())), + ); + } +} + +// { +// "widgetId": 101, +// "name": 'RichText包含其他组件', +// "priority": 2, +// "subtitle": +// "使用WidgetSpan来承载普通组件,作为RichText的内容", +// } +class RichTextWithWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return RichText( + text: TextSpan( + text: 'hello ', + style: TextStyle(color: Colors.black, fontSize: 18), + children: [ + WidgetSpan( + child: Image.asset( + 'assets/images/icon_head.png', + width: 30, + ), + alignment: PlaceholderAlignment.baseline, + baseline: TextBaseline.ideographic), + TextSpan( + text: ' , welcome to ', + style: TextStyle(color: Colors.blue, fontSize: 18), + ), + WidgetSpan( + child: FlutterLogo(), + alignment: PlaceholderAlignment.baseline, + baseline: TextBaseline.ideographic), + TextSpan( + text: ' .\n', + ), + TextSpan( + text: 'focus me on ', + style: TextStyle(color: Colors.orange, fontSize: 16), + ), + TextSpan( + text: 'https://github.com/toly1994328', + style: TextStyle( + color: Colors.blue, + fontSize: 18, + decoration: TextDecoration.underline), + ), + TextSpan( + text: ' .\n', + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Row.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Row.dart new file mode 100644 index 0000000..ddcac5d --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Row.dart @@ -0,0 +1,45 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +// { +// "widgetId": 95, +// "name": 'Row基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【mainAxisAlignment】 : 主轴对齐 【MainAxisAlignment】\n" +// "【crossAxisAlignment】 : 交叉轴对齐 【CrossAxisAlignment】\n" +// "【textBaseline】 : 文字基线 【TextBaseline】\n" +// "【verticalDirection】 : 竖直方向 【VerticalDirection】\n" +// "【mainAxisSize】 : 主轴尺寸 【MainAxisSize】", +// } + +class CustomRow extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + height: 70, + color: Color(0x4484FFFF), + child: Row( + children: [ + Padding( + child: Icon( + Icons.add_location, + size: 30, + color: Colors.pink, + ), + padding: EdgeInsets.only(left: 25, right: 20), + ), + Expanded( + child: Text( + "附近", + style: TextStyle(fontSize: 18), + ), + ), + Padding( + child: Icon(Icons.keyboard_arrow_right, color: Colors.black38), + padding: EdgeInsets.only(right: 25), + ), + ], + )); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Stack.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Stack.dart new file mode 100644 index 0000000..ad1d45f --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Stack.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 97, +// "name": 'Stack基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【textDirection】 : 孩子排布方向 【MainAxisAlignment】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】\n" +// "【overflow】 : 溢出模式 【Overflow】\n" +// "【fit】 : 适应模式 【StackFit】", +// } +class CustomStack extends StatelessWidget { + @override + Widget build(BuildContext context) { + var yellowBox = Container( + color: Colors.yellow, + height: 100, + width: 100, + ); + + var redBox = Container( + color: Colors.red, + height: 90, + width: 90, + ); + + var greenBox = Container( + color: Colors.green, + height: 80, + width: 80, + ); + + var cyanBox = Container( + color: Colors.cyanAccent, + height: 70, + width: 70, + ); + + return Container( + width: 200, + height: 120, + color: Colors.grey.withAlpha(33), + child: Stack( + textDirection: TextDirection.rtl, + fit: StackFit.loose, + alignment: Alignment.topRight, + overflow: Overflow.clip, + children: [yellowBox, redBox, greenBox, cyanBox], + ), + ); + } +} + +// { +// "widgetId": 97, +// "name": 'Stack和Positioned结合使用', +// "priority": 2, +// "subtitle": +// "Positioned组件只能用与Stack中,可以指定左上右下的距离对某个组件进行位置精确安放。", +// } +class PositionedStack extends StatelessWidget { + @override + Widget build(BuildContext context) { + var yellowBox = Container( + color: Colors.yellow, + height: 100, + width: 100, + ); + + var redBox = Container( + color: Colors.red, + height: 90, + width: 90, + ); + + var greenBox = Container( + color: Colors.green, + height: 80, + width: 80, + ); + + var cyanBox = Container( + color: Colors.cyanAccent, + height: 70, + width: 70, + ); + + return Container( + width: 200, + height: 120, + color: Colors.grey.withAlpha(33), + child: Stack( + children: [yellowBox, redBox, greenBox, + Positioned( + child: cyanBox, + bottom: 10, + right: 10, + ) + ], + )); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Wrap.dart b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Wrap.dart new file mode 100644 index 0000000..92293f8 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/MultiChildRenderObjectWidget/Wrap.dart @@ -0,0 +1,365 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 98, +// "name": 'Wrap的基础用法', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【spacing】 : 主轴条目间距 【double】\n" +// "【runSpacing】 : 交叉轴条目间距 【double】\n" +// "【direction】 : 主轴对齐 【Axis】", +// } +class DirectionWrap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: Axis.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 100, + color: Colors.grey.withAlpha(33), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + final yellowBox = Container( + color: Colors.yellow, + height: 30, + width: 50, + ); + + final redBox = Container( + color: Colors.red, + height: 40, + width: 40, + ); + final greenBox = Container( + color: Colors.green, + height: 40, + width: 20, + ); + final blackBox = Container( + color: Colors.black, + height: 10, + width: 10, + ); + final purpleBox = Container( + color: Colors.purple, + height: 20, + width: 20, + ); + final orangeBox = Container( + color: Colors.orange, + height: 80, + width: 20, + ); + final cyanBox = Container( + color: Colors.cyanAccent, + height: 10, + width: 20, + ); + + _buildItem(mode) => Wrap( + direction: mode, + runSpacing: 10, + spacing: 10, + children: [ + yellowBox, redBox, greenBox, cyanBox, + blackBox, purpleBox, orangeBox, + ], + ); +} +// { +// "widgetId": 98, +// "name": 'Wrap的alignment属性', +// "priority": 2, +// "subtitle": +// "【alignment】 : 主轴对齐 【WrapAlignment】", +// } +class WrapAlignmentWrap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: WrapAlignment.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 100, + color: Colors.grey.withAlpha(88), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + final yellowBox = Container( + color: Colors.yellow, + height: 30, + width: 50, + ); + + final redBox = Container( + color: Colors.red, + height: 40, + width: 40, + ); + final greenBox = Container( + color: Colors.green, + height: 40, + width: 20, + ); + final blackBox = Container( + color: Colors.black, + height: 10, + width: 10, + ); + final purpleBox = Container( + color: Colors.purple, + height: 20, + width: 20, + ); + final orangeBox = Container( + color: Colors.orange, + height: 80, + width: 20, + ); + final cyanBox = Container( + color: Colors.cyanAccent, + height: 10, + width: 20, + ); + + _buildItem(mode) => Wrap( + alignment: mode, + runSpacing: 10, + spacing: 10, + children: [ + yellowBox, redBox, + greenBox, cyanBox, + blackBox, purpleBox, + orangeBox, + ], + ); +} +// { +// "widgetId": 98, +// "name": 'Wrap的crossAxisAlignment属性', +// "priority": 3, +// "subtitle": +// "【crossAxisAlignment】 : 交叉轴对齐 【CrossAxisAlignment】", +// } +class CrossAxisAlignmentWrap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: WrapCrossAlignment.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 100, + color: Colors.grey.withAlpha(88), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + final yellowBox = Container( + color: Colors.yellow, + height: 30, + width: 50, + ); + + final redBox = Container( + color: Colors.red, + height: 40, + width: 40, + ); + final greenBox = Container( + color: Colors.green, + height: 40, + width: 20, + ); + final blackBox = Container( + color: Colors.black, + height: 10, + width: 10, + ); + final purpleBox = Container( + color: Colors.purple, + height: 20, + width: 20, + ); + final orangeBox = Container( + color: Colors.orange, + height: 80, + width: 20, + ); + final cyanBox = Container( + color: Colors.cyanAccent, + height: 10, + width: 20, + ); + + _buildItem(mode) => Wrap( + crossAxisAlignment: mode, + runSpacing: 10, + spacing: 10, + children: [ + yellowBox, redBox, + greenBox, cyanBox, + blackBox, purpleBox, + orangeBox, + ], + ); +} + +// { +// "widgetId": 98, +// "name": 'Wrap的textDirection属性', +// "priority": 4, +// "subtitle": +// "【textDirection】 : 文字方向 【TextDirection】", +// } +class TextDirectionWrap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: TextDirection.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 100, + color: Colors.grey.withAlpha(88), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + final yellowBox = Container( + color: Colors.yellow, + height: 30, + width: 50, + ); + + final redBox = Container( + color: Colors.red, + height: 40, + width: 40, + ); + final greenBox = Container( + color: Colors.green, + height: 40, + width: 20, + ); + final blackBox = Container( + color: Colors.black, + height: 10, + width: 10, + ); + final purpleBox = Container( + color: Colors.purple, + height: 20, + width: 20, + ); + final orangeBox = Container( + color: Colors.orange, + height: 80, + width: 20, + ); + final cyanBox = Container( + color: Colors.cyanAccent, + height: 10, + width: 20, + ); + + _buildItem(mode) => Wrap( + textDirection: mode, + runSpacing: 10, + spacing: 10, + children: [ + yellowBox, redBox, greenBox, cyanBox, + blackBox, purpleBox, orangeBox, + ], + ); +} + +// { +// "widgetId": 98, +// "name": 'Wrap的textDirection属性', +// "priority": 5, +// "subtitle": +// "【verticalDirection】 : 竖直方向 【VerticalDirection】", +// } +class VerticalDirectionWrap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: VerticalDirection.values + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 160, + height: 100, + color: Colors.grey.withAlpha(88), + child: _buildItem(mode)), + Text(mode.toString().split('.')[1]) + ])) + .toList()); + } + + final yellowBox = Container( + color: Colors.yellow, + height: 30, + width: 50, + ); + + final redBox = Container( + color: Colors.red, + height: 40, + width: 40, + ); + final greenBox = Container( + color: Colors.green, + height: 40, + width: 20, + ); + final blackBox = Container( + color: Colors.black, + height: 10, + width: 10, + ); + final purpleBox = Container( + color: Colors.purple, + height: 20, + width: 20, + ); + final orangeBox = Container( + color: Colors.orange, + height: 80, + width: 20, + ); + final cyanBox = Container( + color: Colors.cyanAccent, + height: 10, + width: 20, + ); + + _buildItem(mode) => Wrap( + verticalDirection: mode, + direction: Axis.vertical, + runSpacing: 10, + spacing: 10, + children: [ + yellowBox, redBox, greenBox, cyanBox, + blackBox, purpleBox, orangeBox, + ], + ); +} \ No newline at end of file diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Align.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Align.dart new file mode 100644 index 0000000..a415bad --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Align.dart @@ -0,0 +1,135 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 85, +// "name": 'Align基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomAlign extends StatelessWidget { + final alignments = [ + Alignment.topLeft, + Alignment.topCenter, + Alignment.topRight, + Alignment.centerLeft, + Alignment.center, + Alignment.centerRight, + Alignment.bottomLeft, + Alignment.bottomCenter, + Alignment.bottomRight, + ]; + + final alignmentsInfo = [ + "topLeft", + "topCenter", + "topRight", + "centerLeft", + "center", + "centerRight", + "bottomLeft", + "bottomCenter", + "bottomRight", + ]; + + @override + Widget build(BuildContext context) { + return Wrap( + children: alignments + .toList() + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 100, + height: 60, + color: Colors.grey.withAlpha(88), + child: Align( + child: Container( + width: 30, + height: 30, + color: Colors.cyanAccent, + ), + alignment: mode)), + Text(alignmentsInfo[alignments.indexOf(mode)]) + ])) + .toList()); + } +} +// { +// "widgetId": 85, +// "name": 'Align其他用法', +// "priority": 2, +// "subtitle": +// "由于Alignment对象可指定在父容器中宽高的分率位置\n" +// "可以使用Align实现一些复杂的排布需求,比如按指定的数学方程变化位置", +// } +class Ball extends StatelessWidget { + Ball({ + Key key, + this.radius = 15, + this.color = Colors.blue, + }) : super(key: key); + final double radius; //半径 + final Color color; //颜色 + + @override + Widget build(BuildContext context) { + return Container( + width: radius * 2, + height: radius * 2, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + ), + ); + } +} + +class SinLayout extends StatefulWidget { + SinLayout({ + Key key, + }) : super(key: key); + + @override + _SinLayoutState createState() => _SinLayoutState(); +} + +class _SinLayoutState extends State { + var _x = 0.0; //Alignment坐标系上的x坐标 + + @override + Widget build(BuildContext context) { + var item = Container( + width: 300, + height: 120, + color: Colors.black.withAlpha(10), + child: Align( + child: Ball( + color: Colors.orangeAccent, + ), + alignment: Alignment(_x, f(_x * pi)), + ), + ); + + var slider = Slider( + max: 180, + min: -180, + divisions: 360, + label: "${_x.toStringAsFixed(2)}π", + value: _x * 180, + onChanged: (v) => setState(() => _x = v / 180)); + return Column( + mainAxisSize: MainAxisSize.min, + children: [slider, item], + ); + } + + double f(x) { + //映射函数 -- 可随意指定 + double y = sin(x); + return y; + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AnimatedSize.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AnimatedSize.dart new file mode 100644 index 0000000..19137f0 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AnimatedSize.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-01 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 201, +// "name": 'AnimatedAlign基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【vsync】 : vsync 【TickerProvider】", +// } + +class CustomAnimatedSize extends StatefulWidget { + @override + _CustomAnimatedSizeState createState() => _CustomAnimatedSizeState(); +} + +class _CustomAnimatedSizeState extends State + with SingleTickerProviderStateMixin { + final double start = 100; + final double end = 200; + + double _width; + + @override + void initState() { + _width = start; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + alignment: Alignment.center, + child: AnimatedSize( + vsync: this, + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + alignment: Alignment(0, 0), + child: Container( + height: 40, + width: _width, + alignment: Alignment.center, + color: Colors.blue, + child: Text( + '张风捷特烈', + style: TextStyle(color: Colors.white), + ), + ), + ), + ), + ], + ); + } + + Widget _buildSwitch() => Switch( + value: _width == end, + onChanged: (v) { + setState(() { + _width = v ? end : start; + }); + }); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AspectRatio.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AspectRatio.dart new file mode 100644 index 0000000..51ce571 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/AspectRatio.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 77, +// "name": 'AspectRatio基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【aspectRatio】 : 宽高比例 【double】", +// } +class CustomAspectRatio extends StatefulWidget { + @override + _CustomAspectRatioState createState() => _CustomAspectRatioState(); +} + +class _CustomAspectRatioState extends State { + var _ratio = 0.75; + + @override + Widget build(BuildContext context) { + var child = Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 50, + height: 50, + child: Text("Static"), + ); + + var box = AspectRatio( + aspectRatio: _ratio, + child: Container( + color: Colors.orange, + child: Icon( + Icons.android, + color: Colors.white, + )), + ); + + return Column( + children: [ + _buildSlider(), + Container( + color: Colors.grey.withAlpha(22), + width: 300, + height: 100, + child: Row( + children: [child, box, child], + ), + ), + ], + ); + } + + Widget _buildSlider() => Slider( + divisions: 20, + min: 0.1, + max: 2.0, + label: _ratio.toStringAsFixed(2), + value: _ratio, + onChanged: (v) => setState(() => _ratio = v)); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Baseline.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Baseline.dart new file mode 100644 index 0000000..eb70077 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Baseline.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 75, +// "name": 'Baseline基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【baseline】 : 基线位置 【double】\n" +// "【baselineType】 : 基线类型 【TextBaseline】", +// } +class CustomBaseline extends StatefulWidget { + @override + _CustomBaselineState createState() => _CustomBaselineState(); +} + +class _CustomBaselineState extends State { + double _baseline=20; + + @override + Widget build(BuildContext context) { + + var childBox = Text( + '你好,Flutter', + style: TextStyle(fontSize: 20,fontFamily: "Menlo"), + ); + + + var baseline = Baseline( + child: childBox, + baseline: _baseline, + baselineType: TextBaseline.alphabetic + ); + + return Column( + children: [ + _buildSlider(), + Container( + width: 100/0.618, + height: 100, + color: Colors.grey.withAlpha(22), + child: baseline, + ), + ], + ); + } + + Widget _buildSlider() => Slider( + divisions: 20, + min: 0, + max: 60, + label: _baseline.toString(), + value: _baseline, + onChanged: (v) => setState(() => _baseline = v)); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Center.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Center.dart new file mode 100644 index 0000000..cf7540a --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Center.dart @@ -0,0 +1,27 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 86, +// "name": 'Center基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】", +// } +class CustomCenter extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(5), + width: 200, + height: 100, + color: Colors.grey.withAlpha(88), + child: Center( + child: Container( + width: 80, + height: 60, + color: Colors.cyanAccent, + ))); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ColorFiltered.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ColorFiltered.dart new file mode 100644 index 0000000..03de545 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ColorFiltered.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +// { +// "widgetId": 88, +// "name": 'FittedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【colorFilter】 : 滤色器 【ColorFilter】", +// } +class CustomColorFiltered extends StatefulWidget { + @override + _CustomColorFilteredState createState() => _CustomColorFilteredState(); +} + +class _CustomColorFilteredState extends State { + Color _color = Colors.blue.withAlpha(88); + + @override + Widget build(BuildContext context) { + _color = ColorUtils.randomColor(); + return Column( + children: [ + Wrap(spacing: 10, runSpacing: 10, children: [ + _buildRandomColor(), + ...BlendMode.values + .map((mode) => Column( + children: [ + _buildChild(mode), + SizedBox( + height: 10, + ), + Text( + mode.toString().split('.')[1], + style: TextStyle(fontSize: 10), + ) + ], + )) + .toList() + ]), + ], + ); + ; + } + + Widget _buildChild(m) => Container( + width: 58, + height: 58, + child: ColorFiltered( + child: Image(image: AssetImage("assets/images/icon_head.png")), + colorFilter: ColorFilter.mode(_color, m)), + ); + + Widget _buildRandomColor() => GestureDetector( + onTap: () => setState(() {}), + child: Container( + alignment: Alignment.center, + width: 60, + height: 60, + decoration: BoxDecoration(color: _color, shape: BoxShape.circle), + child: Text('点我'), + ), + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ConstrainedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ConstrainedBox.dart new file mode 100644 index 0000000..b245598 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ConstrainedBox.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 80, +// "name": 'BoxConstraints基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【minWidth】 : 最小宽 【double】\n" +// "【minHeight】 : 最小高 【double】\n" +// "【maxHeight】 : 最大高 【double】\n" +// "【maxWidth】 : 最大宽 【double】", +// } +class CustomConstrainedBox extends StatefulWidget { + @override + _CustomConstrainedBoxState createState() => _CustomConstrainedBoxState(); +} + +class _CustomConstrainedBoxState extends State { + var _text = ''; + + @override + Widget build(BuildContext context) { + var child = Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 40, + height: 40, + child: Text("Static"), + ); + + var box = ConstrainedBox( + constraints: BoxConstraints( + minHeight: 50, + minWidth: 20, + maxHeight: 80, + maxWidth: 150, + ), + child: Container(color: Colors.orange, child: Text(_text)), + ); + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(22), + width: 300, + height: 100, + child: Row( + children: [child, UnconstrainedBox(child: box), child], + ), + ), + _buildInput(), + ], + ); + } + + Widget _buildInput() { + return Padding( + padding: const EdgeInsets.all(18.0), + child: TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: '请输入', + ), + onChanged: (v) { + setState(() { + _text = v; + }); + }, + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/CustomPaint.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/CustomPaint.dart new file mode 100644 index 0000000..e980c46 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/CustomPaint.dart @@ -0,0 +1,172 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-28 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 166, +// "name": 'CustomPaint绘线贝塞尔曲线', +// "priority": 2, +// "subtitle": +// " Flutter也支持贝塞尔曲线等复杂绘制。", +// } +class PlayBezier3Page extends StatefulWidget { + @override + _PlayBezier3PageState createState() => _PlayBezier3PageState(); +} + +class _PlayBezier3PageState extends State { + List _pos = []; + int selectPos; + + @override + void initState() { + _initPoints(); + super.initState(); + } + + void _initPoints() { + _pos = List(); + _pos.add(Offset(0, 0)); + _pos.add(Offset(60, -60)); + _pos.add(Offset(-90, -90)); + _pos.add(Offset(-120, -40)); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + width: MediaQuery.of(context).size.width, + child: CustomPaint( + painter: BezierPainter(pos: _pos, selectPos: selectPos), + ), + + ); + } +} + +class BezierPainter extends CustomPainter { + Paint _gridPaint; + Path _gridPath; + + Paint _mainPaint; + Path _mainPath; + int selectPos; + Paint _helpPaint; + + List pos; + + BezierPainter({this.pos, this.selectPos}) { + _gridPaint = Paint()..style = PaintingStyle.stroke; + _gridPath = Path(); + + _mainPaint = Paint() + ..color = Colors.orange + ..style = PaintingStyle.stroke + ..strokeWidth = 2; + _mainPath = Path(); + + _helpPaint = Paint() + ..color = Colors.purple + ..style = PaintingStyle.stroke + ..strokeWidth = 2 + ..strokeCap = StrokeCap.round; + } + + @override + void paint(Canvas canvas, Size size) { + canvas.clipRect(Offset.zero & size); + canvas.translate(size.width / 2, size.height / 2); + _drawGrid(canvas, size); //绘制格线 + _drawAxis(canvas, size); //绘制轴线 + + _mainPath.moveTo(pos[0].dx, pos[0].dy); + _mainPath.cubicTo(pos[1].dx, pos[1].dy, pos[2].dx, pos[2].dy, pos[3].dx, pos[3].dy); + canvas.drawPath(_mainPath, _mainPaint); + _drawHelp(canvas); + _drawSelectPos(canvas); + + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => true; + + void _drawGrid(Canvas canvas, Size size) { + _gridPaint + ..color = Colors.grey + ..strokeWidth = 0.5; + _gridPath = _buildGridPath(_gridPath, size); + canvas.drawPath(_buildGridPath(_gridPath, size), _gridPaint); + + canvas.save(); + canvas.scale(1, -1); //沿x轴镜像 + canvas.drawPath(_gridPath, _gridPaint); + canvas.restore(); + + canvas.save(); + canvas.scale(-1, 1); //沿y轴镜像 + canvas.drawPath(_gridPath, _gridPaint); + canvas.restore(); + + canvas.save(); + canvas.scale(-1, -1); //沿原点镜像 + canvas.drawPath(_gridPath, _gridPaint); + canvas.restore(); + } + + void _drawAxis(Canvas canvas, Size size) { + canvas.drawPoints( + PointMode.lines, + [ + Offset(-size.width / 2, 0), + Offset(size.width / 2, 0), + Offset(0, -size.height / 2), + Offset(0, size.height / 2), + Offset(0, size.height / 2), + Offset(0 - 7.0, size.height / 2 - 10), + Offset(0, size.height / 2), + Offset(0 + 7.0, size.height / 2 - 10), + Offset(size.width / 2, 0), + Offset(size.width / 2 - 10, 7), + Offset(size.width / 2, 0), + Offset(size.width / 2 - 10, -7), + ], + _gridPaint + ..color = Colors.blue + ..strokeWidth = 1.5); + } + + Path _buildGridPath(Path path, Size size, {step = 20.0}) { + for (int i = 0; i < size.height / 2 / step; i++) { + path.moveTo(0, step * i); + path.relativeLineTo(size.width / 2, 0); + } + for (int i = 0; i < size.width / 2 / step; i++) { + path.moveTo(step * i, 0); + path.relativeLineTo( + 0, + size.height / 2, + ); + } + return path; + } + + void _drawHelp(Canvas canvas) { + canvas.drawPoints(PointMode.lines, pos, _helpPaint..strokeWidth = 1); + canvas.drawPoints(PointMode.points, pos, _helpPaint..strokeWidth = 8); + } + + void _drawSelectPos(Canvas canvas) { + if (selectPos == null) return; + canvas.drawCircle( + pos[selectPos], + 10, + _helpPaint + ..color = Colors.green + ..strokeWidth = 2); + } +} \ No newline at end of file diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/colck_page.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/colck_page.dart new file mode 100644 index 0000000..a768860 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/colck_page.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; + +import 'const_res.dart'; + +// { +// "widgetId": 166, +// "name": 'CustomPaint绘线图形', +// "priority": 1, +// "subtitle": +// "【painter】 : 绘画器 【CustomPainter】", +// } +class ClockPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: 100, + child:CustomPaint(//使用CustomPaint盛放画布 + painter: ClockPainter(), + ), + ) + ; + } +} + +class ClockPainter extends CustomPainter { + Paint _paint; + var _radius = 3.0; //小球半径 + Path _path = Path(); //画笔对象 + ClockPainter () { + _paint = Paint()..color= Color(0xff45d0fd)..isAntiAlias=true; + _path.addOval(Rect.fromCircle(radius: _radius, center: Offset(0, 0))); //小球路径 + } + + @override + void paint(Canvas canvas, Size size) { + canvas.translate(size.width/2-65*2, 0); + renderDigit(1, canvas);//渲染数字 + canvas.translate(65, 0);//平移画布 + renderDigit(9, canvas); + canvas.translate(65, 0); renderDigit(9, canvas); + canvas.translate(65, 0); renderDigit(4, canvas); + } + //渲染数字 num :要显示的数字 canvas :画布 + void renderDigit(int num, Canvas canvas) { + if (num > 10) { return; } + for (int i = 0; i < digit[num].length; i++) { + for (int j = 0; j < digit[num][j].length; j++) { + if (digit[num][i][j] == 1) { + canvas.save(); + double rX = j * 2 * (_radius + 1) + (_radius + 1); //第(i,j)个点圆心横坐标 + double rY = i * 2 * (_radius + 1) + (_radius + 1); //第(i,j)个点圆心纵坐标 + canvas.translate(rX, rY); + canvas.drawPath(_path, _paint); + canvas.restore(); + } + } + } + } + @override + bool shouldRepaint(CustomPainter oldDelegate)=>false; +} \ No newline at end of file diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/const_res.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/const_res.dart new file mode 100755 index 0000000..6d3c13a --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/const_res.dart @@ -0,0 +1,136 @@ +const digit = [ + [ + [0, 0, 1, 1, 1, 0, 0], + [0, 1, 1, 0, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 0, 1, 1, 0], + [0, 0, 1, 1, 1, 0, 0] + ], //0 + + [ + [0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [1, 1, 1, 1, 1, 1, 1] + ], //1 + [ + [0, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 1, 1, 0, 0, 0], + [0, 1, 1, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 1, 1, 1, 1, 1] + ], //2 + [ + [1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 1, 1, 0] + ], //3 + + [ + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 0], + [0, 1, 1, 0, 1, 1, 0], + [1, 1, 0, 0, 1, 1, 0], + [1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 1, 1] + ], //4 + [ + [1, 1, 1, 1, 1, 1, 1], + [1, 1, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 1, 1, 0] + ], //5 + [ + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 1, 1, 0, 0, 0], + [0, 1, 1, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0], + [1, 1, 0, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 1, 1, 0] + ], //6 + [ + [1, 1, 1, 1, 1, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 1, 0, 0, 0] + ], //7 + [ + [0, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 1, 1, 0] + ], //8 + [ + [0, 1, 1, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [1, 1, 0, 0, 0, 1, 1], + [0, 1, 1, 1, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 1, 1, 0, 0], + [0, 1, 1, 0, 0, 0, 0] + ], //9 + [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0] + ] //: +]; diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/paper.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/paper.dart new file mode 100644 index 0000000..6ab2185 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/paper.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; + +class Circle { +final double radius; //大小 +final Color color; //颜色 +final Offset pos; //位置 + Circle({this.color, this.pos, this.radius = 1}); +} + +class PaperWidget extends StatefulWidget { + @override + State createState() => _PaperWidgetState(); +} + +class _PaperWidgetState extends State { + var _positions = []; //点集 + var _lines = >[]; //线集 + Offset _oldPos; //记录上一点 + @override + Widget build(BuildContext context) { + var body = Container( + //容器默认全屏 + width: MediaQuery.of(context).size.width, + height: 200, + child: CustomPaint( + painter: PaperPainter(lines: _lines), + ), + ); + return GestureDetector( + child: body, + //手势监听器 + onPanDown: _panDown, + //按下处理 + onPanUpdate: _panUpdate, + //移动处理 + onPanEnd: _panEnd, + //结束处理 + onDoubleTap: () { + //双击清空 + _lines.clear(); + _render(); + }, + ); + } + + void _panDown(DragDownDetails details) { + _lines.add(_positions); + var x = details.localPosition.dx; + var y = details.localPosition.dy; + _oldPos = Offset(x, y); + } + +// 抬起后,将旧线拷贝到线集中 + void _panEnd(DragEndDetails details) { + var oldBall = []; + for (int i = 0; i < _positions.length; i++) { + oldBall.add(_positions[i]); + } + _lines.add(oldBall); + _positions.clear(); + } + + void _panUpdate(DragUpdateDetails details) { + var x = details.localPosition.dx; + var y = details.localPosition.dy; + var curPos = Offset(x, y); + if ((curPos - _oldPos).distance > 3) { +//距离小于3不处理,避免渲染过多 + var circle = Circle( + color:Colors.blue, + pos: curPos, + radius: 6); + _positions.add(circle); + _oldPos = curPos; + _render(); + } + } + + //渲染方法,将重新渲染组件 + void _render() { + setState(() {}); + } +} + +class PaperPainter extends CustomPainter { + + Paint _paint; //画笔 + final List> lines; //记录线的所有点位 + + PaperPainter({ + @required this.lines, + }) { + _paint = Paint() + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round; + } + + @override + void paint(Canvas canvas, Size size) { + for (int i = 0; i < lines.length; i++) { + drawLine(canvas, lines[i]); //绘制线 + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } + + //根据点位绘制线 + void drawLine(Canvas canvas, List positions) { + for (int i = 0; i < positions.length - 1; i++) { + if (positions[i] != null && positions[i + 1] != null) + canvas.drawLine(positions[i].pos, positions[i + 1].pos, + _paint..strokeWidth = positions[i].radius); + } + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/DecoratedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/DecoratedBox.dart new file mode 100644 index 0000000..7805e01 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/DecoratedBox.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; + +// { +// "widgetId": 70, +// "name": 'DecoratedBox基本使用', +// "priority": 1, +// "subtitle": +// "【decoration】 : 装饰对象 【Decoration】\n" +// "【decoration】 : 裁剪行为 【Clip】\n" +// "【position】 : 前景色(左)/后景色(右) 【DecorationPosition】", +// } +class CustomDecoratedBox extends StatelessWidget { + final rainbow = [ + 0xffff0000, + 0xffFF7F00, + 0xffFFFF00, + 0xff00FF00, + 0xff00FFFF, + 0xff0000FF, + 0xff8B00FF + ]; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 30, + children: [_buildDecoratedBox1(), _buildDecoratedBox2()], + ); + } + + Widget _buildDecoratedBox2() { + return DecoratedBox( + position: DecorationPosition.foreground, + decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.black, width: 2)), + //添加渐变色 + gradient: LinearGradient( + stops: [0.0, 1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6, 1.0], + colors: rainbow.map((e) => Color(e)).toList()), + boxShadow: [ + BoxShadow( + color: Colors.orangeAccent, + offset: Offset(1, 1), + blurRadius: 10, + spreadRadius: 1), + ]), + child: Icon( + Icons.android, + size: 80, + color: Colors.black.withAlpha(123), + ), + ); + } + + Widget _buildDecoratedBox1() { + return DecoratedBox( + position: DecorationPosition.background, + decoration: BoxDecoration( + //添加渐变色 + gradient: LinearGradient( + stops: [0.0, 1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6, 1.0], + colors: rainbow.map((e) => Color(e)).toList()), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), bottomRight: Radius.circular(40)), + boxShadow: [ + BoxShadow( + color: Colors.orangeAccent, + offset: Offset(1, 1), + blurRadius: 10, + spreadRadius: 1), + ]), + child: Icon( + Icons.android, + size: 80, + color: Colors.black.withAlpha(123), + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FadeTransition.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FadeTransition.dart new file mode 100644 index 0000000..66240d5 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FadeTransition.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 89, +// "name": 'FadeTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【opacity】 : 动画 【Animation】", +// } +class CustomFadeTransition extends StatefulWidget { + @override + _CustomFadeTransitionState createState() => _CustomFadeTransitionState(); +} + +class _CustomFadeTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 2)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + color: Colors.grey.withAlpha(22), + width: 100, + height: 100, + child: FadeTransition( + opacity: CurvedAnimation(parent: _ctrl, curve: Curves.linear), + child: Icon(Icons.android, color: Colors.green, size: 60), + ), + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FittedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FittedBox.dart new file mode 100644 index 0000000..b13b91a --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FittedBox.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; + +// { +// "widgetId": 87, +// "name": 'FittedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【fit】 : 适应模式 【BoxFit】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomFittedBox extends StatefulWidget { + @override + _CustomFittedBoxState createState() => _CustomFittedBoxState(); +} + +class _CustomFittedBoxState extends State { + double _childW = 20; + double _childH = 30; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Wrap( + spacing: 10, + runSpacing: 10, + children: BoxFit.values + .map((mode) => Column( + children: [ + _buildChild(mode), + SizedBox( + height: 10, + ), + Text(mode.toString().split('.')[1]) + ], + )) + .toList()), + _buildSlider() + ], + ); + } + + Widget _buildChild(BoxFit m) { + return Container( + color: Colors.grey.withAlpha(44), + width: 80, + height: 60, + child: FittedBox( + fit: m, + child: Container( + width: _childW, + height: _childH, + decoration: BoxDecoration( + //添加渐变色 + gradient: LinearGradient( + stops: [0.0, 1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6, 1.0], + colors: Cons.rainbow.map((e) => Color(e)).toList()), + ), + ), + ), + ); + } + + Widget _buildSlider() => Column( + children: [ + Slider( + min: 10, + max: 150, + divisions: 100, + label: '子宽度:' + _childW.toStringAsFixed(1), + value: _childW, + onChanged: (v) => setState(() => _childW = v)), + Slider( + min: 10, + max: 150, + divisions: 100, + label: '子高度:' + _childH.toStringAsFixed(1), + value: _childH, + onChanged: (v) => setState(() => _childH = v)), + ], + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FractionallySizedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FractionallySizedBox.dart new file mode 100644 index 0000000..4d114ee --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/FractionallySizedBox.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 81, +// "name": 'FractionallySizedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【widthFactor】 : 宽分率 【double】\n" +// "【heightFactor】 : 高分率 【double】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomFractionallySizedBox extends StatefulWidget { + @override + _CustomFractionallySizedBoxState createState() => + _CustomFractionallySizedBoxState(); +} + +class _CustomFractionallySizedBoxState + extends State { + var _hf = 0.5; + var _wf = 0.4; + + @override + Widget build(BuildContext context) { + var box = FractionallySizedBox( + widthFactor: _wf, + heightFactor: _hf, + alignment: Alignment.center, + child: Container(color: Colors.orange), + ); + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + child: box), + _buildSlider() + ], + ); + } + + Widget _buildSlider() => Column( + children: [ + Slider( + divisions: 20, + min: 0.0, + max: 2, + label: '宽分率:' + _wf.toStringAsFixed(1), + value: _wf, + onChanged: (v) => setState(() => _wf = v)), + Slider( + divisions: 20, + min: 0.0, + max: 2, + label: '高分率:' + _hf.toStringAsFixed(1), + value: _hf, + onChanged: (v) => setState(() => _hf = v)), + ], + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/LimiteBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/LimiteBox.dart new file mode 100644 index 0000000..3bdf093 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/LimiteBox.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 79, +// "name": 'LimitedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【maxHeight】 : 最大高 【double】\n" +// "【maxWidth】 : 最大宽 【double】", +// } +class CustomLimitedBox extends StatefulWidget { + @override + _CustomLimitedBoxState createState() => _CustomLimitedBoxState(); +} + +class _CustomLimitedBoxState extends State { + var _text = ''; + + @override + Widget build(BuildContext context) { + var child = Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 50, + height: 50, + child: Text("Static"), + ); + + var box = LimitedBox( + maxHeight: 60, + maxWidth: 100, + child: Container(color: Colors.orange, child: Text(_text)), + ); + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(22), + width: 300, + height: 100, + child: Row( + children: [child, UnconstrainedBox(child: box), child], + ), + ), + _buildInput() + ], + ); + } + + Widget _buildInput() { + return Padding( + padding: const EdgeInsets.all(18.0), + child: TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: '请输入', + ), + onChanged: (v) { + setState(() { + _text = v; + }); + }, + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OffStage.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OffStage.dart new file mode 100644 index 0000000..477f3b1 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OffStage.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 71, +// "name": 'Offstage基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【offstage】 : 是否消失 【bool】", +// } +class CustomOffstage extends StatefulWidget { + @override + _CustomOffstageState createState() => _CustomOffstageState(); +} + +class _CustomOffstageState extends State { + bool _off = false; + + @override + Widget build(BuildContext context) { + var radBox = Container( + height: 50, + width: 60, + color: Colors.red, + child: Switch( + value: _off, + onChanged: (v) => setState(() => _off = v)), + ); + + return Container( + width: 250, + height: 200, + child: Row( + children: [radBox, _buildOffStage(), radBox], + ), + ); + } + + Widget _buildOffStage() => Offstage( + offstage: _off, + child: Container( + alignment: Alignment.center, + height: 100, + width: 100, + color: Colors.blue, + child: Text( + "Offstage", + style: TextStyle(fontSize: 20), + ), + )); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Opacity.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Opacity.dart new file mode 100644 index 0000000..38038d0 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Opacity.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 73, +// "name": 'Opacity基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【opacity】 : 透明度0~1 【double】", +// } +class CustomOpacity extends StatefulWidget { + @override + _CustomOpacityState createState() => _CustomOpacityState(); +} + +class _CustomOpacityState extends State { + var _opacity = 0.2; + + @override + Widget build(BuildContext context) { + return Column( + children: [_buildSlider(), _buildOpacity()], + ); + } + + Widget _buildOpacity() => Opacity( + opacity: _opacity, + child: Image.asset( + 'assets/images/icon_head.png', + width: 100, + ), + ); + Widget _buildSlider() => Slider( + divisions: 20, + label: _opacity.toString(), + value: _opacity, + onChanged: (v) => setState(() => _opacity = v)); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OverflowBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OverflowBox.dart new file mode 100644 index 0000000..c5a5141 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/OverflowBox.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 83, +// "name": 'OverflowBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【minWidth】 : 最小宽 【double】\n" +// "【minHeight】 : 最小高 【double】\n" +// "【maxHeight】 : 最大高 【double】\n" +// "【maxWidth】 : 最大宽 【double】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomOverflowBox extends StatefulWidget { + @override + _CustomOverflowBoxState createState() => _CustomOverflowBoxState(); +} + +class _CustomOverflowBoxState extends State { + var _text = ''; + + @override + Widget build(BuildContext context) { + var box = OverflowBox( + alignment: Alignment.center, + minHeight: 50, + minWidth: 50, + maxWidth: 200, + maxHeight: 120, + child: Container( + color: Colors.orange, + child: Text(_text), + ), +// child: Text("张风"), + ); + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(33), + width: 100, + height: 100, + child: box), + _buildInput() + ], + ); + } + + Widget _buildInput() { + return Padding( + padding: const EdgeInsets.all(18.0), + child: TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: '请输入', + ), + onChanged: (v) { + setState(() { + _text = v; + }); + }, + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Padding.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Padding.dart new file mode 100644 index 0000000..8ad91f5 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Padding.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 74, +// "name": 'Padding基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【padding】 : 内四边距 【EdgeInsetsGeometry】", +// } +class CustomPadding extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 150, + child: Padding( + padding: EdgeInsets.all(20), + child: _buildChild(), + ), + ); + } + + Widget _buildChild() { + return Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Text("孩子"), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/RotatedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/RotatedBox.dart new file mode 100644 index 0000000..510cbe2 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/RotatedBox.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 72, +// "name": 'RotatedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【quarterTurns】 : 旋转多少个90° 【int】", +// } +class CustomRotatedBox extends StatefulWidget { + @override + _CustomRotatedBoxState createState() => _CustomRotatedBoxState(); +} + +class _CustomRotatedBoxState extends State { + int _quarterTurns = 0; + + @override + Widget build(BuildContext context) { + return RotatedBox( + quarterTurns: _quarterTurns, + child: GestureDetector( + onTap: () => setState(() => _quarterTurns++), + child: Icon( + Icons.android, + size: 60, + color: Colors.blue, + )), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ShaderMask.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ShaderMask.dart new file mode 100644 index 0000000..5d8ed44 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/ShaderMask.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-12 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 277, +// "name": '径向渐变着色', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【shaderCallback】 : 着色器回调 【ShaderCallback】\n" +// "【blendMode】 : 混色模式 【BlendMode】\n" +// " 通过RadialGradient#createShader创建径向渐变着色器。", +// } +class RadialShaderMask extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ShaderMask( + shaderCallback: _buildShader, + child: Image.asset( + 'assets/images/icon_head.png', + height: 70, + width: 70, + ), + ), + ShaderMask( + shaderCallback: _buildShader, + child: Text( + '张风捷特烈', + style: TextStyle(fontSize: 40, color: Colors.white), + ), + ), + ShaderMask( + shaderCallback: _buildShader, + child: Container( + height: 100, + color: Colors.white, + width: 50, + ), + ), + ], + ); + } + + final colors = [Colors.red, Colors.yellow, Colors.blue]; + + Shader _buildShader(Rect bounds) => RadialGradient( + center: Alignment.topLeft, + radius: 1.0, + tileMode: TileMode.mirror, + colors: colors) + .createShader(bounds); +} + +// { +// "widgetId": 277, +// "name": '线性渐变着色', +// "priority": 2, +// "subtitle": +// "通过LinearGradient#createShader创建线性渐变着色器\n" +// "着色器相关知识详见【绘制专辑】", +// } +class LinearShaderMask extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ShaderMask( + shaderCallback: _buildShader, + child: Image.asset( + 'assets/images/icon_head.png', + height: 70, + width: 70, + ), + ), + ShaderMask( + shaderCallback: _buildShader, + child: Text( + '张风捷特烈', + style: TextStyle(fontSize: 40, color: Colors.white), + ), + ), + ShaderMask( + shaderCallback: _buildShader, + child: Container( + height: 100, + color: Colors.white, + width: 50, + ), + ), + ], + ); + } + + final colors = [Colors.red, Colors.yellow, Colors.blue]; + + Shader _buildShader(Rect bounds) => LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + tileMode: TileMode.mirror, + colors: colors) + .createShader(bounds); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedBox.dart new file mode 100644 index 0000000..45be9dd --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedBox.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 76, +// "name": 'SizedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【width】 : 宽 【double】\n" +// "【height】 : 高 【double】", +// } +class CustomSizedBox extends StatelessWidget { + @override + Widget build(BuildContext context) { + var child = Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 50, + height: 50, + child: Text("Static"), + ); + + var box = SizedBox( + width: 80, + height: 40, + child: Container( + color: Colors.orange, + child: Icon( + Icons.android, + color: Colors.white, + )), + ); + + return Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + child: Row( + children: [child, box, child], + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedOverflowBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedOverflowBox.dart new file mode 100644 index 0000000..1c6ad46 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/SizedOverflowBox.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 84, +// "name": 'SizedOverflowBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【size】 : 尺寸偏移 【Size】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomSizedOverflowBox extends StatefulWidget { + + @override + _CustomSizedOverflowBoxState createState() => _CustomSizedOverflowBoxState(); +} + +class _CustomSizedOverflowBoxState extends State { + double _x = 50; + double _y = 44; + + @override + Widget build(BuildContext context) { + var box = SizedOverflowBox( + alignment: Alignment.bottomRight, + size: Size(_x, _y), + child: Container(width: 30, height: 50, color: Colors.orange), + ); + return Column( + children: [ + Container( + alignment: Alignment.topLeft, + color: Colors.grey.withAlpha(88), + width: 250, + height: 60, + child: box), + _buildSlider() + ], + ); + } + + Widget _buildSlider() => + Column( + children: [ + Slider( + divisions: 100, + min: 0, + max: 250, + label: 'x:' + _x.toStringAsFixed(1), + value: _x, + onChanged: (v) => setState(() => _x = v)), + Slider( + divisions: 100, + min: 0, + max: 100, + label: 'y:' + _y.toStringAsFixed(1), + value: _y, + onChanged: (v) => setState(() => _y = v)), + + ], + ); +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Transform.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Transform.dart new file mode 100644 index 0000000..ff53887 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/Transform.dart @@ -0,0 +1,560 @@ +import 'dart:math'; +import 'dart:math' as prefix0; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CustomTransform extends StatefulWidget { + @override + _CustomTransformState createState() => _CustomTransformState(); +} + +class _CustomTransformState extends State { + var angle = 0.0; + var m = [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.1, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + ]; + + @override + Widget build(BuildContext context) { + var transform = Transform( + transform: Matrix4(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], + m[9], m[10], m[11], m[12], m[13], m[14], m[15]), + child: Container( + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + alignment: Alignment.topLeft, + color: Colors.grey.withAlpha(22), + width: 200, + height: 150, + child: transform, + ), + Text( + '${m[0]},${m[1]},${m[2]},${m[3]},\n' + '${m[4]},${m[5]},${m[6]},${m[7]},\n' + '${m[8]},${m[9]},${m[10]},${m[11]},\n' + '${m[12]},${m[13]},${m[14]},${m[15]}\n', + style: TextStyle(fontSize: 20), + ) + ], + ), + Container( + width: MediaQuery.of(context).size.width, + height: 200, + child: _buildSliders()) + ], + ); + } + + Widget _buildSliders() => GridView.count( + crossAxisCount: 2, + childAspectRatio: 8, + children: m + .asMap() + .keys + .map((i) => Slider( + value: m[i], + max: 0.01, + min: 0.0, + divisions: 10, + onChanged: (v) { + setState(() { + m[i] = v; + }); + })) + .toList()); +} + +// { +// "widgetId": 78, +// "name": '斜切变换skew', +// "priority": 1, +// "subtitle": +// "斜切x由R0C1数控制,入参为弧度值,表示斜切角度\n" +// "斜切y由R1C0数控制,入参为弧度值,表示斜切角度", +// } +class SkewTransform extends StatefulWidget { + @override + _SkewTransformState createState() => _SkewTransformState(); +} + +class _SkewTransformState extends State { + Matrix4 _m4; + double _alpha = 0; + double _beta = 0; + + @override + void initState() { + _m4 = Matrix4.identity(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [_buildTransform(), Matrix4Shower(_m4)], + ), + _buildSliders() + ], + ); + } + + Widget _buildTransform() { + _m4 = Matrix4.skew(_alpha, _beta); + return Transform( + transform: _m4, + child: Container( + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ); + } + + Widget _buildSliders() => Column( + children: [ + Slider( + min: -pi, + max: pi, + value: _alpha, + divisions: 360, + label: 'alpha:' + (_alpha * 180 / pi).toStringAsFixed(1) + "°", + onChanged: (v) { + setState(() { + _alpha = v; + }); + }), + Slider( + min: -pi, + max: pi, + value: _beta, + divisions: 360, + label: 'beta:' + (_beta * 180 / pi).toStringAsFixed(1) + "°", + onChanged: (v) { + setState(() { + _beta = v; + }); + }) + ], + ); +} +// { +// "widgetId": 78, +// "name": '平移变换translationValues', +// "priority": 2, +// "subtitle": +// "平移x由R0C3数控制,入参为数值,表示平移长度\n" +// "平移y由R1C3数控制,入参为数值,表示平移长度\n" +// "平移z由R2C3数控制,入参为数值,表示平移长度", +// } +class TranslationTransform extends StatefulWidget { + @override + _TranslationTransformState createState() => _TranslationTransformState(); +} + +class _TranslationTransformState extends State { + Matrix4 _m4; + double _x = 0; + double _y = 0; + double _z = 0; + + @override + void initState() { + _m4 = Matrix4.identity(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [_buildTransform(), Matrix4Shower(_m4)], + ), + _buildSliders() + ], + ); + } + + Widget _buildTransform() { + _m4 = Matrix4.translationValues(_x, _y, _z); + return Transform( + transform: _m4, + child: Container( + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ); + } + + Widget _buildSliders() => Column( + children: [ + Slider( + min: -100, + max: 100, + value: _x, + divisions: 360, + label: 'x:${_x.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _x = v; + }); + }), + Slider( + min: -100, + max: 100, + value: _y, + divisions: 360, + label: 'y:${_y.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _y = v; + }); + }), + Slider( + min: -100, + max: 100, + value: _z, + divisions: 360, + label: 'z:${_z.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _z = v; + }); + }) + ], + ); +} +// { +// "widgetId": 78, +// "name": '缩放变换diagonal3Values', +// "priority": 3, +// "subtitle": +// "缩放x由R0C0数控制,入参为数值,表示缩放分率\n" +// "缩放y由R1C2数控制,入参为数值,表示缩放分率\n" +// "缩放z由R2C2数控制,入参为数值,表示缩放分率", +// } +class ScaleTransform extends StatefulWidget { + @override + _ScaleTransformState createState() => _ScaleTransformState(); +} + +class _ScaleTransformState extends State { + Matrix4 _m4; + double _x = 1.0; + double _y = 1.0; + double _z = 1.0; + + @override + void initState() { + _m4 = Matrix4.identity(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [_buildTransform(), Matrix4Shower(_m4)], + ), + _buildSliders() + ], + ); + } + + Widget _buildTransform() { + _m4 = Matrix4.diagonal3Values(_x, _y, _z); + return Transform( + transform: _m4, + child: Container( + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ); + } + + Widget _buildSliders() => Column( + children: [ + Slider( + min: -2, + max: 2, + value: _x, + divisions: 360, + label: 'x:${_x.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _x = v; + }); + }), + Slider( + min: -2, + max: 2, + value: _y, + divisions: 360, + label: 'y:${_y.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _y = v; + }); + }), + Slider( + min: -2, + max: 2, + value: _z, + divisions: 360, + label: 'z:${_z.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _z = v; + }); + }) + ], + ); +} +// { +// "widgetId": 78, +// "name": '旋转变换rotation', +// "priority": 4, +// "subtitle": +// "x旋转由R1C1、R1C2、R2C1、R2C2控制,入参表示弧度\n" +// "y旋转由R0C0、R0C2、R2C0、R2C2控制,入参表示弧度\n" +// "z旋转由R0C0、R0C1、R1C0、R1C1控制,入参表示弧度\n" +// } +class RotateTransform extends StatefulWidget { + @override + _RotateTransformState createState() => _RotateTransformState(); +} + +class _RotateTransformState extends State { + Matrix4 _m4; + double _x = 0; + int _rotateFlag = 1; + + @override + void initState() { + _m4 = Matrix4.identity(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [_buildTransform(), Matrix4Shower(_m4)], + ), + _buildSliders() + ], + ); + } + + Widget _buildTransform() { + if (_rotateFlag == 1) { + _m4 = Matrix4.rotationX(_x); + } else if (_rotateFlag == 2) { + _m4 = Matrix4.rotationY(_x); + } else { + _m4 = Matrix4.rotationZ(_x); + } + + return Transform( + transform: _m4, + child: Container( + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ); + } + + final Map map = { + 1: 'rotationX', + 2: 'rotationY', + 3: 'rotationZ', + }; + + Widget _buildSliders() => Column( + children: [ + Wrap( + children: map.keys.map((key) => _buildChild(key)).toList(), + ), + Slider( + min: -pi, + max: pi, + value: _x, + divisions: 360, + label: 'x:${_x.toStringAsFixed(1)}', + onChanged: (v) { + setState(() { + _x = v; + }); + }), + ], + ); + + Padding _buildChild(int key) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: FilterChip( + selectedColor: Colors.orange.withAlpha(55), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + pressElevation: 5, + elevation: 3, + avatar: CircleAvatar(child: Text(key.toString())), + label: Text(map[key]), + selected: _rotateFlag == key, + onSelected: (bool value) { + print(map[key]); + setState(() { + _x = 0; + if (value) { + _rotateFlag = key; + } + }); + }, + ), + ); + } +} +// { +// "widgetId": 78, +// "name": '透视变换rotation', +// "priority": 5, +// "subtitle": +// "由R3C1、R3C2、R3C3控制透视" +// } +class R3C2 extends StatefulWidget { + @override + _R3C2State createState() => _R3C2State(); +} + +class _R3C2State extends State { + Matrix4 _m4; + double _value = 0; + double _rad = 0; + + @override + Widget build(BuildContext context) { + _m4 = Matrix4.identity() +// ..setEntry(3, 0, _value) // x +// ..setEntry(3, 1, _value)// y + ..setEntry(3, 2, _value) // z + ..rotateY(_rad) +// ..rotateX(_rad) + ; + return Column( + children: [ + Transform( + transform: _m4, + child: Container( + color: Colors.cyanAccent, + width: 100, + height: 100, + child: Image.asset( + 'assets/images/wy_300x200.jpg', + fit: BoxFit.cover, + )), + ), + _buildSliders() + ], + ); + } + + Widget _buildSliders() => Column( + children: [ + Slider( + min: -0.01, + max: 0.01, + value: _value, + divisions: 360, + label: 'x:${_value.toStringAsFixed(5)}', + onChanged: (v) { + setState(() { + _value = v; + }); + }), + Slider( + min: -pi, + max: pi, + value: _rad, + divisions: 360, + label: '角度:' + (_rad * 180 / pi).toStringAsFixed(1) + "°", + onChanged: (v) { + setState(() { + _rad = v; + }); + }), + ], + ); +} + +class Matrix4Shower extends StatelessWidget { + final Matrix4 matrix4; + + Matrix4Shower(this.matrix4); + + @override + Widget build(BuildContext context) { + return Container( + child: Text( + '${matrix4.entry(0, 0).toStringAsFixed(1)},${matrix4.entry(0, 1).toStringAsFixed(1)},${matrix4.entry(0, 2).toStringAsFixed(1)},${matrix4.entry(0, 3).toStringAsFixed(1)},\n' + '${matrix4.entry(1, 0).toStringAsFixed(1)},${matrix4.entry(1, 1).toStringAsFixed(1)},${matrix4.entry(1, 2).toStringAsFixed(1)},${matrix4.entry(1, 3).toStringAsFixed(1)},\n' + '${matrix4.entry(2, 0).toStringAsFixed(1)},${matrix4.entry(2, 1).toStringAsFixed(1)},${matrix4.entry(2, 2).toStringAsFixed(1)},${matrix4.entry(2, 3).toStringAsFixed(1)},\n' + '${matrix4.entry(3, 0).toStringAsFixed(1)},${matrix4.entry(3, 1).toStringAsFixed(1)},${matrix4.entry(3, 2).toStringAsFixed(1)},${matrix4.entry(3, 3).toStringAsFixed(1)}', + style: TextStyle(fontSize: 20, color: Colors.blue), + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/UnConstrainedBox.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/UnConstrainedBox.dart new file mode 100644 index 0000000..bfe36f1 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/UnConstrainedBox.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 81, +// "name": 'UnConstrainedBox基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【constrainedAxis】 : 仍受约束的轴*2 【Axis】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】", +// } +class CustomUnConstrainedBox extends StatefulWidget { + @override + _CustomUnConstrainedBoxState createState() => _CustomUnConstrainedBoxState(); +} + +class _CustomUnConstrainedBoxState extends State { + var _value = false; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + children: [_buildUnconstrainedBox(), _buildConstrainedAxis()], + ); + } + + Widget _buildUnconstrainedBox() { + var child = Container( + color: Colors.cyanAccent, + width: 60, + height: 60, + child: Switch( + value: _value, + onChanged: (v) { + setState(() { + _value = v; + }); + }, + ), + ); + + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(22), + width: 150, + height: 100, + child: _value + ? UnconstrainedBox(alignment: Alignment.center, child: child) + : child, + ), + Text(_value ? "已解除约束" : "子组件受约束") + ], + ); + } + + Widget _buildConstrainedAxis() { + return Column( + children: [ + Container( + color: Colors.grey.withAlpha(22), + width: 150, + height: 100, + child: UnconstrainedBox( + alignment: Alignment.center, + constrainedAxis: Axis.vertical, + child: Container( + color: Colors.cyanAccent, + width: 60, + height: 60, + )), + ), + Text("竖直方向仍约束") + ], + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipOval.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipOval.dart new file mode 100644 index 0000000..729f544 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipOval.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + + +// { +// "widgetId": 66, +// "name": 'ClipOval基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【clipBehavior】 : 裁剪行为 【Clip】\n" +// "【clipper】 : 裁剪器 【CustomClipper】", +// } +class CustomClipOval extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + children: [ + ClipOval( + + child: Image.asset( + "assets/images/wy_300x200.jpg", + width: 150, + height: 100, + ), + ), + ClipOval( + child: Image.asset( + "assets/images/wy_300x200.jpg", + width: 100, + height: 100, + fit: BoxFit.cover, + ), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipPath.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipPath.dart new file mode 100644 index 0000000..440d951 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipPath.dart @@ -0,0 +1,67 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 69, +// "name": 'ClipPath基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【clipBehavior】 : 裁剪行为 【Clip】\n" +// "【clipper】 : 裁剪器 【CustomClipper】", +// } +class CustomClipPath extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ClipPath( + clipper: ShapeBorderClipper(shape: _StarShapeBorder()), + child: Image.asset( + "assets/images/wy_300x200.jpg", + width: 150, + height: 100, + fit: BoxFit.cover, + ), + ); + } +} + +class _StarShapeBorder extends ShapeBorder { + final Path _path = Path(); + + @override + EdgeInsetsGeometry get dimensions => null; + + @override + Path getInnerPath(Rect rect, {TextDirection textDirection}) { + return null; + } + + @override + Path getOuterPath(Rect rect, {TextDirection textDirection}) => + nStarPath(20, rect.height / 2, rect.height / 2 * 0.85, + dx: rect.width / 2, dy: rect.height / 2); + + @override + void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {} + + Path nStarPath(int num, double R, double r, {dx = 0, dy = 0}) { + double perRad = 2 * pi / num; + double radA = perRad / 2 / 2; + double radB = 2 * pi / (num - 1) / 2 - radA / 2 + radA; + _path.moveTo(cos(radA) * R + dx, -sin(radA) * R + dy); + for (int i = 0; i < num; i++) { + _path.lineTo( + cos(radA + perRad * i) * R + dx, -sin(radA + perRad * i) * R + dy); + _path.lineTo( + cos(radB + perRad * i) * r + dx, -sin(radB + perRad * i) * r + dy); + } + _path.close(); + return _path; + } + + @override + ShapeBorder scale(double t) { + return null; + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRRect.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRRect.dart new file mode 100644 index 0000000..faabd59 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRRect.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 68, +// "name": 'ClipRRect基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【borderRadius】 : 边线半径 【BorderRadius】\n" +// "【clipBehavior】 : 裁剪行为 【Clip】\n" +// "【clipper】 : 裁剪器 【CustomClipper】", +// } +class CustomClipRRect extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: BorderRadius.all(Radius.elliptical(35, 30)), + child: Image.asset( + "assets/images/wy_300x200.jpg", + width: 150, + height: 100, + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRect.dart b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRect.dart new file mode 100644 index 0000000..ce3f7bc --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/SingleChildRenderObjectWidget/clip/ClipRect.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 67, +// "name": 'ClipRect基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【clipBehavior】 : 裁剪行为 【Clip】\n" +// "【clipper】 : 裁剪器 【CustomClipper】", +// } +class CustomClipRect extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ClipRect( + child: SizedBox( + height: 100, + width: 100, + child: Image.asset( + "assets/images/wy_300x200.jpg", + fit: BoxFit.cover,), + ), + ); + } +} diff --git a/lib/views/widgets/RenderObjectWidget/Table.dart b/lib/views/widgets/RenderObjectWidget/Table.dart new file mode 100644 index 0000000..1d9f9fe --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/Table.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 110, +// "name": 'Table基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 组件列表 【List】\n" +// "【columnWidths】 : 列宽 【Map】\n" +// "【defaultColumnWidth】 : 默认列宽 【TableColumnWidth】\n" +// "【border】 : 边线 【TableBorder】\n" +// "【textDirection】 : 文字方向 【TextDirection】\n" +// "【defaultVerticalAlignment】 : 单元格竖直方向对齐模式 【TableCellVerticalAlignment】", +// } +class CustomTable extends StatelessWidget { + @override + Widget build(BuildContext context) { + var title = _ItemBean("单位称", "量纲", "单位", "单位名称", "单位符号"); + var m = _ItemBean("长度", "L", "1m", "米", "m"); + var kg = _ItemBean("质量", "M", "1Kg", "千克", "Kg"); + var s = _ItemBean("时间", "T", "1s", "秒", "s"); + var a = _ItemBean("安培", "Ι", "1A", "安培", "A"); + var k = _ItemBean("热力学温度", "θ", "1K", "开尔文", "K"); + var mol = _ItemBean("物质的量", "N", "1mol", "摩尔", "mol"); + var cd = _ItemBean("发光强度", "J", "1cd", "坎德拉", "cd"); + + var data = <_ItemBean>[title, m, kg, s, a, k, mol, cd]; + + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Table( + columnWidths: const { + 0: FixedColumnWidth(80.0), + 1: FixedColumnWidth(80.0), + 2: FixedColumnWidth(80.0), + 3: FixedColumnWidth(80.0), + 4: FixedColumnWidth(80.0), + }, + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + border: TableBorder.all( + color: Colors.orangeAccent, width: 1.0, style: BorderStyle.solid), + children: data + .map((item) => TableRow(children: [ + Center( + child: Text( + item.name, + style: TextStyle(color: Colors.blue), + )), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.symbol)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unitSymbol)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unitName)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unit)), + ), + ])) + .toList(), + ), + ); + } +} + +class _ItemBean { + String name; + String symbol; + String unit; + String unitName; + String unitSymbol; + + _ItemBean(this.name, this.symbol, this.unit, this.unitName, this.unitSymbol); +} diff --git a/lib/views/widgets/RenderObjectWidget/render_object_widget.dart b/lib/views/widgets/RenderObjectWidget/render_object_widget.dart new file mode 100644 index 0000000..7708fc9 --- /dev/null +++ b/lib/views/widgets/RenderObjectWidget/render_object_widget.dart @@ -0,0 +1,36 @@ +library render_object_widget; + + +export 'MultiChildRenderObjectWidget/Flex.dart'; +export 'MultiChildRenderObjectWidget/Flow.dart'; +export 'MultiChildRenderObjectWidget/RichText.dart'; +export 'MultiChildRenderObjectWidget/Stack.dart'; +export 'MultiChildRenderObjectWidget/Wrap.dart'; +export 'SingleChildRenderObjectWidget/Align.dart'; +export 'SingleChildRenderObjectWidget/ConstrainedBox.dart'; +export 'SingleChildRenderObjectWidget/ColorFiltered.dart'; +export 'SingleChildRenderObjectWidget/Baseline.dart'; +export 'SingleChildRenderObjectWidget/DecoratedBox.dart'; +export 'SingleChildRenderObjectWidget/FadeTransition.dart'; +export 'SingleChildRenderObjectWidget/FittedBox.dart'; +export 'SingleChildRenderObjectWidget/FractionallySizedBox.dart'; +export 'SingleChildRenderObjectWidget/LimiteBox.dart'; +export 'SingleChildRenderObjectWidget/OffStage.dart'; +export 'SingleChildRenderObjectWidget/Opacity.dart'; +export 'SingleChildRenderObjectWidget/Padding.dart'; +export 'SingleChildRenderObjectWidget/RotatedBox.dart'; +export 'SingleChildRenderObjectWidget/SizedBox.dart'; +export 'SingleChildRenderObjectWidget/SizedOverflowBox.dart'; +export 'SingleChildRenderObjectWidget/Transform.dart'; +export 'SingleChildRenderObjectWidget/UnConstrainedBox.dart'; +export '../StatefulWidget/AnimatedWidget/PositionedTransition.dart'; +export '../StatefulWidget/AnimatedWidget/RotationTransition.dart'; +export '../StatefulWidget/AnimatedWidget/ScaleTransition.dart'; +export '../StatefulWidget/AnimatedWidget/SizeTransition.dart'; +export 'SingleChildRenderObjectWidget/clip/ClipOval.dart'; +export 'SingleChildRenderObjectWidget/clip/ClipPath.dart'; +export 'SingleChildRenderObjectWidget/clip/ClipRRect.dart'; +export 'SingleChildRenderObjectWidget/clip/ClipRect.dart'; +export 'SingleChildRenderObjectWidget/OverflowBox.dart'; +export 'Table.dart'; +export 'SingleChildRenderObjectWidget/AspectRatio.dart'; diff --git a/lib/views/widgets/Sliver/CustomScrollView.dart b/lib/views/widgets/Sliver/CustomScrollView.dart new file mode 100644 index 0000000..c0ac2bd --- /dev/null +++ b/lib/views/widgets/Sliver/CustomScrollView.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 183, +// "name": 'CustomScrollView基本使用', +// "priority": 1, +// "subtitle": +// "【slivers】 : 子组件列表 【List】\n" +// "【reverse】 : 是否反向 【bool】\n" +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【controller】 : 控制器 【ScrollController】", +// } +class CustomScrollViewDemo extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + anchor: 0, + scrollDirection: Axis.vertical, + reverse: false, + slivers: [_buildSliverAppBar(), _buildSliverFixedExtentList()], + ), + ); + } + + Widget _buildSliverFixedExtentList() => SliverFixedExtentList( + itemExtent: 60, + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')), + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + title: Text( + '张风捷特烈', + style: TextStyle(color: Colors.black, //标题 + shadows: [ + Shadow(color: Colors.blue, offset: Offset(1, 1), blurRadius: 2) + ]), + ), + background: Image.asset( + "assets/images/caver.jpeg", fit: BoxFit.cover, + ), + ), + ); + } +} diff --git a/lib/views/widgets/Sliver/FlexibleSpaceBar.dart b/lib/views/widgets/Sliver/FlexibleSpaceBar.dart new file mode 100644 index 0000000..9240e84 --- /dev/null +++ b/lib/views/widgets/Sliver/FlexibleSpaceBar.dart @@ -0,0 +1,110 @@ +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// 说明: +// { +// "widgetId": 196, +// "name": 'SliverAppBar基本使用', +// "priority": 1, +// "subtitle": +// "【title】 : 标题组件 【Widget】\n" +// "【titlePadding】 : 标题间距 【EdgeInsetsGeometry】\n" +// "【collapseMode】 : 折叠模式 【CollapseMode】\n" +// "【stretchModes】 : 延伸模式 【List】\n" +// "【background】 : 背景组件 【Widget】\n" +// "【centerTitle】 : 是否居中 【bool】", +// } +class FlexibleSpaceBarDemo extends StatelessWidget { + + final data = [ + Colors.blue[50], + Colors.blue[100], + Colors.blue[200], + Colors.blue[300], + Colors.blue[400], + Colors.blue[500], + Colors.blue[600], + Colors.blue[700], + Colors.blue[800], + Colors.blue[900], + ]; + + @override + Widget build(BuildContext context) { + return + Container( + height: 300, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + _buildSliverFixedExtentList() + ], + ), + ); + } + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + actions: _buildActions(), + pinned: true, + backgroundColor: Colors.blue, + flexibleSpace: FlexibleSpaceBar(//伸展处布局 + centerTitle: false, + title: Text('张风捷特烈',style: TextStyle(shadows: [ + Shadow(color: Colors.blue, offset: Offset(1, 1), blurRadius: 2) + ]),), + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + stretchModes: [StretchMode.blurBackground,StretchMode.zoomBackground], + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + Widget _buildSliverFixedExtentList() => SliverFixedExtentList( + itemExtent: 60, + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverAppBar.dart b/lib/views/widgets/Sliver/SliverAppBar.dart new file mode 100644 index 0000000..8a78706 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverAppBar.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 183, +// "name": 'SliverAppBar基本使用', +// "priority": 1, +// "subtitle": +// "【leading】 : 左侧组件 【Widget】\n" +// "【title】 : 中间组件 【Widget】\n" +// "【actions】 : 尾部组件列表 【List】\n" +// "【floating】 : 是否浮动 【bool】\n" +// "【pinned】 : 是否顶部停留 【bool】\n" +// "【snap】 : 是否半收展 【bool】\n" +// "【bottom】 : 底部组件 【PreferredSizeWidget】\n" +// "【expandedHeight】 : 延展高度 【double】\n" +// "【elevation】 : 影深 【double】\n" +// "【flexibleSpace】 : 延展空间 【FlexibleSpaceBar】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【controller】 : 控制器 【ScrollController】\n" +// " snap为true时必需floating为true", +// } +class SliverAppBarDemo extends StatefulWidget { + @override + _SliverAppBarDemoState createState() => _SliverAppBarDemoState(); +} + +class _SliverAppBarDemoState extends State { + bool _floating = false; + bool _pinned = false; + bool _snap = false; + + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildTool(), + Container( + height: 300, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + _buildSliverFixedExtentList() + ], + ), + ), + ], + ); + } + + Widget _buildSliverAppBar() { + print(_floating); + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + floating: _floating, + pinned: _pinned, + snap: _snap, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar(//伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + Widget _buildSliverFixedExtentList() => SliverFixedExtentList( + itemExtent: 60, + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + Widget _buildTool() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text('floating'), + Switch( + value: _floating, + onChanged: (v) { + if(_snap&&!v){ + _snap =false; + } + setState(() => _floating = v); + }), + ], + ), + Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text('pinned'), + Switch( + value: _pinned, + onChanged: (v) => setState(() => _pinned = v)), + ], + ) ,Wrap( + direction: Axis.vertical, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text('snap'), + Switch( + value: _snap, + onChanged: (v) { + if(_floating){ + setState(() => _snap = v); + } + + }), + ], + ) + ], + ); + } +} diff --git a/lib/views/widgets/Sliver/SliverFillViewport.dart b/lib/views/widgets/Sliver/SliverFillViewport.dart new file mode 100644 index 0000000..d809bfb --- /dev/null +++ b/lib/views/widgets/Sliver/SliverFillViewport.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 186, +// "name": 'SliverFixedExtentList基本使用', +// "priority": 1, +// "subtitle": +// "【viewportFraction】 : 视口分率 【double】\n" +// "【delegate】 : 孩子代理 【SliverChildDelegate】", +// } +class SliverFillViewportDemo extends StatefulWidget { + @override + _SliverFillViewportDemoState createState() => _SliverFillViewportDemoState(); +} + +class _SliverFillViewportDemoState extends State { + final data = [ + Colors.orange[50], + Colors.orange[100], + Colors.orange[200], + Colors.orange[300], + Colors.orange[400], + Colors.orange[500], + Colors.orange[600], + Colors.orange[700], + Colors.orange[800], + Colors.orange[900], + ]; + var _viewportFraction = 0.5; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildTool(), + Container( + height: 300, + child: CustomScrollView( + slivers: [_buildSliverAppBar(), _buildSliverList()], + ), + ), + ], + ); + } + + Widget _buildSliverList() => SliverFillViewport( + viewportFraction: _viewportFraction, + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + _buildTool() { + return Slider( + value: _viewportFraction, + min: 0.01, + divisions: 20, + label: _viewportFraction.toStringAsFixed(1), + max: 2.0, + onChanged: (v) => setState(() => _viewportFraction = v)); + } +} diff --git a/lib/views/widgets/Sliver/SliverFixedExtentList.dart b/lib/views/widgets/Sliver/SliverFixedExtentList.dart new file mode 100644 index 0000000..b5c18f5 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverFixedExtentList.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 186, +// "name": 'SliverFixedExtentList基本使用', +// "priority": 1, +// "subtitle": +// "【itemExtent】 : 主轴方向强迫长度 【double】\n" +// "【delegate】 : 孩子代理 【SliverChildDelegate】", +// } +class SliverFixedExtentListDemo extends StatefulWidget { + @override + _SliverFixedExtentListDemoState createState() => _SliverFixedExtentListDemoState(); +} + +class _SliverFixedExtentListDemoState extends State { + final data = [ + Colors.orange[50], + Colors.orange[100], + Colors.orange[200], + Colors.orange[300], + Colors.orange[400], + Colors.orange[500], + Colors.orange[600], + Colors.orange[700], + Colors.orange[800], + Colors.orange[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [_buildSliverAppBar(), _buildSliverList()], + ), + ); + } + + Widget _buildSliverList() => SliverFixedExtentList( + itemExtent: 50, + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverGrid.dart b/lib/views/widgets/Sliver/SliverGrid.dart new file mode 100644 index 0000000..eda5d5e --- /dev/null +++ b/lib/views/widgets/Sliver/SliverGrid.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 188, +// "name": 'SliverList基本使用', +// "priority": 1, +// "subtitle": +// "SliverGrid.count 指定轴向数量构造\n" +// "SliverGrid.extent 指定轴向长度构造\n" +// "属性特征同GridView,可详见之", +// } +class SliverGirdDemo extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF6600FF - 2 * i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [_buildSliverAppBar(), _buildSliverList()], + ), + ); + } + + Widget _buildSliverList() => SliverGrid.extent( + childAspectRatio: 1 / 0.618, + maxCrossAxisExtent: 180, + crossAxisSpacing: 5, + mainAxisSpacing: 5, + children: data + .map((e) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: e, + child: Text( + colorString(e), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverList.dart b/lib/views/widgets/Sliver/SliverList.dart new file mode 100644 index 0000000..b907238 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverList.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 185, +// "name": 'SliverList基本使用', +// "priority": 1, +// "subtitle": +// "【delegate】 : 孩子代理 【SliverChildDelegate】", +// } +class SliverListDemo extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [_buildSliverAppBar(), _buildSliverList()], + ), + ); + } + + Widget _buildSliverList() => SliverList( + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverOpacity.dart b/lib/views/widgets/Sliver/SliverOpacity.dart new file mode 100644 index 0000000..e320514 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverOpacity.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 192, +// "name": 'SliverOpacity基本使用', +// "priority": 1, +// "subtitle": +// "【opacity】 : 透明度 【double】\n" +// "【sliver】 : 子组件 【Function()】", +// } +class SliverOpacityDemo extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF6600FF - 2 * i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + SliverPadding( + padding: EdgeInsets.only(top: 10), + sliver: SliverOpacity(opacity: 0.2, sliver: _buildSliverGrid())) + ], + ), + ); + } + + Widget _buildSliverGrid() => SliverGrid.extent( + childAspectRatio: 1 / 0.618, + maxCrossAxisExtent: 180, + crossAxisSpacing: 5, + mainAxisSpacing: 5, + children: data + .map((e) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: e, + child: Text( + colorString(e), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverPadding.dart b/lib/views/widgets/Sliver/SliverPadding.dart new file mode 100644 index 0000000..96e286e --- /dev/null +++ b/lib/views/widgets/Sliver/SliverPadding.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 191, +// "name": 'SliverPadding基本使用', +// "priority": 1, +// "subtitle": +// "【sliver】 : 子组件 【Widget】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class SliverPaddingDemo extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF6600FF - 2 * i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [_buildSliverAppBar(), SliverPadding( + padding: EdgeInsets.only(top: 10), + sliver + : _buildSliverGrid())], + ), + ); + } + + Widget _buildSliverGrid() => SliverGrid.extent( + childAspectRatio: 1 / 0.618, + maxCrossAxisExtent: 180, + crossAxisSpacing: 5, + mainAxisSpacing: 5, + children: data + .map((e) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: e, + child: Text( + colorString(e), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 5, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/Sliver/SliverPersistentHeader.dart b/lib/views/widgets/Sliver/SliverPersistentHeader.dart new file mode 100644 index 0000000..cec3816 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverPersistentHeader.dart @@ -0,0 +1,165 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 190, +// "name": 'SliverPersistentHeader基本使用', +// "priority": 1, +// "subtitle": +// "【delegate】 : 代理 【SliverPersistentHeaderDelegate】\n" +// "【floating】 : 是否浮动 【bool】\n" +// "【pinned】 : 是否顶部停留 【bool】", +// } +class SliverPersistentHeaderDemo extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 500, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + _buildPersistentHeader('袅缈岁月,青丝银发',Color(0xffe7fcc9)), + _buildCommonWidget(), + _buildPersistentHeader('以梦为马,不负韶华',Color(0xffcca4ff)), + _buildSliverList() + ], + ), + ); + } + + Widget _buildCommonWidget() => SliverToBoxAdapter( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + color: Colors.grey.withAlpha(22), + child: ListTile( + leading: Image.asset("assets/images/icon_head.png"), + title: Text("以梦为马"), + subtitle: Text("海子"), + selected: true, + contentPadding: EdgeInsets.all(5), + trailing: Icon(Icons.more_vert), + ), + ), + ); + Widget _buildPersistentHeader(String text,Color color) => SliverPersistentHeader( + pinned: true, + delegate: _SliverDelegate( + minHeight: 40.0, + maxHeight: 100.0, + child: Container( + color: color, + child: Center( + child: Text(text, style: TextStyle( + fontSize: 18, + shadows: [Shadow(color: Colors.white, offset: Offset(1, 1))]), + ), + )), + )); + + Widget _buildSliverList() => SliverList( + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 2, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + + +class _SliverDelegate extends SliverPersistentHeaderDelegate { + _SliverDelegate({ + @required this.minHeight, + @required this.maxHeight, + @required this.child, + }); + + final double minHeight; //最小高度 + final double maxHeight; //最大高度 + final Widget child; //孩子 + + @override + double get minExtent => minHeight; + + @override + double get maxExtent => max(maxHeight, minHeight); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return new SizedBox.expand(child: child); + } + + @override //是否需要重建 + bool shouldRebuild(_SliverDelegate oldDelegate) { + return maxHeight != oldDelegate.maxHeight || + minHeight != oldDelegate.minHeight || + child != oldDelegate.child; + } +} \ No newline at end of file diff --git a/lib/views/widgets/Sliver/SliverToBoxAdapter.dart b/lib/views/widgets/Sliver/SliverToBoxAdapter.dart new file mode 100644 index 0000000..3eaa525 --- /dev/null +++ b/lib/views/widgets/Sliver/SliverToBoxAdapter.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 189, +// "name": 'SliverToBoxAdapter基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】", +// } +class SliverToBoxAdapterDemo extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: CustomScrollView( + slivers: [ + _buildSliverAppBar(), + _buildCommonWidget(), + _buildSliverList() + ], + ), + ); + } + + Widget _buildCommonWidget() => SliverToBoxAdapter( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + color: Colors.grey.withAlpha(22), + child: ListTile( + leading: Image.asset("assets/images/icon_head.png"), + title: Text("以梦为马"), + subtitle: Text("海子"), + selected: true, + contentPadding: EdgeInsets.all(5), + trailing: Icon(Icons.more_vert), + ), + ), + ); + + Widget _buildSliverList() => SliverList( + delegate: SliverChildBuilderDelegate( + (_, int index) => Container( + alignment: Alignment.center, + width: 100, + height: 60, + color: data[index], + child: Text( + colorString(data[index]), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ), + childCount: data.length), + ); + + Widget _buildSliverAppBar() { + return SliverAppBar( + expandedHeight: 190.0, + leading: _buildLeading(), + title: Text('张风捷特烈'), + actions: _buildActions(), + elevation: 2, + pinned: true, + backgroundColor: Colors.orange, + flexibleSpace: FlexibleSpaceBar( + //伸展处布局 + titlePadding: EdgeInsets.only(left: 55, bottom: 15), //标题边距 + collapseMode: CollapseMode.parallax, //视差效果 + background: Image.asset( + "assets/images/caver.jpeg", + fit: BoxFit.cover, + ), + ), + ); + } + + Widget _buildLeading() => Container( + margin: EdgeInsets.all(10), + child: Image.asset('assets/images/icon_head.png')); + + List _buildActions() => [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.star_border, + color: Colors.white, + ), + ) + ]; + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedCrossFade.dart b/lib/views/widgets/StatefulWidget/AnimatedCrossFade.dart new file mode 100644 index 0000000..f1f8a80 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedCrossFade.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-20 +/// contact me by email 1981462002@qq.com +/// 说明: + + +// { +// "widgetId": 100, +// "name": 'AnimatedCrossFade基本使用', +// "priority": 1, +// "subtitle": +// "【firstChild】 : 第一孩子 【Widget】\n" +// "【secondChild】 : 第二孩子 【Widget】\n" +// "【crossFadeState】 : 显示第几个 【CrossFadeState】\n" +// "【duration】 : 时长 【Duration】", +// } +class CustomAnimatedCrossFade extends StatefulWidget { + @override + _CustomAnimatedCrossFadeState createState() => + _CustomAnimatedCrossFadeState(); +} + +class _CustomAnimatedCrossFadeState extends State { + var _crossFadeState = CrossFadeState.showFirst; + + bool get isFirst => _crossFadeState == CrossFadeState.showFirst; + + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + child: AnimatedCrossFade( + firstChild: Container( + alignment: Alignment.center, + width: 200, + height: 150, + color: Colors.orange, + child: FlutterLogo(colors: Colors.blue, size: 100,), + ), + secondChild: Container( + width: 200, + height: 150, + alignment: Alignment.center, + color: Colors.blue, + child: FlutterLogo( + textColor: Colors.white, + colors: Colors.orange, + size: 100, + style: FlutterLogoStyle.stacked,), + ), + duration: Duration(milliseconds: 600), + + crossFadeState: _crossFadeState, + ), + ), + _buildSwitch(), + ], + + ); + } + + Widget _buildSwitch() => + Switch(value: isFirst, onChanged: (v) { + setState(() { + _crossFadeState = + v ? CrossFadeState.showFirst : CrossFadeState.showSecond; + }); + }); +} +// { +// "widgetId": 100, +// "name": 'AnimatedCrossFade基本使用', +// "priority": 2, +// "subtitle": +// "【firstCurve】 : 第一曲线 【Curve】\n" +// "【secondCurve】 : 第二曲线 【Curve】\n" +// "【sizeCurve】 : 尺寸变化曲线 【CrossFadeState】", +// } +class CurveAnimatedCrossFade extends StatefulWidget { + @override + _CurveAnimatedCrossFadeState createState() => _CurveAnimatedCrossFadeState(); +} + +class _CurveAnimatedCrossFadeState extends State { + var _crossFadeState = CrossFadeState.showFirst; + + bool get isFirst=> _crossFadeState == CrossFadeState.showFirst; + + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + child: AnimatedCrossFade( + firstCurve: Curves.easeInCirc, + secondCurve: Curves.easeInToLinear, + sizeCurve: Curves.bounceOut, + firstChild: Container( + alignment: Alignment.center, + width: 200, + height: 80, + color: Colors.orange , + child: FlutterLogo(colors: Colors.blue,size: 50,), + ), + secondChild: Container( + width: 200, + height: 150, + alignment: Alignment.center, + color: Colors.blue, + child: FlutterLogo( + textColor: Colors.white, + colors: Colors.orange,size: 100,style: FlutterLogoStyle.stacked,), + ), + duration: Duration(milliseconds: 1000), + crossFadeState: _crossFadeState, + ), + ), + _buildSwitch(), + ], + ); + } + + Widget _buildSwitch() => Switch(value: isFirst, onChanged: (v){ + setState(() { + _crossFadeState= v?CrossFadeState.showFirst:CrossFadeState.showSecond; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedList.dart b/lib/views/widgets/StatefulWidget/AnimatedList.dart new file mode 100644 index 0000000..d148ddf --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedList.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 117, +// "name": 'AnimatedList基本使用', +// "priority": 1, +// "subtitle": +// "【itemBuilder】 : 组件构造器 【AnimatedListItemBuilder】\n" +// "【initialItemCount】 : 子组件数量 【int】\n" +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【controller】 : 滑动控制器 【ScrollController】\n" +// "【reverse】 : 数据是否反向 【bool】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class CustomAnimatedList extends StatefulWidget { + @override + _CustomAnimatedListState createState() => _CustomAnimatedListState(); +} + +class _CustomAnimatedListState extends State { + final GlobalKey _listKey = GlobalKey(); + ListModel _list; + int _selectedItem; + int _nextItem; + + @override + void initState() { + super.initState(); + _list = ListModel( + listKey: _listKey, + initialItems: [0, 1, 2, 3], + removedItemBuilder: _buildRemovedItem, + ); + _nextItem = 4; + } + + Widget _buildItem( + BuildContext context, int index, Animation animation) { + return CardItem( + animation: animation, + item: _list[index], + selected: _selectedItem == _list[index], + onTap: () { + setState(() { + _selectedItem = _selectedItem == _list[index] ? null : _list[index]; + }); + }, + ); + } + + Widget _buildRemovedItem( + int item, BuildContext context, Animation animation) { + return CardItem( + animation: animation, + item: item, + selected: false, + ); + } + + void _insert() { + final int index = + _selectedItem == null ? _list.length : _list.indexOf(_selectedItem); + _list.insert(index, _nextItem++); + } + + void _remove() { + if (_selectedItem != null) { + _list.removeAt(_list.indexOf(_selectedItem)); + setState(() { + _selectedItem = null; + }); + } + } + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.grey.withAlpha(33), + width: MediaQuery.of(context).size.width/2, + child: Column( + children: [ + _buildBtn(), + Container( + width: MediaQuery.of(context).size.width/2, + height: 300, + child: AnimatedList( + padding: EdgeInsets.all(10.0), + key: _listKey, + initialItemCount: _list.length, + itemBuilder: _buildItem, + ), + ) + ], + )); + } + + Widget _buildBtn() => Row( + children: [ + IconButton( + icon: const Icon( + Icons.add_circle, + color: Colors.blue, + ), + onPressed: _insert, + ), + IconButton( + icon: const Icon(Icons.remove_circle, color: Colors.blue), + onPressed: _remove, + ), + ], + ); +} + +class ListModel { + ListModel({ + @required this.listKey, + @required this.removedItemBuilder, + Iterable initialItems, + }) : assert(listKey != null), + assert(removedItemBuilder != null), + _items = List.from(initialItems ?? []); + final GlobalKey listKey; + final dynamic removedItemBuilder; + final List _items; + + AnimatedListState get _animatedList => listKey.currentState; + + void insert(int index, E item) { + _items.insert(index, item); + _animatedList.insertItem(index); + } + + E removeAt(int index) { + final E removedItem = _items.removeAt(index); + if (removedItem != null) { + _animatedList.removeItem(index, + (BuildContext context, Animation animation) => + removedItemBuilder(removedItem, context, animation), + ); + } + return removedItem; + } + + int get length => _items.length; + + E operator [](int index) => _items[index]; + + int indexOf(E item) => _items.indexOf(item); +} + +class CardItem extends StatelessWidget { + const CardItem( + {Key key, + @required this.animation, + this.onTap, + @required this.item, + this.selected: false}) + : assert(animation != null), + assert(item != null && item >= 0), + assert(selected != null), + super(key: key); + final Animation animation; + final VoidCallback onTap; + final int item; + final bool selected; + + @override + Widget build(BuildContext context) { + return SizeTransition( + axis: Axis.vertical, + sizeFactor: animation, + child: Card( + child: Container( + color: Colors.primaries[item % Colors.primaries.length], + child: CheckboxListTile( + dense: true, + title: Text( + 'Item $item', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + value: selected, + onChanged: (v) => onTap()), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedSwitcher.dart b/lib/views/widgets/StatefulWidget/AnimatedSwitcher.dart new file mode 100644 index 0000000..f3d87c5 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedSwitcher.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 116, +// "name": 'AnimatedSwitcher基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【switchOutCurve】 : 切出曲线 【Curves】\n" +// "【switchInCurve】 : 切入曲线 【Curves】\n" +// "【switchInCurve】 : 切入曲线 【Curves】\n" +// "【transitionBuilder】 : 动画构造器 【Widget Function(Widget, Animation)】", +// } + +class CustomAnimatedSwitcher extends StatefulWidget { + @override + _CustomAnimatedSwitcherState createState() => _CustomAnimatedSwitcherState(); +} + +class _CustomAnimatedSwitcherState extends State { + int _count = 0; + + @override + Widget build(BuildContext context) { + return Container( + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + _buildMinusBtn(), + SizedBox(width:80,child: _buildAnimatedSwitcher(context)), + _buildAddBtn() + ], + ), + ); + } + + Widget _buildAnimatedSwitcher(BuildContext context) => + AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: (Widget child, Animation animation) => + ScaleTransition( + child: RotationTransition(turns: animation, child: child), + scale: animation), + child: Text( + '$_count', + key: ValueKey(_count), + style: Theme.of(context).textTheme.display3, + ), + ); + + Widget _buildMinusBtn() { + return MaterialButton( + padding: EdgeInsets.all(0), + textColor: Color(0xffFfffff), + elevation: 3, + color: Colors.red, + highlightColor: Color(0xffF88B0A), + splashColor: Colors.red, + child: Icon( + Icons.remove, + color: Colors.white, + ), + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: () => setState(() => _count -= 1)); + } + + Widget _buildAddBtn() => MaterialButton( + padding: EdgeInsets.all(0), + textColor: Color(0xffFfffff), + elevation: 3, + color: Colors.blue, + highlightColor: Color(0xffF88B0A), + splashColor: Colors.red, + child: Icon( + Icons.add, + color: Colors.white, + ), + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: () => setState(() => _count += 1)); +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/AlignTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/AlignTransition.dart new file mode 100644 index 0000000..861bd0b --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/AlignTransition.dart @@ -0,0 +1,56 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 111, +// "name": 'AlignTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【alignment】 : 对齐动画 【Animation】", +// } +class CustomAlignTransition extends StatefulWidget { + @override + _CustomAlignTransitionState createState() => _CustomAlignTransitionState(); +} + +class _CustomAlignTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + width: MediaQuery.of(context).size.width, + color: Colors.grey.withAlpha(33), + height: 100, + child: AlignTransition( + alignment: AlignmentTween( + begin: Alignment.topLeft, end: Alignment.bottomRight) + .animate(_ctrl), + child: Container( + child: Icon(Icons.android, color: Colors.green, size: 60)), + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/DecoratedBoxTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/DecoratedBoxTransition.dart new file mode 100644 index 0000000..c3bdae5 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/DecoratedBoxTransition.dart @@ -0,0 +1,77 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 113, +// "name": 'DecoratedBoxTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【position】 : 前/背景色 【DecorationPosition】\n" +// "【decoration】 : 动画 【Animation】", +// } +class CustomDecoratedBoxTransition extends StatefulWidget { + @override + _CustomDecoratedBoxTransitionState createState() => + _CustomDecoratedBoxTransitionState(); +} + +class _CustomDecoratedBoxTransitionState + extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + width: 200, + height: 100, + child: DecoratedBoxTransition( + position: DecorationPosition.background, + decoration: DecorationTween( + begin: BoxDecoration( + color: Colors.greenAccent, + borderRadius: BorderRadius.all(Radius.circular(50)), + boxShadow: [ + BoxShadow( + offset: Offset(1, 1), + color: Colors.purple, + blurRadius: 3, + spreadRadius: 1) + ]), + end: BoxDecoration( + color: Colors.orange, + borderRadius: BorderRadius.all(Radius.circular(10)), + boxShadow: [ + BoxShadow( + offset: Offset(1, 1), + color: Colors.blue, + blurRadius: 1, + spreadRadius: 0) + ])).animate(_ctrl), + child: Container( + child: Icon(Icons.android, color: Colors.white, size: 60)), + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/DefaultTextStyleTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/DefaultTextStyleTransition.dart new file mode 100644 index 0000000..7c22675 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/DefaultTextStyleTransition.dart @@ -0,0 +1,71 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 113, +// "name": 'DefaultTextStyleTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【textAlign】 : 文字对齐方式 【TextAlign】\n" +// "【softWrap】 : 是否包裹 【bool】\n" +// "【maxLines】 : 最大行数 【int】\n" +// "【overflow】 : 溢出模式 【TextOverflow】\n" +// "【style】 : 动画 【Animation】", +// } +class CustomDefaultTextStyleTransition extends StatefulWidget { + @override + _CustomDefaultTextStyleTransitionState createState() => + _CustomDefaultTextStyleTransitionState(); +} + +class _CustomDefaultTextStyleTransitionState + extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + alignment: Alignment.center, + width: 300, + height: 100, + child: DefaultTextStyleTransition( + textAlign: TextAlign.start, + softWrap: true, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyleTween( + begin: TextStyle(color: Colors.blue, fontSize: 50, shadows: [ + Shadow( + offset: Offset(1, 1), color: Colors.black, blurRadius: 3) + ]), + end: TextStyle(color: Colors.white, fontSize: 20, shadows: [ + Shadow( + offset: Offset(1, 1), color: Colors.purple, blurRadius: 3) + ])).animate(_ctrl), + child: Text('张风捷特烈'), + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/PositionedTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/PositionedTransition.dart new file mode 100644 index 0000000..e397469 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/PositionedTransition.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 92, +// "name": 'PositionedTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【rect】 : 动画 【Animation】\n" +// " PositionedTransition组件只能在Stack内起作用", +// } +class CustomPositionedTransition extends StatefulWidget { + @override + _CustomPositionedTransitionState createState() => + _CustomPositionedTransitionState(); +} + +class _CustomPositionedTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 2)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + color: Colors.grey.withAlpha(33), + width: 200, + height: 100, + child: Stack( + children: [ + PositionedTransition( + rect: RelativeRectTween( + begin: RelativeRect.fromLTRB(0, 50, 150, 100), + end: RelativeRect.fromLTRB(60, 0, 150, -50), + ).animate(_ctrl), + child: Icon( + Icons.android, + color: Colors.green, + size: 50, + ), + ) + ], + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/RelativePositionedTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/RelativePositionedTransition.dart new file mode 100644 index 0000000..69814d7 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/RelativePositionedTransition.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 115, +// "name": 'RelativePositionedTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【size】 : 左和上的偏移量 【Size】\n" +// "【rect】 : 动画 【Animation】\n" +// " PositionedTransition组件只能在Stack内起作用", +// } +class CustomRelativePositionedTransition extends StatefulWidget { + @override + _CustomRelativePositionedTransitionState createState() => + _CustomRelativePositionedTransitionState(); +} + +class _CustomRelativePositionedTransitionState + extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 2)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + color: Colors.grey.withAlpha(33), + width: 200, + height: 100, + child: Stack( + children: [ + RelativePositionedTransition( + size: Size(200, 100), + rect: RectTween( + begin: Rect.fromLTRB(0, 0, 50, 50), + end: Rect.fromLTRB(0, 0, 50, 50).translate(100, 50), + ).animate(_ctrl), + child: Icon( + Icons.android, + color: Colors.green, + size: 50, + ), + ) + ], + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/RotationTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/RotationTransition.dart new file mode 100644 index 0000000..ef9e4bd --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/RotationTransition.dart @@ -0,0 +1,53 @@ + +import 'package:flutter/material.dart'; +// { +// "widgetId": 90, +// "name": 'RotationTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【turns】 : 是否消失 【Animation】", +// } +class CustomRotationTransition extends StatefulWidget { + @override + _CustomRotationTransitionState createState() => _CustomRotationTransitionState(); +} + +class _CustomRotationTransitionState extends State with SingleTickerProviderStateMixin{ + + AnimationController _ctrl; + + @override + void initState() { + _ctrl= AnimationController(vsync: this,duration: Duration(seconds: 2)); + _ctrl.forward(); + super.initState(); + } +@override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + color: Colors.grey.withAlpha(22), + width: 100, + height: 100, + child: RotationTransition( + turns: CurvedAnimation(parent: _ctrl, curve: Curves.linear), + child: Icon(Icons.android,color: Colors.green,size: 60), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/ScaleTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/ScaleTransition.dart new file mode 100644 index 0000000..ecc02f0 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/ScaleTransition.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 91, +// "name": 'ScaleTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【scale】 : 动画 【Animation】", +// } +class CustomScaleTransition extends StatefulWidget { + @override + _CustomScaleTransitionState createState() => _CustomScaleTransitionState(); +} + +class _CustomScaleTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 2)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + color: Colors.grey.withAlpha(22), + width: 100, + height: 100, + child: ScaleTransition( + scale: CurvedAnimation(parent: _ctrl, curve: Curves.linear), + child: Icon(Icons.android, color: Colors.green, size: 60), + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/SizeTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/SizeTransition.dart new file mode 100644 index 0000000..535d0d5 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/SizeTransition.dart @@ -0,0 +1,67 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 92, +// "name": 'FadeTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【axis】 : 轴向*2 【Axis】\n" +// "【sizeFactor】 : 动画 【Animation】", +// } +class CustomSizeTransition extends StatefulWidget { + @override + _CustomSizeTransitionState createState() => _CustomSizeTransitionState(); +} + +class _CustomSizeTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Wrap( + runSpacing: 20, + children: [ + SizeTransition( + axis: Axis.horizontal, + sizeFactor: CurvedAnimation(parent: _ctrl, curve: Curves.linear), + child: Container( + width: MediaQuery.of(context).size.width, + color: Colors.orange, + child: Icon(Icons.android, color: Colors.green, size: 80)), + ), + SizeTransition( + axis: Axis.vertical, + sizeFactor: CurvedAnimation(parent: _ctrl, curve: Curves.linear), + child: Container( + width: MediaQuery.of(context).size.width, + color: Colors.orange, + child: Icon(Icons.android, color: Colors.green, size: 80)), + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/AnimatedWidget/SlideTransition.dart b/lib/views/widgets/StatefulWidget/AnimatedWidget/SlideTransition.dart new file mode 100644 index 0000000..b7d9a6b --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AnimatedWidget/SlideTransition.dart @@ -0,0 +1,59 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 112, +// "name": 'SlideTransition基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【textDirection】 : x轴方向 【TextDirection】\n" +// "【position】 : 动画 【Animation】", +// } +class CustomSlideTransition extends StatefulWidget { + @override + _CustomSlideTransitionState createState() => _CustomSlideTransitionState(); +} + +class _CustomSlideTransitionState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Container( + width: MediaQuery.of(context).size.width, + color: Colors.grey.withAlpha(33), + height: 100, + child: SlideTransition( + textDirection: TextDirection.ltr, + position: Tween( + begin: Offset.zero, + end: Offset(0.2, 0.2), + ).animate(_ctrl), + child: Container( + child: Icon(Icons.android, color: Colors.green, size: 60)), + ), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/AppBar.dart b/lib/views/widgets/StatefulWidget/AppBar.dart new file mode 100755 index 0000000..5742ed3 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/AppBar.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'PopupMenuButton.dart'; + +// { +// "widgetId": 57, +// "name": 'AppBar基本使用', +// "priority": 1, +// "subtitle": +// "【leading】 : 左侧组件 【Widget】\n" +// "【title】 : 中间组件 【Widget】\n" +// "【actions】 : 右侧组件 【List】\n" +// "【elevation】 : 影深 【double】\n" +// "【shape】 : 形状 【ShapeBorder】\n" +// "【backgroundColor】 : 影深 【背景色】\n" +// "【centerTitle】 : 中间是否居中 【bool】", +// } + +class CustomAppBar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AppBar( + title: Text('风雅六社'), + leading: BackButton(), + backgroundColor: Colors.amber[500], + elevation: 2, + centerTitle: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + topRight: Radius.circular(5), + bottomLeft: Radius.circular(5), + )), + actions: [ + IconButton( + icon: Icon(Icons.star), + tooltip: 'like', + onPressed: () { + // do nothing + }), + CustomPopupMenuButton() + ], + ); + } +} + +// { +// "widgetId": 57, +// "name": 'AppBar与TabBar、TabBarView联用', +// "priority": 2, +// "subtitle": +// "【bottom】 : 底部组件 【PreferredSizeWidget】", +// } +class TabAppBar extends StatefulWidget { + @override + _TabAppBarState createState() => _TabAppBarState(); +} + +class _TabAppBarState extends State + with SingleTickerProviderStateMixin { + final tabs = ['风画庭', '雨韵舍', '雷鸣殿', '电疾堂', '霜寒阁', '雪月楼']; + TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + height: 180, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + "assets/images/sabar.jpg", + ), + fit: BoxFit.cover)), + child: _buildAppBar(), + ), + Container( + height: 150, color: Color(0xff916BF0), child: _buildTableBarView()) + ], + ); + } + + Widget _buildAppBar() => AppBar( + title: Text('风雅六社'), + elevation: 1, + leading: BackButton(), + backgroundColor: Colors.amber[500].withAlpha(33), + centerTitle: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + )), + actions: [ + IconButton( + icon: Icon(Icons.star), + tooltip: 'like', + onPressed: () { + // do nothing + }), + CustomPopupMenuButton() + ], + bottom: TabBar( + isScrollable: true, + controller: _tabController, + indicatorColor: Colors.orangeAccent, + tabs: tabs.map((e) => Tab(text: e)).toList(), + ), + ); + + Widget _buildTableBarView() => TabBarView( + controller: _tabController, + children: tabs + .map((e) => Center( + child: Text( + e, + style: TextStyle(color: Colors.white, fontSize: 20), + ))) + .toList()); +} diff --git a/lib/views/widgets/StatefulWidget/BottomAppBar.dart b/lib/views/widgets/StatefulWidget/BottomAppBar.dart new file mode 100755 index 0000000..d34a3d8 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/BottomAppBar.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/pather.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +// { +// "widgetId": 61, +// "name": 'BottomAppBar基本用法', +// "priority": 1, +// "subtitle": +// "【elevation】 : 影深 【double】\n" +// "【shape】 : 形状 【NotchedShape】\n" +// "【notchMargin】 : 间隔距离 【double】\n" +// "【color】 : 颜色 【Color】\n" +// "【child】 : 孩子 【Widget】", +// } +class CustomBottomAppBar extends StatefulWidget { + @override + _CustomBottomAppBarState createState() => _CustomBottomAppBarState(); +} + +class _CustomBottomAppBarState extends State { + var _position = 0; + var _location = FloatingActionButtonLocation.centerDocked; + final iconsMap = { + "图鉴": Icons.home, + "动态": Icons.toys, + "喜欢": Icons.favorite, + "手册": Icons.class_, + }; + var activeColor = Colors.blue.withAlpha(240); + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: 180, + child: Scaffold( + backgroundColor: Colors.purple.withAlpha(22), + floatingActionButton: FloatingActionButton( + onPressed: () => DialogAbout.show(context), + child: Icon(Icons.add), + ), + bottomNavigationBar: _buildBottomAppBar(), + floatingActionButtonLocation: _location, + body: _buildContent(), + ), + ); + } + + Widget _buildBottomAppBar() { + return BottomAppBar( + elevation: 1, + shape: CircularNotchedRectangle(), + notchMargin: 5, + color: Colors.red, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: info.asMap().keys.map((i) => _buildChild(i)).toList() + ..insertAll(isCenter ? 2 : 4, [SizedBox(width: 30)])), + ); + } + + Container _buildContent() { + return Container( + alignment: Alignment.center, + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + '当前页索引:$_position', + style: TextStyle(color: Colors.blue, fontSize: 18), + ), + Switch( + value: isCenter, + onChanged: (v) { + setState(() { + _location = v + ? FloatingActionButtonLocation.centerDocked + : FloatingActionButtonLocation.endDocked; + }); + }), + ], + ), + ); + } + + List get info => iconsMap.keys.toList(); + + bool get isCenter => _location == FloatingActionButtonLocation.centerDocked; + + Widget _buildChild(int i) { + var active = i == _position; + return Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () => setState(() => _position = i), + child: Wrap( + direction: Axis.vertical, + alignment: WrapAlignment.center, + children: [ + Icon( + iconsMap[info[i]], + color: active ? activeColor : Colors.white, + size: 30, + ), + Text(info[i], + style: TextStyle( + color: active ? activeColor : Colors.white, fontSize: 14)), + ], + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/BottomNavigationBar.dart b/lib/views/widgets/StatefulWidget/BottomNavigationBar.dart new file mode 100755 index 0000000..cd84852 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/BottomNavigationBar.dart @@ -0,0 +1,197 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; + +// { +// "widgetId": 60, +// "name": 'BottomNavigationBar基本使用', +// "priority": 1, +// "subtitle": +// "【currentIndex】 : 当前索引 【int】\n" +// "【elevation】 : 影深 【double】\n" +// "【type】 : 类型*2 【BottomNavigationBarType】\n" +// "【fixedColor】 : type为fix的颜色 【Color】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【iconSize】 : 图标大小 【double】\n" +// "【selectedLabelStyle】 : 选中文字样式 【TextStyle】\n" +// "【unselectedLabelStyle】 : 未选中文字样式 【TextStyle】\n" +// "【showUnselectedLabels】 : 显示未选中标签 【bool】\n" +// "【showSelectedLabels】 : 显示选中标签 【bool】\n" +// "【items】 : 条目 【List】\n" +// "【onTap】 : 点击事件 【Function(int)】", +// } +class CustomBottomNavigationBar extends StatefulWidget { + @override + _CustomBottomNavigationBarState createState() => + _CustomBottomNavigationBarState(); +} + +class _CustomBottomNavigationBarState extends State { + var _position = 0; + BottomNavigationBarType _type = BottomNavigationBarType.shifting; + final iconsMap = { + //底栏图标 + "图鉴": Icons.home, "动态": Icons.toys, + "喜欢": Icons.favorite, "手册": Icons.class_, + "我的": Icons.account_circle, + }; + final _colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.purple, + ]; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + _buildOp(), + _buildBottomNavigationBar(), + ], + ); + } + + bool get isShifting => _type == BottomNavigationBarType.shifting; + + BottomNavigationBar _buildBottomNavigationBar() { + return BottomNavigationBar( + onTap: (position) => setState(() => _position = position), + currentIndex: _position, + elevation: 1, + type: _type, + fixedColor: isShifting ? Colors.white : _colors[_position], + backgroundColor: Colors.white, + iconSize: 25, + selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold), + showUnselectedLabels: false, + showSelectedLabels: true, + items: iconsMap.keys + .map((key) => BottomNavigationBarItem( + title: Text( + key, + ), + icon: Icon(iconsMap[key]), + backgroundColor: _colors[_position])) + .toList(), + ); + } + + Widget _buildOp() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + _type.toString(), + style: TextStyle(fontWeight: FontWeight.bold, color: Colors.blue), + ), + Switch( + value: _type == BottomNavigationBarType.shifting, + onChanged: (b) { + setState(() => _type = b + ? BottomNavigationBarType.shifting + : BottomNavigationBarType.fixed); + }), + ], + ); + } +} + +// { +// "widgetId": 60, +// "name": '可结合PageView进行切页', +// "priority": 2, +// "subtitle": +// "在onTap时进行使用控制器进行切页", +// } +class BottomNavigationBarWithPageView extends StatefulWidget { + @override + _BottomNavigationBarWithPageViewState createState() => + _BottomNavigationBarWithPageViewState(); +} + +class _BottomNavigationBarWithPageViewState + extends State { + var _position = 0; + final iconsMap = { + //底栏图标 + "图鉴": Icons.home, "动态": Icons.toys, + "喜欢": Icons.favorite, "手册": Icons.class_, + "我的": Icons.account_circle, + }; + final _colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.purple, + ]; + PageController _controller; //页面控制器,初始0 + + @override + void initState() { + _controller = PageController( + initialPage: _position, + ); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Container( + color: Colors.orange.withAlpha(88), + width: MediaQuery.of(context).size.width, + height: 150, + child: PageView( + controller: _controller, + children: iconsMap.keys + .map((e) => Center( + child: Text( + e, + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )) + .toList(), + ), + ), + _buildBottomNavigationBar() + ], + ), + ); + } + + BottomNavigationBar _buildBottomNavigationBar() { + return BottomNavigationBar( + onTap: (position) { + _controller.jumpToPage(position); + setState(() => _position = position); + }, + currentIndex: _position, + elevation: 1, + type: BottomNavigationBarType.shifting, + fixedColor: Colors.white, + iconSize: 25, + selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold), + showUnselectedLabels: false, + showSelectedLabels: true, + items: iconsMap.keys + .map((key) => BottomNavigationBarItem( + title: Text( + key, + ), + icon: Icon(iconsMap[key]), + backgroundColor: _colors[_position])) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/Checkbox.dart b/lib/views/widgets/StatefulWidget/Checkbox.dart new file mode 100644 index 0000000..e3517b5 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Checkbox.dart @@ -0,0 +1,77 @@ + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 39, +// "name": 'Checkbox基础用法', +// "priority": 1, +// "subtitle": +// "【value】 : 是否选中 【double】\n" +// "【checkColor】: 选中时✔️gou颜色 【Color】\n" +// "【activeColor】: 选中时框内颜色 【Color】\n" +// "【onChanged】: 状态改变事件 【Function(bool)】\n" +// } + +class CustomCheckbox extends StatefulWidget { + @override + _CustomCheckboxState createState() => _CustomCheckboxState(); +} + +class _CustomCheckboxState extends State { + bool _checked = false; + final colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: colors + .map((e) => + Checkbox( + value: _checked, + checkColor: Colors.white, + activeColor: e, + onChanged: (v) => + setState(() => _checked = v))) + .toList(), + ); + } +} + + +/// { +// "widgetId": 39, +// "name": 'Checkbox的三态', +// "priority": 2, +// "subtitle": +// "【tristate】 : 是否是三态 【double】\n" +// " onChanged时,回调true、null、false三种状态" +// } +class TristateCheckBok extends StatefulWidget { + @override + _TristateCheckBokState createState() => _TristateCheckBokState(); +} + +class _TristateCheckBokState extends State { + bool _checked = false; + final colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: colors + .map((e) => + Checkbox( + value: _checked, + tristate: true, + checkColor: Colors.white, + activeColor: e, + onChanged: (v) { + print(v); + setState(() => _checked = v); + })) + .toList(), + ); + } +} + diff --git a/lib/views/widgets/StatefulWidget/CircularProgressIndicator.dart b/lib/views/widgets/StatefulWidget/CircularProgressIndicator.dart new file mode 100644 index 0000000..8d41385 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CircularProgressIndicator.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 46, +// "name": 'CircularProgressIndicator基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 进度 【double】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【valueColor】 : 进度颜色 【Animation】\n" +// "【strokeWidth】 : 线宽 【double】", +// } +class CustomCircularProgressIndicator extends StatefulWidget { + @override + _CustomCircularProgressIndicatorState createState() => + _CustomCircularProgressIndicatorState(); +} + +class _CustomCircularProgressIndicatorState + extends State { + + var data = [0.2,0.4,0.6,0.8,null]; + + @override + Widget build(BuildContext context) { + + return Wrap( + spacing: 10, + children:data.map((e)=>Container( + width: 50, + height: 50, + child: CircularProgressIndicator( + value: e, + backgroundColor: Colors.grey.withAlpha(33), + valueColor: AlwaysStoppedAnimation(Colors.orange), + strokeWidth: 5, + ), + )).toList(), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoActivityIndicator.dart b/lib/views/widgets/StatefulWidget/CupertinoActivityIndicator.dart new file mode 100644 index 0000000..97d576b --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoActivityIndicator.dart @@ -0,0 +1,30 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +// { +// "widgetId": 48, +// "name": 'CupertinoActivityIndicator基本使用', +// "priority": 1, +// "subtitle": +// "【animating】 : 是否loading动画 【bool】\n" +// "【radius】 : 半径 【double】" +// } +class CustomCupertinoActivityIndicator extends StatelessWidget { + + @override + Widget build(BuildContext context) { + + return Wrap( + spacing: 20, + children: [ + CupertinoActivityIndicator( + animating: true, + radius: 25, + ), + CupertinoActivityIndicator( + animating: false, + radius: 25, + ) + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoApp.dart b/lib/views/widgets/StatefulWidget/CupertinoApp.dart new file mode 100644 index 0000000..7b6aa51 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoApp.dart @@ -0,0 +1,48 @@ +import 'package:flutter/cupertino.dart'; + +/// create by 张风捷特烈 on 2020-03-17 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 156, +// "name": 'CupertinoApp基本用法', +// "priority": 1, +// "subtitle": +// "【theme】 : 主题 【ThemeData】\n" +// "【title】 : 任务栏标题 【String】\n" +// "【onGenerateRoute】 : 路由生成器 【RouteFactory】\n" +// "【home】 : 主页 【Widget】", +// } +class CustomCupertinoApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 200, + child: CupertinoApp( + title: 'Flutter Demo', + theme: CupertinoThemeData( + primaryColor: CupertinoColors.white, + ), + home: CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + leading: Icon( + CupertinoIcons.reply, + color: CupertinoColors.black, + ), + trailing: Icon( + CupertinoIcons.share, + color: CupertinoColors.black, + ), + middle: Text('Flutter Unit'), + ), + backgroundColor: CupertinoColors.systemBackground, + child: Center( + child: Text('Hello, World!'), + ), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoNavigationBar.dart b/lib/views/widgets/StatefulWidget/CupertinoNavigationBar.dart new file mode 100755 index 0000000..d1e287e --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoNavigationBar.dart @@ -0,0 +1,36 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 62, +// "name": 'CupertinoNavigationBar基本用法', +// "priority": 1, +// "subtitle": +// "【leading】 : 左侧组件 【Widget】\n" +// "【middle】 : 中间组件 【Widget】\n" +// "【trailing】 : 尾部组件 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【padding】 : 内边距 【EdgeInsetsDirectional】\n" +// "【border】 : 边线 【Border】", +// } +class CustomCupertinoNavigationBar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CupertinoNavigationBar( + leading: Icon( + CupertinoIcons.back, + size: 25, + color: Colors.blue, + ), + middle: Text("风雪雅舍"), + trailing: Image.asset( + "assets/images/icon_head.png", + width: 25.0, + height: 25.0, + ), + backgroundColor: Color(0xfff1f1f1), + padding: EdgeInsetsDirectional.only(start: 10,end: 20), + border: Border.all(color: Colors.transparent), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoPageScaffold.dart b/lib/views/widgets/StatefulWidget/CupertinoPageScaffold.dart new file mode 100644 index 0000000..d757029 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoPageScaffold.dart @@ -0,0 +1,34 @@ +import 'package:flutter/cupertino.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 157, +// "name": 'CupertinoPageScaffold基本用法', +// "priority": 1, +// "subtitle": +// "【child】 : 内容 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【navigationBar】 : 头部 【ObstructingPreferredSizeWidget】", +// } +class CustomCupertinoPageScaffold extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 300, + child: CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + leading: Icon(CupertinoIcons.reply), + trailing: Icon(CupertinoIcons.share), + middle: Text('Flutter Unit'), + ), + backgroundColor: CupertinoColors.systemBackground, + child: Center( + child: Text('Hello, World!'), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/CupertinoScrollbar.dart b/lib/views/widgets/StatefulWidget/CupertinoScrollbar.dart new file mode 100644 index 0000000..bc89eed --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoScrollbar.dart @@ -0,0 +1,60 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 195, +// "name": 'CupertinoScrollbar基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【controller】 : 控制器 【ScrollController】", +// } +class CustomCupertinoScrollbar extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: CupertinoScrollbar( + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 5), + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/CupertinoSlider.dart b/lib/views/widgets/StatefulWidget/CupertinoSlider.dart new file mode 100644 index 0000000..44f2a83 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoSlider.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +// { +// "widgetId": 43, +// "name": 'CupertinoSlider基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 数值 【double】\n" +// "【min】 : 最小值 【double】\n" +// "【max】 : 最大值 【double】\n" +// "【activeColor】 : 激活颜色 【Color】\n" +// "【thumbColor】 : 圆形颜色 【Color】\n" +// "【divisions】 : 分段数 【int】\n" +// "【onChangeStart】 : 开始滑动回调 【Function(double)】\n" +// "【onChangeEnd】 : 滑动结束回调 【Function(double)】\n" +// "【onChanged】 : 改变时回调 【Function(double)】", +// } +class CustomCupertinoSlider extends StatefulWidget { + @override + _CustomCupertinoSliderState createState() => _CustomCupertinoSliderState(); +} + +class _CustomCupertinoSliderState extends State { + double _value = 0.0; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + + children: [ + Text('当前值:${_value.toStringAsFixed(1)}'), + CupertinoSlider( + value: _value, + divisions: 180, + min: 0.0, + max: 360.0, + activeColor: Colors.green, + thumbColor: Colors.white, + onChangeStart: (value) { + print('开始滑动:$value'); + }, + onChangeEnd: (value) { + print('滑动结束:$value'); + }, + onChanged: (value) { + setState(() { + _value = value; + }); + }), + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoSwitch.dart b/lib/views/widgets/StatefulWidget/CupertinoSwitch.dart new file mode 100644 index 0000000..c560b1a --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoSwitch.dart @@ -0,0 +1,37 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// { +// "widgetId": 41, +// "name": 'CupertinoSwitch基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 是否选中 【double】\n" +// "【activeColor】 : 激活态颜色 【Color】\n" +// "【onChanged】 : 切换回调 【Function(double)】", +// } +class CustomCupertinoSwitch extends StatefulWidget { + @override + _CustomCupertinoSwitchState createState() => _CustomCupertinoSwitchState(); +} + +class _CustomCupertinoSwitchState extends State { + final colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + + bool _checked = false; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: colors + .map((e) => CupertinoSwitch( + value: _checked, + activeColor: e, + onChanged: (v) { + setState(() => _checked = v); + })) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoTabBar.dart b/lib/views/widgets/StatefulWidget/CupertinoTabBar.dart new file mode 100755 index 0000000..dcb75b4 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoTabBar.dart @@ -0,0 +1,74 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 63, +// "name": 'CupertinoNavigationBar基本用法', +// "priority": 1, +// "subtitle": +// "【currentIndex】 : 当前激活索引 【Widget】\n" +// "【items】 : 条目组件 【Widget】\n" +// "【trailing】 : 尾部组件 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【inactiveColor】 : 非激活色 【Color】\n" +// "【activeColor】 : 激活色 【Color】\n" +// "【iconSize】 : 图标大小 【double】\n" +// "【border】 : 边线 【Border】\n" +// "【onTap】 : 点击事件 【Function(int)】", +// } +class CustomCupertinoTabBar extends StatefulWidget { + @override + _CustomCupertinoTabBarState createState() => _CustomCupertinoTabBarState(); +} + +class _CustomCupertinoTabBarState extends State { + var _position = 0; + final iconsMap = { + //底栏图标 + "图鉴": Icons.home, "动态": Icons.toys, + "喜欢": Icons.favorite, "手册": Icons.class_, + "我的": Icons.account_circle, + }; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildContent(context), + _buildTabBar(), + ], + ); + } + + Widget _buildTabBar() { + return CupertinoTabBar( + currentIndex: _position, + onTap: (value) => setState(() => _position = value), + items: iconsMap.keys + .map((e) => BottomNavigationBarItem( + icon: Icon( + iconsMap[e], + ), + title: Text(e), + )) + .toList(), + activeColor: Colors.blue, + inactiveColor: Color(0xff333333), + backgroundColor: Color(0xfff1f1f1), + iconSize: 25.0, + ); + } + + Widget _buildContent(BuildContext context) { + return Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width, + height: 150, + color: Color(0xffE7F3FC), + child: Text( + iconsMap.keys.toList()[_position], + style: TextStyle(color: Colors.blue, fontSize: 24), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/CupertinoTabScaffold.dart b/lib/views/widgets/StatefulWidget/CupertinoTabScaffold.dart new file mode 100644 index 0000000..1ff6ba2 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/CupertinoTabScaffold.dart @@ -0,0 +1,67 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 158, +// "name": 'CupertinoTabScaffold基本用法', +// "priority": 1, +// "subtitle": +// "【tabBar】 : 页签条 【CupertinoTabBar】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【controller】 : 控制器 【CupertinoTabController】\n" +// "【tabBuilder】 : 页面构造器 【IndexedWidgetBuilder】", +// } +class CustomCupertinoTabScaffold extends StatefulWidget { + @override + _CustomCupertinoTabScaffoldState createState() => + _CustomCupertinoTabScaffoldState(); +} + +class _CustomCupertinoTabScaffoldState + extends State { + var _position = 0; + final iconsMap = { + //底栏图标 + "图鉴": Icons.home, "动态": Icons.toys, + "喜欢": Icons.favorite, "手册": Icons.class_, + "我的": Icons.account_circle, + }; + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 300, + child: CupertinoTabScaffold( + backgroundColor: Colors.grey.withAlpha(11), + tabBar: _buildTabBar(), + tabBuilder: (_, index) => _buildContent(index)), + ); + } + + CupertinoTabBar _buildTabBar() => CupertinoTabBar( + currentIndex: _position, + onTap: (value) => setState(() => _position = value), + items: iconsMap.keys + .map((e) => BottomNavigationBarItem( + icon: Icon( + iconsMap[e], + ), + title: Text(e), + )) + .toList(), + activeColor: Colors.blue, + inactiveColor: Color(0xff333333), + backgroundColor: Color(0xfff1f1f1), + iconSize: 25.0, + ); + + _buildContent(int index) => Container( + alignment: Alignment.center, + child: Text(iconsMap.keys.toList()[index]), + ); +} diff --git a/lib/views/widgets/StatefulWidget/Dismissible.dart b/lib/views/widgets/StatefulWidget/Dismissible.dart new file mode 100644 index 0000000..7546768 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Dismissible.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: + + +// { +// "widgetId": 176, +// "name": 'Dismissible基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【background】 : 左底 【Widget】\n" +// "【secondaryBackground】 : 右底 【Widget】\n" +// "【key】 : 键 【Key】\n" +// "【confirmDismiss】 : 确认回调 【DismissDirectionCallback】\n" +// "【onDismissed】 : 消失回调 【DismissDirectionCallback】\n", +// } +class CustomDismissible extends StatefulWidget { + @override + _CustomDismissibleState createState() => _CustomDismissibleState(); +} + +class _CustomDismissibleState extends State { + var data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 5), + children: data.map((color) => _buildItem(color)).toList(), + ), + ); + } + + Widget _buildItem(Color color) { + return Dismissible( + background: Container( + color: Colors.green, + alignment: Alignment(-0.9, 0), + child: Icon( + Icons.check, + color: Colors.white, + ), + ), + secondaryBackground: Container( + alignment: Alignment(0.9, 0), + child: Icon( + Icons.close, + color: Colors.white, + ), + color: Colors.red, + ), + key: ValueKey(color), + onDismissed: (d) { + data.remove(color); + }, + confirmDismiss: (e) async { + if (e == DismissDirection.endToStart) { + return true; + } else { + return false; + } + }, + child: Container( + alignment: Alignment.center, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} +// { +// "widgetId": 176, +// "name": 'Dismissible基本使用', +// "priority": 2, +// "subtitle": +// "【direction】 : 方向 【DismissDirection】\n" +// "【crossAxisEndOffset】 : 偏移 【double】\n", +// } +class DirectionDismissible extends StatefulWidget { + @override + _CustomDirectionDismissibleState createState() => _CustomDirectionDismissibleState(); +} + +class _CustomDirectionDismissibleState extends State { + var data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView( + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 5), + children: data.map((color) => _buildItem(color)).toList(), + ), + ); + } + + Widget _buildItem(Color color) { + return Dismissible( + direction: DismissDirection.vertical, + background: Container( + color: Colors.green, + alignment: Alignment( 0,-0.9,), + child: Icon( + Icons.check, + color: Colors.white, + ), + ), + crossAxisEndOffset: 0.5, + secondaryBackground: Container( + alignment: Alignment( 0,0.9,), + child: Icon( + Icons.close, + color: Colors.white, + ), + color: Colors.red, + ), + key: ValueKey(color), + onDismissed: (d) { + data.remove(color); + }, + confirmDismiss: (e) async { + print(e); + if (e == DismissDirection.up) { + return true; + } else { + return false; + } + }, + child: Container( + alignment: Alignment.center, + width: 80, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/DragTarget.dart b/lib/views/widgets/StatefulWidget/DragTarget.dart new file mode 100644 index 0000000..715f36c --- /dev/null +++ b/lib/views/widgets/StatefulWidget/DragTarget.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 104, +// "name": 'DragTarget基本使用', +// "priority": 1, +// "subtitle": +// "【builder】 : 组件构造器 【DragTargetBuilder】\n" +// "【onWillAccept】 : 拖入时 【Function(T)】\n" +// "【onAccept】 : 拖拽成功 【Function(T)】\n" +// "【onLeave】 : 拖入再脱出 【Function(T)】", +// } + +class CustomDragTarget extends StatefulWidget { + @override + _CustomDragTargetState createState() => _CustomDragTargetState(); +} + +class _CustomDragTargetState extends State { + Color _color = Colors.grey; + String _info = 'DragTarget'; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Wrap( + children: _buildColors(), + spacing: 10, + ), + SizedBox(height: 20,), + _buildDragTarget() + ], + ), + ); + } + + List _buildColors() { + var colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.orange, + Colors.purple, + Colors.cyanAccent + ]; + return colors + .map( + (e) => Draggable( + child: Container( + width: 30, + height: 30, + alignment: Alignment.center, + child: Text( + colors.indexOf(e).toString(), + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.bold), + ), + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + ), + data: e, + feedback: Container( + width: 25, + height: 25, + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + )), + ) + .toList(); + } + + Widget _buildDragTarget() { + return DragTarget( + onLeave: (data) => setState(() => _info='onLeave'), + onAccept: (data) => setState(() { + _info='onAccept'; + _color = data; + }), + onWillAccept: (data) { + setState(() { + _info='onWillAccept'; + }); + print("onWillAccept: data = $data "); + return data != null; + }, + builder: (context, candidateData, rejectedData) => Container( + width: 150.0, + height: 50.0, + color: _color, + child: Center( + child: Text( + _info, + style: TextStyle(color: Colors.white), + ), + ))); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/Draggable.dart b/lib/views/widgets/StatefulWidget/Draggable.dart new file mode 100644 index 0000000..cf245cb --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Draggable.dart @@ -0,0 +1,230 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 103, +// "name": 'Draggable基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子 【Widget】\n" +// "【feedback】 : 拖拽时的孩子 【Widget】\n" +// "【axis】 : 拖动的轴 【Axis】", +// } +class CustomDraggable extends StatelessWidget { + @override + Widget build(BuildContext context) { + var axis = [null, Axis.vertical, Axis.horizontal]; + return Wrap( + spacing: 30, + children: axis + .map((e) => Draggable( + axis: e, + child: Container( + width: 30, + height: 30, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.blue, shape: BoxShape.circle), + ), + feedback: Container( + width: 30, + height: 30, + decoration: BoxDecoration( + color: Colors.red, shape: BoxShape.circle), + ), + )) + .toList()); + } +} + +// { +// "widgetId": 103, +// "name": 'Draggable与DragTarget联用', +// "priority": 2, +// "subtitle": +// "【data】 : 数据 【T】\n" +// "【onDragStarted】 : 开始拖拽 【Function()】\n" +// "【onDragEnd】 : 结束拖拽 【Function(DraggableDetails)】\n" +// "【onDragCompleted】 : 拖拽完成 【Function()】\n" +// "【onDraggableCanceled】 : 拖拽取消 【Function(Velocity,Offset)】\n" +// "【onChanged】 : 改变时回调 【Function(T)】", +// } + +class DraggablePage extends StatefulWidget { + @override + _DraggablePageState createState() => _DraggablePageState(); +} + +class _DraggablePageState extends State { + Color _color = Colors.grey; + String _info = 'DragTarget'; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Wrap( + children: _buildColors(), + spacing: 10, + ), + SizedBox( + height: 20, + ), + _buildDragTarget() + ], + ), + ); + } + + List _buildColors() { + var colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.orange, + Colors.purple, + Colors.cyanAccent + ]; + return colors + .map( + (e) => Draggable( + onDragStarted: () => setState(() => _info = '开始拖拽'), + onDragEnd: (d) => setState(() => _info = '结束拖拽'), + onDragCompleted: () => _info = '拖拽完成', + onDraggableCanceled: (v, o) => _info = '拖拽取消', + child: Container( + width: 30, + height: 30, + alignment: Alignment.center, + child: Text( + colors.indexOf(e).toString(), + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.bold), + ), + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + ), + data: e, + feedback: Container( + width: 25, + height: 25, + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + )), + ) + .toList(); + } + + Widget _buildDragTarget() { + return DragTarget( + onLeave: (data) => print("onLeave: data = $data "), + onAccept: (data) { + print("onAccept: data = $data "); + setState(() { + _color = data; + }); + }, + onWillAccept: (data) { + print("onWillAccept: data = $data "); + return data != null; + }, + builder: (context, candidateData, rejectedData) => Container( + width: 150.0, + height: 50.0, + color: _color, + child: Center( + child: Text( + _info, + style: TextStyle(color: Colors.white), + ), + ))); + } +} + +// { +// "widgetId": 103, +// "name": 'Draggable其他使用', +// "priority": 3, +// "subtitle": +// "可以根据拖拽来处理一些事件。如删除、查询、弹框等" +// } + +class DeleteDraggable extends StatefulWidget { + @override + _DeleteDraggableState createState() => _DeleteDraggableState(); +} + +class _DeleteDraggableState extends State { + List colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.orange, + Colors.purple, + Colors.cyanAccent + ]; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Wrap( + children: _buildColors(), + spacing: 10, + ), + SizedBox( + height: 20, + ), + _buildDragTarget() + ], + ), + ); + } + + Widget _buildDragTarget() { + return DragTarget( + onAccept: (data) { + setState(() { + colors.removeAt(data); + }); + }, + onWillAccept: (data) => data != null, + builder: (context, candidateData, rejectedData) => Container( + width: 50.0, + height: 50.0, + decoration: + BoxDecoration(color: Colors.red, shape: BoxShape.circle), + child: Center( + child: Icon(Icons.delete_sweep, color: Colors.white), + ))); + } + + List _buildColors() => colors + .map( + (e) => Draggable( + child: Container( + width: 30, + height: 30, + alignment: Alignment.center, + child: Text( + colors.indexOf(e).toString(), + style: + TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + ), + data: colors.indexOf(e), + feedback: Container( + width: 25, + height: 25, + decoration: BoxDecoration( + color: e.withAlpha(100), shape: BoxShape.circle), + )), + ) + .toList(); +} diff --git a/lib/views/widgets/StatefulWidget/DropdownButton.dart b/lib/views/widgets/StatefulWidget/DropdownButton.dart new file mode 100644 index 0000000..f15c054 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/DropdownButton.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-16 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 55, +// "name": 'DropdownButton基本语法', +// "priority": 1, +// "subtitle": +// "【value】 : 当前值 【T】\n" +// "【items】 : 下拉选框 【List>】\n" +// "【icon】 : 图标 【Widget】\n" +// "【elevation】 : 影深 【double】\n" +// "【onChanged】 : 选择条目事件 【Function(T)】\n" +// "【backgroundColor】 : 背景色 【Color】", +// } +class CustomDropDownButton extends StatefulWidget { + @override + _CustomDropDownButtonState createState() => _CustomDropDownButtonState(); +} + +class _CustomDropDownButtonState extends State { + Color _color = Colors.red; + final _colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + final _info = ["红色", "黄色", "蓝色", "绿色"]; + + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + margin: EdgeInsets.symmetric(horizontal: 20), + width: 50, + height: 50, + color: _color, + ), + DropdownButton( + value: _color, + elevation: 1, + icon: Icon( + Icons.expand_more, + size: 20, + color: _color, + ), + items: _buildItems(), + onChanged: (v) => setState(() => _color = v)), + ], + ); + } + + List> _buildItems() => _colors + .map((e) => DropdownMenuItem( + value: e, + child: Text( + _info[_colors.indexOf(e)], + style: TextStyle(color: e), + ))) + .toList(); +} + +// { +// "widgetId": 55, +// "name": 'DropdownButton基本语法', +// "priority": 2, +// "subtitle": +// "【isDense】 : 是否紧排 【bool】\n" +// "【iconSize】 : 图标大小 【double】\n" +// "【hint】 : 提示组件 【Widget】\n" +// "【iconEnabledColor】 : 图标颜色 【Color】", +// } +class StyleDropDownButton extends StatefulWidget { + @override + _StyleDropDownButtonState createState() => _StyleDropDownButtonState(); +} + +class _StyleDropDownButtonState extends State { + Color _color = Colors.red ; + final _colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + final _info = ["红色", "黄色", "蓝色", "绿色"]; + + @override + Widget build(BuildContext context) { + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Container( + margin: EdgeInsets.symmetric(horizontal: 20), + width: 50, + height: 50, + color: _color??Colors.transparent, + ), + DropdownButton( + hint: Text('请选择'), + isDense: true, + iconSize:20, + iconEnabledColor:_color??Colors.orange, + value: _color, + items: _buildItems(), + onChanged: (v) => setState(() => _color = v)), + ], + ); + } + + List> _buildItems() => _colors + .map((e) => DropdownMenuItem( + value: e, + child: Text( + _info[_colors.indexOf(e)], + style: TextStyle(color: e), + ))) + .toList(); +} diff --git a/lib/views/widgets/StatefulWidget/ExpandIcon.dart b/lib/views/widgets/StatefulWidget/ExpandIcon.dart new file mode 100644 index 0000000..e9ddaff --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ExpandIcon.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 51, +// "name": 'ExpandIcon基本使用', +// "priority": 1, +// "subtitle": +// "【isExpanded】 : 是否展开 【bool】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】\n", +// "【size】 : 图标大小 【double】\n" +// "【color】 : 不展开时颜色 【Color】\n" +// "【expandedColor】 : 展开时颜色 【Color】\n" +// "【onPressed】 : 点击事件 【Function(bool)】", +// } +class CustomExpandIcon extends StatefulWidget { + @override + _CustomExpandIconState createState() => _CustomExpandIconState(); +} + +class _CustomExpandIconState extends State { + var _closed = true; + + @override + Widget build(BuildContext context) { + return ExpandIcon( + isExpanded: _closed, + padding: EdgeInsets.all(5), + size: 30, + color: Colors.blue, + expandedColor: Colors.orangeAccent, + onPressed: (value) => setState(() => _closed = !_closed), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/ExpansionPanelList.dart b/lib/views/widgets/StatefulWidget/ExpansionPanelList.dart new file mode 100644 index 0000000..4ca2194 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ExpansionPanelList.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 178, +// "name": 'ExpansionPanelList基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【animationDuration】 : 动画时长 【Duration】\n" +// "【expansionCallback】 : 展开回调 【List】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class CustomExpansionPanelList extends StatefulWidget { + @override + _CustomExpansionPanelListState createState() => + _CustomExpansionPanelListState(); +} + +class _CustomExpansionPanelListState extends State { + var data = [ + Colors.red[50], + Colors.red[100], + Colors.red[200], + Colors.red[300], + Colors.red[400], + Colors.red[500], + Colors.red[600], + Colors.red[700], + Colors.red[800], + Colors.red[900], + ]; + int _position = 0; + + @override + Widget build(BuildContext context) { + return Container( + width: 300, + child: ExpansionPanelList( + children: data.map((color) => _buildItem(color)).toList(), + animationDuration: Duration(milliseconds: 200), + expansionCallback: (index, open) { + setState(() => _position=open?-1:index); + }, + ), + ); + } + + ExpansionPanel _buildItem(Color color) { + return ExpansionPanel( + isExpanded: data.indexOf(color) == _position, + canTapOnHeader: true, + headerBuilder: (ctx, index) => Center( + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Container( + height: 30, + width: 30, + decoration: + BoxDecoration(color: color, shape: BoxShape.circle), + ), + Container( + width: 120, + alignment: Alignment.center, + height: 50, + child: Text( + colorString(color), + style: TextStyle(color: Colors.black), + ), + ), + ], + ), + ), + body: Container( + alignment: Alignment.center, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + )); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/StatefulWidget/ExpansionTile.dart b/lib/views/widgets/StatefulWidget/ExpansionTile.dart new file mode 100644 index 0000000..5cf17c9 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ExpansionTile.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/widgets/StatelessWidget/RadioListTile.dart'; +// { +// "widgetId": 52, +// "name": 'ExpansionTile基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 展开内容 【List】\n" +// "【leading】 : 头左组件 【Widget】\n" +// "【title】 : 头中组件 【Widget】\n" +// "【trailing】 : 头尾组件 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【onExpansionChanged】 : 折叠事件 【Function(bool)】\n" +// "【initiallyExpanded】 : 是否初始时展开 【bool】", +// } +class CustomExpansionTile extends StatefulWidget { + @override + _CustomExpansionTileState createState() => _CustomExpansionTileState(); +} + +class _CustomExpansionTileState extends State { + + @override + Widget build(BuildContext context) { + + return ExpansionTile( + leading: Icon(Icons.star), + title: Text("选择语言"), + backgroundColor: Colors.grey.withAlpha(6), + onExpansionChanged: (value){ + print('$value'); + }, + initiallyExpanded: false, + children: [ + CustomRadioListTile() + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/Form.dart b/lib/views/widgets/StatefulWidget/Form.dart new file mode 100644 index 0000000..4a1cfbc --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Form.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 198, +// "name": 'Form基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onChanged】 : 表单变化回调 【VoidCallback】\n" +// "【onWillPop】 : 返回回调 【WillPopCallback】", +// } +class CustomForm extends StatefulWidget { + @override + _CustomFormState createState() => _CustomFormState(); +} + +class _CustomFormState extends State { + GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Container( + child: Form( + onWillPop: () => _willPop(context), + key: _formKey, + onChanged: () { + print('Form---onChanged'); + }, + child: + Stack( + alignment: Alignment.centerRight, + children: [ + Container( + width: 350, + child: UnconstrainedBox( + child: Container( + width: 200, + height: 70, + child: TextFormField( + style: TextStyle(textBaseline: TextBaseline.alphabetic), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'username', + ), + validator: _validateUsername, + ), + ), + ), + ), + Positioned( + top: 0, right: 0, child: _buildSubmitButton(context)), + ], + ), + ), + ); + } + + String _validateUsername(value) { + if (value.isEmpty) { + return '用户名不能为空'; + } + return null; + } + + RaisedButton _buildSubmitButton(BuildContext context) { + return RaisedButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: _onSubmit, + child: Icon( + Icons.check, + color: Colors.white, + ), + ); + } + + _onSubmit(){ + if (_formKey.currentState.validate()) { + FocusScope.of(context).requestFocus(FocusNode()); + Navigator.of(context).pop(); + } + } + + Future _willPop(context) async { + return await showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + title: Text('提示'), + content: Text('你确定要离开此页吗?'), + actions: [ + FlatButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text('确定'), + ), + FlatButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text('取消'), + ), + ], + ), + ) ?? + false; + } +} diff --git a/lib/views/widgets/StatefulWidget/FutureBuilder.dart b/lib/views/widgets/StatefulWidget/FutureBuilder.dart new file mode 100644 index 0000000..fc8c5f6 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/FutureBuilder.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 172, +// "name": 'FutureBuilder基本使用', +// "priority": 1, +// "subtitle": +// "【builder】 : 子组件 【AsyncWidgetBuilder】\n" +// "【initialData】 : 初始数据 【T】\n" +// "【future】 : 异步任务 【Future】", +// } +class CustomFutureBuilder extends StatefulWidget { + @override + _CustomFutureBuilderState createState() => _CustomFutureBuilderState(); +} + +class _CustomFutureBuilderState extends State { + Future _future; + + @override + void initState() { + _future = loadData(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: FutureBuilder( + initialData: 'Load', + future: _future, + builder: (ctx, snap) { + if (snap.connectionState == ConnectionState.done) { + return Text(snap.data); + } + if (snap.connectionState == ConnectionState.waiting) { + return CircularProgressIndicator(); + } + if (snap.hasError) { + return Text('Error'); + } + return Container(); + }), + ); + } + + Future loadData() async { + await Future.delayed(Duration(seconds: 2)); + return 'LoadeSuccess'; + } +} diff --git a/lib/views/widgets/StatefulWidget/Hero.dart b/lib/views/widgets/StatefulWidget/Hero.dart new file mode 100644 index 0000000..8eb0364 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Hero.dart @@ -0,0 +1,122 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": tag, +// "name": 'Hero基本使用', +// "priority": 1, +// "subtitle": +// "【tag】 : 标签 【String】\n", +// } +class CustomHero extends StatelessWidget { + @override + Widget build(BuildContext context) { + var hero = Hero( + //----定义一个Hero,并添加tag标签,此中组件共享 + tag: 'user-head', + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(30)), + child: Image.asset( + "assets/images/icon_head.png", + width: 60, + height: 60, + fit: BoxFit.cover, + ), + ), + ); + + var container = Container( + alignment: Alignment(-0.8, -0.8), + child: hero, + width: 250, + height: 250 * 0.618, + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Colors.red.withAlpha(99), + Colors.yellow.withAlpha(189), + Colors.green.withAlpha(88), + Colors.blue.withAlpha(230) + ])), + ); + + return GestureDetector( + child: Card(elevation: 5, child: container), + onTap: () => Navigator.push( + context, + Bottom2TopRouter(child: TargetPage(), duration_ms: 1000), + ), + ); + } + +} + +class TargetPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var hero = Hero( + //----定义一个Hero,为其添加标签,两个标签相同,则可以共享 + tag: 'user-head', + child: Padding( + padding: EdgeInsets.all(6.0), + child: CircleAvatar( + backgroundColor: Colors.transparent, + backgroundImage: AssetImage( + "assets/images/icon_head.png", + ), + ), + ), + ); + + var touch = InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: hero, + ); + + return Scaffold( + appBar: AppBar( + actions: [touch], + ), + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Colors.red.withAlpha(99), + Colors.yellow.withAlpha(189), + Colors.green.withAlpha(88), + Colors.blue.withAlpha(230) + ])), + ), + ); + } +} + +//下--->上 +class Bottom2TopRouter extends PageRouteBuilder { + final Widget child; + final int duration_ms; + final Curve curve; + + Bottom2TopRouter( + {this.child, this.duration_ms = 500, this.curve = Curves.fastOutSlowIn}) + : super( + transitionDuration: Duration(milliseconds: duration_ms), + pageBuilder: (ctx, a1, a2) { + return child; + }, + transitionsBuilder: ( + ctx, + a1, + a2, + Widget child, + ) => SlideTransition( + position: Tween( + begin: Offset(0.0, 1.0), + end: Offset(0.0, 0.0), + ).animate(CurvedAnimation(parent: a1, curve: curve)), + child: child)); +} diff --git a/lib/views/widgets/StatefulWidget/Image.dart b/lib/views/widgets/StatefulWidget/Image.dart new file mode 100644 index 0000000..cd08c70 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Image.dart @@ -0,0 +1,231 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +// { +// "widgetId": 38, +// "name": '可从资源文件和网络加载图片', +// "priority": 1, +// "subtitle": +// "Image.asset加载资源图片,指定路径;\n" +// "Image.network加载资源网络图片,指定链接。\n" +// "Image.file加载资源文件图片,指定路径。\n" +// "Image.memory加载内存图片,指定字节数组。\n" +// "【height】 : 宽 【double】\n" +// "【width】: 高 【double】" +// } + +class LoadImage extends StatelessWidget { + final assetsImagePath = "assets/images/icon_head.png"; + final assetsGif = "assets/images/pica.gif"; + final netImageUrl = "https://user-gold-cdn.xitu.io" + "/2019/7/24/16c225e78234ec26?" + "imageView2/1/w/1304/h/734/q/85/format/webp/interlace/1"; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: [ + _loadFromAssets(), + _loadFromNet(), + ], + ); + } + + Widget _loadFromAssets() => Wrap( + spacing: 10, + children: [ + Image.asset(assetsImagePath, height: 80, width: 80), + Image.asset(assetsGif, height: 80, width: 80), + ], + ); + + Widget _loadFromNet() => Image.network(netImageUrl, height: 80); +} + +// { +// "widgetId": 38, +// "name": '图片的适应模式', +// "priority": 2, +// "subtitle": +// "【fit】 : 适应模式*7 【BoxFit】\n" +// }, + +class FitImage extends StatefulWidget { + @override + _FitImageState createState() => _FitImageState(); +} + +class _FitImageState extends State { + bool _smallImage = false; + + @override + Widget build(BuildContext context) { + var imageLi = BoxFit.values + .toList() + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 100, + height: 80, + color: Colors.grey.withAlpha(88), + child: Image( + image: AssetImage(!_smallImage + ? "assets/images/wy_300x200.jpg" + : "assets/images/wy_30x20.jpg"), + fit: mode)), + Text(mode.toString().split(".")[1]) + ])) + .toList(); + + return Wrap( + children: [...imageLi, _buildSwitch()], + ); + } + + Widget _buildSwitch() { + return Container( + alignment: Alignment.center, + width: 200, + height: 100, + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text("使用小图"), + Switch( + value: _smallImage, + onChanged: (b) => setState(() => _smallImage = b)), + ], + ), + ); + } +} + +// { +// "widgetId": 38, +// "name": '图片对齐模式', +// "priority": 3, +// "subtitle": +// "【alignment】 : 颜色 【AlignmentGeometry】\n" +// " 常用Alignment类的九个静态常量,但也可定制位置" +// }, + +class AlignmentImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var alignment = [ + Alignment.center, + Alignment.centerLeft, + Alignment.centerRight, + Alignment.topCenter, + Alignment.topLeft, + Alignment.topRight, + Alignment.bottomCenter, + Alignment.bottomLeft, + Alignment.bottomRight + ]; //测试数组 + var imgLi = alignment + .map((alignment) => //生成子Widget列表 + Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 90, + height: 60, + color: Colors.grey.withAlpha(88), + child: Image( + image: AssetImage("assets/images/wy_30x20.jpg"), + alignment: alignment, + )), + Text(alignment.toString()) + ])) + .toList(); + var imageAlignment = Wrap(children: imgLi); + return imageAlignment; + } +} + +// { +// "widgetId": 38, +// "name": '图片颜色及混合模式', +// "priority": 4, +// "subtitle": +// "【color】 : 颜色 【Color】\n" +// "【colorBlendMode】: 混合模式*29 【BlendMode】" +// }, + +class BlendModeImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: BlendMode.values + .toList() + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 60, + height: 60, + color: Colors.red, + child: Image( + image: AssetImage("assets/images/icon_head.png"), + color: Colors.blue.withAlpha(88), + colorBlendMode: mode)), + Text(mode.toString().split(".")[1]) + ])) + .toList(), + ); + } +} + +// { +// "widgetId": 38, +// "name": '图片重复模式', +// "priority": 5, +// "subtitle": +// "【repeat】 : 重复模式*4 【ImageRepeat】" +// }, + +class RepeatImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: ImageRepeat.values + .toList() + .map((mode) => Column(children: [ + Container( + margin: EdgeInsets.all(5), + width: 150, + height: 60, + color: Colors.red, + child: Image( + image: AssetImage("assets/images/wy_30x20.jpg"), + repeat: mode)), + Text(mode.toString().split(".")[1]) + ])) + .toList(), + ); + } +} + +// { +// "widgetId": 38, +// "name": '图片实现局部放大', +// "priority": 6, +// "subtitle": +// "【centerSlice】 : 保留的区域 【Rect】" +// }, + +class CenterSliceImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: 300, + height: 80, + child: Image.asset( + "assets/images/right_chat.png", + centerSlice: Rect.fromLTRB(9, 27, 60, 27 + 1.0), + fit: BoxFit.fill, + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedAlign.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedAlign.dart new file mode 100644 index 0000000..e448143 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedAlign.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 120, +// "name": 'AnimatedAlign基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class CustomAnimatedAlign extends StatefulWidget { + @override + _CustomAnimatedAlignState createState() => _CustomAnimatedAlignState(); +} + +class _CustomAnimatedAlignState extends State { + final Alignment start = Alignment(0, 0); + final Alignment end = Alignment.bottomRight; + + Alignment _alignment; + + @override + void initState() { + _alignment = start; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + child: AnimatedAlign( + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + alignment: _alignment, + onEnd: () => print('End'), + child: Container( + height: 40, + width: 80, + alignment: Alignment.center, + color: Colors.blue, + child: Text( + '张风捷特烈', + style: TextStyle(color: Colors.white), + ), + ), + ), + ), + ], + ); + } + + Widget _buildSwitch() => Switch( + value: _alignment == end, + onChanged: (v) { + setState(() { + _alignment = v ? end : start; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedContainer.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedContainer.dart new file mode 100644 index 0000000..ca9e749 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedContainer.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 123, +// "name": 'AnimatedContainer基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【color】 : 颜色 【Color】\n" +// "【width】 : 宽 【double】\n" +// "【height】 : 高 【double】\n" +// "【alignment】 : 对齐 【AlignmentGeometry】\n" +// "【decoration】 : 装饰 【Decoration】\n" +// "【constraints】 : 约束 【BoxConstraints】\n" +// "【transform】 : 变化 【Matrix4】\n" +// "【margin】 : 外边距 【EdgeInsetsGeometry】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class CustomAnimatedContainer extends StatefulWidget { + @override + _CustomAnimatedContainerState createState() => + _CustomAnimatedContainerState(); +} + +class _CustomAnimatedContainerState extends State { + final Decoration startDecoration = BoxDecoration( + color: Colors.blue, + image: DecorationImage( + image: AssetImage('assets/images/wy_200x300.jpg'), fit: BoxFit.cover), + borderRadius: BorderRadius.all(Radius.circular(20))); + final Decoration endDecoration = BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/wy_200x300.jpg'), fit: BoxFit.cover), + color: Colors.orange, + borderRadius: BorderRadius.all(Radius.circular(50))); + + final Alignment startAlignment = Alignment(0, 0); + final Alignment endAlignment = Alignment.topLeft + Alignment(0.2, 0.2); + + final startHeight = 100.0; + final endHeight = 50.0; + + Decoration _decoration; + double _height; + Alignment _alignment; + + @override + void initState() { + _decoration = startDecoration; + _height = startHeight; + _alignment=startAlignment; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + AnimatedContainer( + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + alignment: _alignment, + color: Colors.grey.withAlpha(22), + width: 200, + height: 120, + child: UnconstrainedBox( + child: AnimatedContainer( + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + decoration: _decoration, + onEnd: () => print('End'), + height: _height, + width: _height, + ), + ), + ), + ], + ); + } + + Widget _buildSwitch() => Switch( + value: _height == endHeight, + onChanged: (v) { + setState(() { + _height = v ? endHeight : startHeight; + _decoration = v ? endDecoration : startDecoration; + _alignment = v ? endAlignment : startAlignment; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedDefaultTextStyle.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedDefaultTextStyle.dart new file mode 100644 index 0000000..0b6f30a --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedDefaultTextStyle.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 124, +// "name": 'AnimatedDefaultTextStyle基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【textAlign】 : 文字对齐方式 【TextAlign】\n" +// "【softWrap】 : 是否包裹 【bool】\n" +// "【maxLines】 : 最大行数 【int】\n" +// "【overflow】 : 溢出模式 【TextOverflow】\n" +// "【style】 : 文字样式 【TextStyle】", +// } +class CustomAnimatedDefaultTextStyle extends StatefulWidget { + @override + _CustomAnimatedDefaultTextStyleState createState() => + _CustomAnimatedDefaultTextStyleState(); +} + +class _CustomAnimatedDefaultTextStyleState + extends State { + final TextStyle start = TextStyle(color: Colors.blue, fontSize: 50, shadows: [ + Shadow(offset: Offset(1, 1), color: Colors.black, blurRadius: 3) + ]); + final TextStyle end = TextStyle(color: Colors.white, fontSize: 20, shadows: [ + Shadow(offset: Offset(1, 1), color: Colors.purple, blurRadius: 3) + ]); + + TextStyle _style; + + @override + void initState() { + _style = start; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + alignment: Alignment.center, + color: Colors.grey.withAlpha(22), + width: 300, + height: 100, + child: AnimatedDefaultTextStyle( + textAlign: TextAlign.start, + softWrap: true, + maxLines: 1, + overflow: TextOverflow.ellipsis, + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + style: _style, + onEnd: () => print('End'), + child: Text( + '张风捷特烈', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ); + } + + Widget _buildSwitch() => Switch( + value: _style == end, + onChanged: (v) { + setState(() { + _style = v ? end : start; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedOpacity.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedOpacity.dart new file mode 100644 index 0000000..04510c9 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedOpacity.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 118, +// "name": 'AnimatedOpacity基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【opacity】 : 透明度 【double】", +// } +class CustomAnimatedOpacity extends StatefulWidget { + @override + _CustomAnimatedOpacityState createState() => _CustomAnimatedOpacityState(); +} + +class _CustomAnimatedOpacityState extends State { + double _opacity = 1.0; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Switch( + value: _opacity == 0, + onChanged: (v) { + setState(() { + _opacity = v ? 0 : 1.0; + }); + }), + Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + child: AnimatedOpacity( + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + opacity: _opacity, + onEnd: () => print('End'), + child: Icon(Icons.android, color: Colors.green, size: 60), + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPadding.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPadding.dart new file mode 100644 index 0000000..f2eb951 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPadding.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 119, +// "name": 'AnimatedPadding基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class CustomAnimatedPadding extends StatefulWidget { + @override + _CustomAnimatedPaddingState createState() => _CustomAnimatedPaddingState(); +} + +class _CustomAnimatedPaddingState extends State { + final EdgeInsets startPadding = EdgeInsets.all(10); + final EdgeInsets endPadding = EdgeInsets.all(30); + + EdgeInsets _padding; + + @override + void initState() { + _padding = startPadding; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Switch( + value: _padding == endPadding, + onChanged: (v) { + setState(() { + _padding = v ? endPadding : startPadding; + }); + }), + Container( + color: Colors.grey.withAlpha(22), + width: 200, + height: 100, + child: AnimatedPadding( + duration: Duration(seconds: 1), + curve: Curves.fastOutSlowIn, + padding: _padding, + onEnd: () => print('End'), + child: Container( + alignment: Alignment.center, + color: Colors.blue, + child: Text( + '张风捷特烈', + style: TextStyle(color: Colors.white), + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositioned.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositioned.dart new file mode 100644 index 0000000..b10146c --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositioned.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 121, +// "name": 'AnimatedPositioned基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【top】 : 到父顶距离 【double】\n" +// "【right】 : 到父右距离 【double】\n" +// "【left】 : 到父左距离 【double】\n" +// "【bottom】 : 到父底距离 【double】", +// } +class CustomAnimatedPositioned extends StatefulWidget { + @override + _CustomAnimatedPositionedState createState() => + _CustomAnimatedPositionedState(); +} + +class _CustomAnimatedPositionedState extends State { + final startTop = 0.0; + final endTop = 30.0; + + var _top = 0.0; + + @override + void initState() { + _top = startTop; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + color: Colors.grey.withAlpha(33), + width: 200, + height: 100, + child: Stack( + children: _buildChildren(), + ), + ), + ], + ); + } + + List _buildChildren() => [ + AnimatedPositioned( + duration: Duration(seconds: 1), + top: _top, + left: _top * 4, + child: Icon( + Icons.android, + color: Colors.green, + size: 50, + ), + ), + AnimatedPositioned( + duration: Duration(seconds: 1), + top: 50 - _top, + left: 150 - _top * 4, + child: Icon( + Icons.android, + color: Colors.red, + size: 50, + ), + ) + ]; + + Widget _buildSwitch() => Switch( + value: _top == endTop, + onChanged: (v) { + setState(() { + _top = v ? endTop : startTop; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositionedDirectional.dart b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositionedDirectional.dart new file mode 100644 index 0000000..2622b28 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ImplicitlyAnimatedWidget/AnimatedPositionedDirectional.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-23 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 122, +// "name": 'AnimatedPositionedDirectional基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子组件 【Widget】\n" +// "【duration】 : 动画时长 【Duration】\n" +// "【onEnd】 : 动画结束回调 【Function()】\n" +// "【curve】 : 动画曲线 【Duration】\n" +// "【top】 : 到父顶距离 【double】\n" +// "【end】 : 到父右距离 【double】\n" +// "【start】 : 到父左距离 【double】\n" +// "【bottom】 : 到父底距离 【double】", +// } +class CustomAnimatedPositionedDirectional extends StatefulWidget { + @override + _CustomAnimatedPositionedDirectionalState createState() => + _CustomAnimatedPositionedDirectionalState(); +} + +class _CustomAnimatedPositionedDirectionalState + extends State { + final startTop = 0.0; + final endTop = 30.0; + + var _top = 0.0; + + @override + void initState() { + _top = startTop; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSwitch(), + Container( + color: Colors.grey.withAlpha(33), + width: 200, + height: 100, + child: Stack( + children: _buildChildren(), + ), + ), + ], + ); + } + + List _buildChildren() => [ + AnimatedPositionedDirectional( + duration: Duration(seconds: 1), + top: _top, + start: _top * 4, + child: Icon( + Icons.android, + color: Colors.green, + size: 50, + ), + ), + AnimatedPositionedDirectional( + duration: Duration(seconds: 1), + top: 50 - _top, + start: 150 - _top * 4, + child: Icon( + Icons.android, + color: Colors.red, + size: 50, + ), + ) + ]; + + Widget _buildSwitch() => Switch( + value: _top == endTop, + onChanged: (v) { + setState(() { + _top = v ? endTop : startTop; + }); + }); +} diff --git a/lib/views/widgets/StatefulWidget/Ink.dart b/lib/views/widgets/StatefulWidget/Ink.dart new file mode 100644 index 0000000..1a256c4 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Ink.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 152, +// "name": 'Ink基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】\n" +// "【decoration】 : 装饰 【Decoration】\n" +// "【width】 : 宽 【double】\n" +// "【height】 : 高 【double】\n" +// "【color】 : 颜色 【Color】", +// } +class CustomInk extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Material( + color: Colors.orangeAccent, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Ink( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.yellow, + borderRadius: BorderRadius.all(Radius.circular(20)) + ), + + width: 200.0, + height: 100.0, + child: InkWell( + onTap: () { + }, + child: Center( + child: Text('Hello'), + )), + ), + ), + ), + ); + } +} + +// { +// "widgetId": 152, +// "name": 'Ink.image图片水波纹', +// "priority": 2, +// "subtitle": +// " 其中属性与Image组件一致,详见Image组件" +// } + +class InkImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Material( + color: Colors.grey[800], + child: Center( + child: Ink.image( + image: AssetImage('assets/images/sabar.jpg'), + fit: BoxFit.cover, + width: 300.0, + height: 200.0, + child: InkWell( + onTap: () {}, + child: Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Text('Chaos', + style: TextStyle( + fontWeight: FontWeight.w900, color: Colors.black)), + ), + )), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/InkResponse.dart b/lib/views/widgets/StatefulWidget/InkResponse.dart new file mode 100644 index 0000000..f87bb9d --- /dev/null +++ b/lib/views/widgets/StatefulWidget/InkResponse.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 149, +// "name": 'InkResponse基本事件', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onTap】 : 点击事件 【Function()】\n" +// "【onDoubleTap】 : 双击事件 【Function()】\n" +// "【onTapCancel】 : 点击取消 【Function()】\n" +// "【onLongPress】 : 长按事件 【Function()】", +// } + +class CustomInkResponse extends StatefulWidget { + @override + _CustomInkResponseState createState() => _CustomInkResponseState(); +} + +class _CustomInkResponseState extends State { + var _info = 'Push'; + + @override + Widget build(BuildContext context) { + return InkResponse( + onTap: () => setState(() => _info = 'onTap'), + onDoubleTap: () => setState(() => _info = 'onDoubleTap'), + onLongPress: () => setState(() => _info = 'onLongPress'), + onTapCancel: () => setState(() => _info = 'onTapCancel'), + child: Container( + alignment: Alignment.center, + width: 200, + height: 100, + child: Text(_info), + ), + ); + } +} + +// { +// "widgetId": 149, +// "name": 'InkResponse其他属性', +// "priority": 2, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onHighlightChanged】 : 高亮变化回调 【Function(bool)】\n" +// "【highlightColor】 : 高亮色 【Color】\n" +// "【splashColor】 : 水波纹色 【Color】\n" +// "【radius】 : 水波半径 【double】", +// } + +class ColorInkResponse extends StatefulWidget { + @override + _ColorInkResponseState createState() => _ColorInkResponseState(); +} + +class _ColorInkResponseState extends State { + var _info = 'Push'; + + @override + Widget build(BuildContext context) { + return InkResponse( + onTap: () => {}, + splashColor: Colors.blueAccent, + highlightColor: Colors.orange, + onHighlightChanged: (v) => + setState(() => _info = 'onHighlightChanged:$v'), + radius: 50, + child: Container( + alignment: Alignment.center, + width: 200, + height: 100, + child: Text(_info), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/InkWell.dart b/lib/views/widgets/StatefulWidget/InkWell.dart new file mode 100644 index 0000000..f4f9136 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/InkWell.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 150, +// "name": 'InkWell基本事件', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onTap】 : 点击事件 【Function()】\n" +// "【onDoubleTap】 : 双击事件 【Function()】\n" +// "【onTapCancel】 : 点击取消 【Function()】\n" +// "【onLongPress】 : 长按事件 【Function()】", +// } + +class CustomInkWell extends StatefulWidget { + @override + _CustomInkWellState createState() => _CustomInkWellState(); +} + +class _CustomInkWellState extends State { + var _info = 'Push'; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => setState(() => _info = 'onTap'), + onDoubleTap: () => setState(() => _info = 'onDoubleTap'), + onLongPress: () => setState(() => _info = 'onLongPress'), + onTapCancel: () => setState(() => _info = 'onTapCancel'), + child: Container( + alignment: Alignment.center, + width: 120, + height: 50, + child: Text(_info), + ), + ); + } +} + +// { +// "widgetId": 150, +// "name": 'InkWell其他属性', +// "priority": 2, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onHighlightChanged】 : 高亮变化回调 【Function(bool)】\n" +// "【highlightColor】 : 高亮色 【Color】\n" +// "【splashColor】 : 水波纹色 【Color】\n" +// "【radius】 : 水波半径 【double】", +// } + +class ColorInkWell extends StatefulWidget { + @override + _ColorInkWellState createState() => _ColorInkWellState(); +} + +class _ColorInkWellState extends State { + var _info = 'Push'; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => {}, + splashColor: Colors.blueAccent, + highlightColor: Colors.orange, + onHighlightChanged: (v) => + setState(() => _info = 'onHighlightChanged:$v'), + radius: 50, + child: Container( + alignment: Alignment.center, + width: 180, + height: 50, + child: Text(_info), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/LicensePage.dart b/lib/views/widgets/StatefulWidget/LicensePage.dart new file mode 100644 index 0000000..f031c90 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/LicensePage.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 145, +// "name": 'LicensePage基本使用', +// "priority": 1, +// "subtitle": +// "【applicationIcon】 : 左上图标 【Widget】\n" +// "【applicationVersion】 : 版本号 【String】\n" +// "【applicationName】 : 应用名 【String】\n" +// "【applicationLegalese】 : 应用律术 【String】", +// } +class CustomLicensePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: 400, + child: LicensePage( + applicationIcon: FlutterLogo(), + applicationVersion: 'v0.0.1', + applicationName: 'Flutter Unit', + applicationLegalese: 'Copyright© 2018-2020 张风捷特烈', + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/LinearProgressIndicator.dart b/lib/views/widgets/StatefulWidget/LinearProgressIndicator.dart new file mode 100644 index 0000000..6bc56f1 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/LinearProgressIndicator.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 47, +// "name": 'LinearProgressIndicator基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 进度 【double】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【valueColor】 : 进度颜色 【Animation】\n" +// " value为null时会不停循环", +// } +class CustomLinearProgressIndicator extends StatefulWidget { + @override + _CustomLinearProgressIndicatorState createState() => + _CustomLinearProgressIndicatorState(); +} + +class _CustomLinearProgressIndicatorState + extends State { + var data = [0.2, 0.4, 0.6, 0.8, null]; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: data + .map((e) => Container( + width: 50, + height: 3, + child:LinearProgressIndicator( + value: e, + backgroundColor: Colors.grey.withAlpha(33), + valueColor: AlwaysStoppedAnimation(Colors.orange), + ), + )) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/ListWheelScrollView.dart b/lib/views/widgets/StatefulWidget/ListWheelScrollView.dart new file mode 100644 index 0000000..3e4e274 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ListWheelScrollView.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 179, +// "name": 'ListWheelScrollView基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【perspective】 : 透视度 【double】\n" +// "【itemExtent】 : item高 【EdgeInsets】\n" +// "【onSelectedItemChanged】 : 选中回调 【ValueChanged 】", +// } +class CustomListWheelScrollView extends StatefulWidget { + @override + _CustomListWheelScrollViewState createState() => _CustomListWheelScrollViewState(); +} + +class _CustomListWheelScrollViewState extends State { + var data = [ + Colors.orange[50], + Colors.orange[100], + Colors.orange[200], + Colors.orange[300], + Colors.orange[400], + Colors.orange[500], + Colors.orange[600], + Colors.orange[700], + Colors.orange[800], + Colors.orange[900], + ]; + + Color _color = Colors.blue; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildCircle(), + Container( + height: 150, + width: 300, + child: ListWheelScrollView( + perspective: 0.006, + itemExtent: 50, + onSelectedItemChanged: (index){ + print('onSelectedItemChanged:$index'); + setState(() => _color=data[index]); + }, + children: data.map((color) => _buildItem(color)).toList(), + ), + ), + ], + ); + } + + Widget _buildCircle() => Container( + margin: EdgeInsets.only(bottom: 5), + width: 30, + height: 30, + decoration: BoxDecoration( + color: _color, + shape: BoxShape.circle + ), + ); + + Widget _buildItem(Color color) { + return Container( + key: ValueKey(color) , + alignment: Alignment.center, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/StatefulWidget/LongPressDraggable.dart b/lib/views/widgets/StatefulWidget/LongPressDraggable.dart new file mode 100644 index 0000000..1d2166d --- /dev/null +++ b/lib/views/widgets/StatefulWidget/LongPressDraggable.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 105, +// "name": 'LongPressDraggable与DragTarget联用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子 【Widget】\n" +// "【feedback】 : 拖拽时的孩子 【Widget】\n" +// "【axis】 : 拖动的轴 【Axis】\n" +// "【data】 : 数据 【T】\n" +// "【onDragStarted】 : 开始拖拽 【Function()】\n" +// "【onDragEnd】 : 结束拖拽 【Function(DraggableDetails)】\n" +// "【onDragCompleted】 : 拖拽完成 【Function()】\n" +// "【onDraggableCanceled】 : 拖拽取消 【Function(Velocity,Offset)】", +// } +class CustomLongPressDraggable extends StatefulWidget { + @override + _CustomLongPressDraggableState createState() => _CustomLongPressDraggableState(); +} + +class _CustomLongPressDraggableState extends State { + Color _color = Colors.grey; + String _info = 'DragTarget'; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Wrap( + children: _buildColors(), + spacing: 10, + ), + SizedBox(height: 20,), + _buildDragTarget() + ], + ), + ); + } + + List _buildColors() { + var colors = [ + Colors.red, + Colors.yellow, + Colors.blue, + Colors.green, + Colors.orange, + Colors.purple, + Colors.cyanAccent + ]; + return colors + .map( + (e) => LongPressDraggable( + onDragStarted: () => setState(() => _info = '开始拖拽'), + onDragEnd: (d) => setState(() => _info = '结束拖拽'), + onDragCompleted: () => _info = '拖拽完成', + onDraggableCanceled: (v, o) => _info = '拖拽取消', + child: Container( + width: 30, + height: 30, + alignment: Alignment.center, + child: Text( + colors.indexOf(e).toString(), + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.bold), + ), + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + ), + data: e, + feedback: Container( + width: 25, + height: 25, + decoration: BoxDecoration(color: e, shape: BoxShape.circle), + )), + ) + .toList(); + } + + Widget _buildDragTarget() { + return DragTarget( + onAccept: (data) => setState(() { + _info='onAccept'; + _color = data; + }), + builder: (context, candidateData, rejectedData) => Container( + width: 150.0, + height: 50.0, + color: _color, + child: Center( + child: Text( + _info, + style: TextStyle(color: Colors.white), + ), + ))); + } +} diff --git a/lib/views/widgets/StatefulWidget/Material.dart b/lib/views/widgets/StatefulWidget/Material.dart new file mode 100644 index 0000000..6c38775 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Material.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 160, +// "name": 'Material基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【type】 : 类型 【MaterialType】\n" +// "【elevation】 : 影深 【double】\n" +// "【shadowColor】 : 阴影颜色 【Color】\n" +// "【color】 : 颜色 【Color】", +// } +class CustomMaterial extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + runSpacing: 10, + children: MaterialType.values.map((e) => _buildMaterial(e)).toList()); + } + + Material _buildMaterial(MaterialType type) => Material( + shadowColor: Colors.blue, + type: type, + color: Colors.orange, + elevation: 3, + child: Container( + alignment: Alignment.center, + width: 100, + height: 60, + child: Text( + type.toString().split('.')[1], + style: TextStyle(color: Colors.black), + ), + ), + ); +} + +// { +// "widgetId": 160, +// "name": 'Material的shape属性', +// "priority": 2, +// "subtitle": +// "【shape】 : 形状 【ShapeBorder】\n", +// } +class ShapeMaterial extends StatelessWidget { + + final shapeMap = { + 'BorderDirectional': BorderDirectional( + top: BorderSide( + color: Colors.white, + ), + start: BorderSide(color: Colors.black, width: 15), + bottom: BorderSide( + color: Colors.white, + )), + 'Border': Border( + top: BorderSide(width: 5.0, color: Color(0xFFFFDFDFDF)), + left: BorderSide(width: 5.0, color: Color(0xFFFFDFDFDF)), + right: BorderSide(width: 5.0, color: Color(0xFFFF7F7F7F)), + bottom: BorderSide(width: 5.0, color: Color(0xFFFF7F7F7F)), + ), + 'Circle': CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + 'RoundedRectangleBorder': RoundedRectangleBorder( + side: BorderSide(width: 1.0, color: Colors.black), + borderRadius: BorderRadius.all(Radius.circular(15))), + 'ContinuousRectangleBorder': ContinuousRectangleBorder( + side: BorderSide.none, + borderRadius: BorderRadius.circular(40.0), + ) + }; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + runSpacing: 10, + children: shapeMap.keys.map((e) => _buildMaterial(e)).toList()); + } + + Material _buildMaterial(String type) => Material( + shadowColor: Colors.blue, + shape: shapeMap[type], + color: Colors.orange, + elevation: 3, + textStyle: TextStyle(color: Colors.white), + child: Container( + alignment: Alignment.center, + width: 300, + height: 60, + child: Text( + type, + ), + ), + ); +} diff --git a/lib/views/widgets/StatefulWidget/MaterialApp.dart b/lib/views/widgets/StatefulWidget/MaterialApp.dart new file mode 100644 index 0000000..8e3ffb6 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/MaterialApp.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/router.dart'; +import 'package:flutter_unit/views/pages/navigation/unit_navigation.dart'; +import 'package:flutter_unit/views/widgets/StatefulWidget/Scaffold.dart'; + +/// create by 张风捷特烈 on 2020-03-17 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 65, +// "name": 'MaterialApp基本用法', +// "priority": 1, +// "subtitle": +// "【theme】 : 主题 【ThemeData】\n" +// "【title】 : 任务栏标题 【String】\n" +// "【onGenerateRoute】 : 路由生成器 【RouteFactory】\n" +// "【home】 : 主页 【Widget】" +// } +class CustomMaterialApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 200, + child: MaterialApp( + title: 'Flutter Demo', + onGenerateRoute: Router.generateRoute, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: CustomScaffold(), + ), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/Overlay.dart b/lib/views/widgets/StatefulWidget/Overlay.dart new file mode 100644 index 0000000..5de2b41 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Overlay.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 182, +// "name": 'Overlay基本使用', +// "priority": 1, +// "subtitle": +// " Overlay.of(context).insert插入全局组件", +// } + + +bool show = false; +Offset offset = Offset(200, 200); + +final double radius = 60; +var entry = OverlayEntry( + builder: (context) => Stack( + children: [ + Positioned( + left: offset.dx, + top: offset.dy, + child: _buildFloating(), + ), + ], + )); + +///绘制悬浮控件 +_buildFloating() => GestureDetector( + onPanDown: (details) { + offset = details.globalPosition - Offset(radius / 2, radius / 2); + entry.markNeedsBuild(); + }, + onPanUpdate: (DragUpdateDetails details) { + offset = offset + details.delta; + entry.markNeedsBuild(); + }, + onLongPress: hideFloating, + child: Material( + color: Colors.transparent, + child: Container( + height: radius, + width: radius, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage('assets/images/icon_head.png')), + ), + ), + )); + +showFloating(BuildContext context) { + if (!show) { + Overlay.of(context).insert(entry); + show = true; + } +} + +hideFloating() { + if (show) { + entry.remove(); + show = false; + } +} + +class CustomOverlay extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + children: [ + Container( + height: 50, + child: RawMaterialButton( + elevation: 2, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + fillColor: Colors.blue, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + child: Icon(Icons.add), + onPressed: ()=>showFloating(context), + ), + ), + Container( + height: 50, + child: RawMaterialButton( + elevation: 2, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + fillColor: Colors.red, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + child: Icon(Icons.remove), + onPressed: hideFloating, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/PageView.dart b/lib/views/widgets/StatefulWidget/PageView.dart new file mode 100644 index 0000000..71ec1d0 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/PageView.dart @@ -0,0 +1,195 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-28 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 165, +// "name": 'PageView基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【onPageChanged】 : 点击事件 【ValueChanged】", +// } +class CustomPageView extends StatelessWidget { + final data = [ + Colors.green[50], + Colors.green[100], + Colors.green[200], + Colors.green[300], + Colors.green[400], + Colors.green[500], + Colors.green[600], + Colors.green[700], + Colors.green[800], + Colors.green[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 150, + child: PageView( + onPageChanged: (position){ + print(position); + }, + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 90, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, + fontSize:24,shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ); + } + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} +// { +// "widgetId": 165, +// "name": 'PageView滑动方向', +// "priority": 2, +// "subtitle": +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【reverse】 : 是否反向 【bool】", +// } +class DirectionPageView extends StatelessWidget { + final data = [ + Colors.orange[50], + Colors.orange[100], + Colors.orange[200], + Colors.orange[300], + Colors.orange[400], + Colors.orange[500], + Colors.orange[600], + Colors.orange[700], + Colors.orange[800], + Colors.orange[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 150, + child: PageView( + scrollDirection: Axis.vertical, + reverse: true, + onPageChanged: (position) { + print(position); + }, + children: data + .map((color) => + Container( + alignment: Alignment.center, + width: 90, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, + fontSize: 24, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 165, +// "name": 'PageView控制器简单实用', +// "priority": 3, +// "subtitle": +// "【controller】 : 页面控制器 【PageController】", +// } +class CtrlPageView extends StatefulWidget { + @override + _CtrlPageViewState createState() => _CtrlPageViewState(); +} + +class _CtrlPageViewState extends State { + final data = [ + Colors.orange[50], + Colors.orange[100], + Colors.orange[200], + Colors.orange[300], + Colors.orange[400], + Colors.orange[500], + Colors.orange[600], + Colors.orange[700], + Colors.orange[800], + Colors.orange[900], + ]; + + PageController _controller; + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + _controller=PageController( + viewportFraction: 0.8, + initialPage: (data.length/2).round() + ); + + } + + @override + Widget build(BuildContext context) { + return Container( + height: 150, + child: PageView( + controller: _controller, + onPageChanged: (position) { + print(position); + }, + children: data + .map((color) => + Container( + alignment: Alignment.center, + width: 90, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, + fontSize: 24, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/PopupMenuButton.dart b/lib/views/widgets/StatefulWidget/PopupMenuButton.dart new file mode 100644 index 0000000..2680a34 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/PopupMenuButton.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-16 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 56, +// "name": 'PopupMenuButton基本使用', +// "priority": 1, +// "subtitle": +// "【itemBuilder】 : 构造器 【PopupMenuItemBuilder】\n" +// "【offset】 : 偏移 【Offset】\n" +// "【color】 : 背景颜色 【Color】\n" +// "【shape】 : 形状 【ShapeBorder】\n" +// "【elevation】 : 影深 【double】\n" +// "【onCanceled】 : 取消事件 【Function()】\n" +// "【onSelected】 : 选择事件 【Function(T)】", +// } +class CustomPopupMenuButton extends StatefulWidget { + @override + _CustomPopupMenuButtonState createState() => _CustomPopupMenuButtonState(); +} + +class _CustomPopupMenuButtonState extends State { + final map = { + "关于": Icons.info_outline, + "帮助": Icons.help_outline, + "问题反馈": Icons.add_comment, + }; + + @override + Widget build(BuildContext context) { + return PopupMenuButton( + itemBuilder: (context) => buildItems(), + offset: Offset(0, 50), + color: Color(0xffF4FFFA), + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + topRight: Radius.circular(5), + bottomLeft: Radius.circular(5), + )), + onSelected: (e) { + print(e); + if (e == '关于') { + DialogAbout.show(context); + } + }, + onCanceled: () => print('onCanceled'), + ); + } + + List> buildItems() { + return map.keys + .toList() + .map((e) => PopupMenuItem( + value: e, + child: Wrap( + spacing: 10, + children: [ + Icon( + map[e], + color: Colors.blue, + ), + Text(e), + ], + ))) + .toList(); + } +} diff --git a/lib/views/widgets/StatefulWidget/PopupMenuDivider.dart b/lib/views/widgets/StatefulWidget/PopupMenuDivider.dart new file mode 100644 index 0000000..44e9859 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/PopupMenuDivider.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 174, +// "name": 'PopupMenuDivider基本使用', +// "priority": 1, +// "subtitle": +// "【height】 : 高度 【double】", +// } +class CustomPopupMenuDivider extends StatelessWidget { + final map = { + "关于": Icons.info_outline, + "帮助": Icons.help_outline, + "问题反馈": Icons.add_comment, + }; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + _buildPopupMenuButton(context), + PopupMenuDivider(), + ], + ), + ); + } + + PopupMenuButton _buildPopupMenuButton(BuildContext context) { + return PopupMenuButton( + itemBuilder: (context) => [ + ...buildItems().sublist(0, 2), + PopupMenuDivider(), + ...buildItems().sublist(2, 3) + ], + offset: Offset(0, 50), + color: Color(0xffF4FFFA), + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + topRight: Radius.circular(5), + bottomLeft: Radius.circular(5), + )), + onSelected: (e) { + print(e); + if (e == '关于') { + DialogAbout.show(context); + } + }, + onCanceled: () => print('onCanceled'), + ); + } + + List> buildItems() { + return map.keys + .toList() + .map((e) => PopupMenuItem( + value: e, + child: Wrap( + spacing: 10, + children: [ + Icon( + map[e], + color: Colors.blue, + ), + Text(e), + ], + ))) + .toList(); + } +} diff --git a/lib/views/widgets/StatefulWidget/Radio.dart b/lib/views/widgets/StatefulWidget/Radio.dart new file mode 100644 index 0000000..562a72d --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Radio.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 45, +// "name": 'Radio基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 选钮值 【T】\n" +// "【groupValue】 : 当前匹配值 【T】\n" +// "【activeColor】 : 激活颜色 【Color】\n" +// "【onChanged】 : 改变时回调 【Function(T)】", +// } +class CustomRadio extends StatefulWidget { + @override + _CustomRadioState createState() => _CustomRadioState(); +} + +class _CustomRadioState extends State { + var data = [1, 2, 3, 4, 5]; + double _value = 1; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: data + .map((e) => Radio( + activeColor: Colors.orangeAccent, + value: e, + groupValue: _value, + onChanged: (v) => setState(() => _value = v))) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/RangerSlider.dart b/lib/views/widgets/StatefulWidget/RangerSlider.dart new file mode 100644 index 0000000..ee6c761 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/RangerSlider.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 44, +// "name": 'Slider基本使用', +// "priority": 1, +// "subtitle": +// "【values】 : 数值 【RangeValues】\n" +// "【min】 : 最小值 【double】\n" +// "【max】 : 最大值 【double】\n" +// "【divisions】 : 分段数 【int】\n" +// "【label】 : 提示气泡文字 【String】\n" +// "【activeColor】 : 激活颜色 【Color】\n" +// "【inactiveColor】 : 非激活颜色 【Color】\n" +// "【onChangeStart】 : 开始滑动时监听 【Function(RangeValues)】\n" +// "【onChangeEnd】 : 滑动结束时监听 【Function(RangeValues)】\n" +// "【onChanged】 : 改变时回调 【Function(RangeValues)】", +// } +class CustomRangeSlider extends StatefulWidget { + @override + _CustomRangeSliderState createState() => _CustomRangeSliderState(); +} + +class _CustomRangeSliderState extends State { + RangeValues _rangeValues = RangeValues(90, 270); + + @override + Widget build(BuildContext context) { + return RangeSlider( + values: _rangeValues, + divisions: 180, + min: 0.0, + max: 360.0, + labels: RangeLabels("${_rangeValues.start.toStringAsFixed(1)}", + "${_rangeValues.end.toStringAsFixed(1)}"), + activeColor: Colors.orangeAccent, + inactiveColor: Colors.green.withAlpha(99), + onChangeStart: (value) { + print('开始滑动:$value'); + }, + onChangeEnd: (value) { + print('滑动结束:$value'); + }, + onChanged: (value) { + setState(() { + _rangeValues = value; + }); + }); + } +} diff --git a/lib/views/widgets/StatefulWidget/RawChip.dart b/lib/views/widgets/StatefulWidget/RawChip.dart new file mode 100644 index 0000000..db324d1 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/RawChip.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 153, +// "name": 'RawChip点击效果', +// "priority": 1, +// "subtitle": +// "【label】: 中间组件 【Widget】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】\n" +// "【labelPadding】 : label边距 【EdgeInsetsGeometry】\n" +// "【shadowColor】: 阴影色 【Color】\n" +// "【avatar】: 左侧组件 【Widget】\n" +// "【elevation】: 影深 【double】\n" +// "【pressElevation】: 点击时影深 【double】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class PressRawChip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: RawChip( + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + label: Text('张风捷特烈'), + avatar: Image.asset("assets/images/icon_head.png"), + elevation: 3, + pressElevation: 5, + shadowColor: Colors.orangeAccent, + onPressed: () => DialogAbout.show(context), + ), + ); + } +} + +// { +// "widgetId": 153, +// "name": 'RawChip选中和删除效果', +// "priority": 2, +// "subtitle": +// "【selected】: 是否选中 【bool】\n" +// "【deleteIconColor】: 尾部图标色 【Color】\n" +// "【selectedColor】: 选中色 【Color】\n" +// "【deleteIcon】: 尾部组件 【Widget】\n" +// "【onSelected】: 选中事件 【Function(bool)】\n" +// "【onDeleted】 : 尾部事件 【Function()】", +// } +class SelectRawChip extends StatefulWidget { + @override + _SelectRawChipState createState() => _SelectRawChipState(); +} + +class _SelectRawChipState extends State { + bool _selected = false; + @override + Widget build(BuildContext context) { + return Container( + child: RawChip( + selected: _selected, + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + deleteIconColor: Colors.red, + selectedColor: Colors.orangeAccent.withAlpha(44), + label: Text('张风捷特烈'), + avatar: Image.asset("assets/images/icon_head.png"), + elevation: 3, + pressElevation: 5, + shadowColor: Colors.orangeAccent, + onSelected: (v)=> setState(() => _selected=v), + onDeleted: () => DialogAbout.show(context), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/RawMaterialButton.dart b/lib/views/widgets/StatefulWidget/RawMaterialButton.dart new file mode 100644 index 0000000..dac5c3e --- /dev/null +++ b/lib/views/widgets/StatefulWidget/RawMaterialButton.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 175, +// "name": 'RawMaterialButton基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【elevation】 : 影深 【double】\n" +// "【fillColor】 : 填充色 【Color】\n" +// "【splashColor】 : 水波纹色 【Color】\n" +// "【textStyle】 : 文字样式 【TextStyle】\n" +// "【onLongPress】 : 长按事件 【Function()】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class CustomRawMaterialButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: Wrap( + spacing: 20, + children: [ + RawMaterialButton( + elevation: 2, + fillColor: Colors.green, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Icon(Icons.remove), + onPressed: ()=>print('onPressed'), + ), + RawMaterialButton( + elevation: 2, + fillColor: Colors.blue, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Text('Push'), + onPressed: ()=>print('onPressed'), + ), + RawMaterialButton( + elevation: 2, + fillColor: Colors.red, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Icon(Icons.add), + onPressed: ()=>print('onPressed'), + ), + + ], + ), + ); + } +} + +// { +// "widgetId": 175, +// "name": 'RawMaterialButton基本使用', +// "priority": 2, +// "subtitle": +// "【highlightElevation】 : 高亮影深 【double】\n" +// "【shape】 : 形状 【ShapeBorder】", +// } +class ShapeRawMaterialButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: Wrap( + spacing: 20, + children: [ + RawMaterialButton( + elevation: 2, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + fillColor: Colors.green, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Icon(Icons.remove), + onPressed: ()=>print('onPressed'), + ), + RawMaterialButton( + shape:RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15))), + elevation: 0, + highlightElevation: 0, + fillColor: Colors.blue, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Text('Push'), + onPressed: ()=>print('onPressed'), + ), + RawMaterialButton( + elevation: 2, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + fillColor: Colors.red, + splashColor: Colors.orange, + textStyle: TextStyle(color: Colors.white), + onLongPress: ()=>print('onLongPress'), + child: Icon(Icons.add), + onPressed: ()=>print('onPressed'), + ), + + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/RefreshIndicator.dart b/lib/views/widgets/StatefulWidget/RefreshIndicator.dart new file mode 100644 index 0000000..caaae62 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/RefreshIndicator.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +// { +// "widgetId": 49, +// "name": 'RefreshIndicator基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 孩子(可滑动) 【Widget】\n" +// "【displacement】 : 指示器悬浮高度 【double】\n" +// "【color】 : 指示器颜色 【Color】\n", +// "【backgroundColor】 : 指示器背景色 【Color】\n" +// "【onRefresh】 : 异步函数 【Future Function()】" +// } +class CustomRefreshIndicator extends StatefulWidget { + @override + _CustomRefreshIndicatorState createState() => _CustomRefreshIndicatorState(); +} + +class _CustomRefreshIndicatorState extends State { + int _count = 0; + + @override + Widget build(BuildContext context) { + + return Container( + height: 200, + width: 200, + child: RefreshIndicator( + onRefresh: _increment, + displacement: 20, + color: Colors.orange, + backgroundColor: Colors.white, + child: SingleChildScrollView( + child: Container( + alignment: Alignment.center, + width: 200, + height: 300, + color: Colors.blue, + child: Text('$_count',style: TextStyle(color: Colors.white,fontSize: 40)), + ), + ), + ), + ); + } + + Future _increment() async { + await Future.delayed(Duration(seconds: 2)); + setState(() { + _count++; + }); + } +} diff --git a/lib/views/widgets/StatefulWidget/ReorderableListView.dart b/lib/views/widgets/StatefulWidget/ReorderableListView.dart new file mode 100644 index 0000000..078c137 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/ReorderableListView.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-30 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 177, +// "name": 'ReorderableListView基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【header】 : 头部组件 【Widget】\n" +// "【padding】 : 内边距 【EdgeInsets】\n" +// "【onReorder】 : 调换时回调 【ReorderCallback】", +// } +class CustomReorderableListView extends StatefulWidget { + @override + _CustomReorderableListViewState createState() => _CustomReorderableListViewState(); +} + +class _CustomReorderableListViewState extends State { + var data = [ + Colors.yellow[50], + Colors.yellow[100], + Colors.yellow[200], + Colors.yellow[300], + Colors.yellow[400], + Colors.yellow[500], + Colors.yellow[600], + Colors.yellow[700], + Colors.yellow[800], + Colors.yellow[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 250, + child: ReorderableListView( + padding: EdgeInsets.all(10), + header: Container( + color: Colors.blue, + alignment: Alignment.center, + height: 50, + child: Text('长按拖拽进行换位',style: TextStyle(color: Colors.white),)), + onReorder: _handleReorder, + children: data.map((color) => _buildItem(color)).toList(), + ), + ); + } + + void _handleReorder(int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + setState(() { + final element = data.removeAt(oldIndex); + data.insert(newIndex, element); + }); + + } + + Widget _buildItem(Color color) { + return Container( + key: ValueKey(color) , + alignment: Alignment.center, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} +// { +// "widgetId": 177, +// "name": 'ReorderableListView滑动方向', +// "priority": 2, +// "subtitle": +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【reverse】 : 是否反向 【bool】", +// } +class DirectionReorderableListView extends StatefulWidget { + @override + _DirectionReorderableListViewState createState() => _DirectionReorderableListViewState(); +} + +class _DirectionReorderableListViewState extends State { + var data = [ + Colors.yellow[50], + Colors.yellow[100], + Colors.yellow[200], + Colors.yellow[300], + Colors.yellow[400], + Colors.yellow[500], + Colors.yellow[600], + Colors.yellow[700], + Colors.yellow[800], + Colors.yellow[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ReorderableListView( + scrollDirection: Axis.horizontal, + reverse: false, + onReorder: _handleReorder, + children: data.map((color) => _buildItem(color)).toList(), + ), + ); + } + + void _handleReorder(int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + setState(() { + final element = data.removeAt(oldIndex); + data.insert(newIndex, element); + }); + + } + + Widget _buildItem(Color color) { + return Container( + key: ValueKey(color) , + alignment: Alignment.center, + width: 80, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/Scaffold.dart b/lib/views/widgets/StatefulWidget/Scaffold.dart new file mode 100755 index 0000000..4485858 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Scaffold.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/widgets/StatefulWidget/PopupMenuButton.dart'; + +// { +// "widgetId": 64, +// "name": 'Scaffold基本用法', +// "priority": 1, +// "subtitle": +// "【appBar】 : 头部组件 【PreferredSizeWidget】\n" +// "【bottomNavigationBar】 : 底部组件 【Widget】\n" +// "【drawer】 : 左侧滑组件 【Widget】\n" +// "【endDrawer】 : 右侧滑组件 【Widget】\n" +// "【body】 : 内容组件 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【floatingActionButton】 : 浮动按钮 【Widget】\n" +// "【floatingActionButtonLocation】 : 浮动按钮位置 【FloatingActionButtonLocation】", +// } +class CustomScaffold extends StatefulWidget { + CustomScaffold({Key key}) : super(key: key); + + @override + State createState() => _CustomScaffoldState(); +} + +// AppBar 默认的实例,有状态 +class _CustomScaffoldState extends State with SingleTickerProviderStateMixin { + final tabs = ['风画庭', '雨韵舍', '雷鸣殿', '电疾堂', '霜寒阁', '雪月楼']; + var _position = 0; + final iconsMap = { + "图鉴": Icons.home, + "动态": Icons.toys, + "喜欢": Icons.favorite, + "手册": Icons.class_, + "我的": Icons.account_circle, + }; + final _colors = [ + Colors.blue, + Colors.red, + Colors.yellow, + Colors.green, + Colors.purple, + ]; + + TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 300, + child: Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + onPressed: () {}, + ), + drawer: _buildLeftDrawer(), + endDrawer: _buildLeftDrawer(), + appBar: AppBar( + title: Text('风雅六社'), + backgroundColor: Colors.blue, + centerTitle: true, + actions: [Icon(Icons.star), CustomPopupMenuButton()], + bottom: _buildTabBar(), + ), + body: _buildTableBarView(), + bottomNavigationBar: _buildBottomNavigationBar(), + ), + ); + } + + Drawer _buildLeftDrawer() => Drawer( + elevation: 1, + child: Image.asset( + 'assets/images/sabar.jpg', + fit: BoxFit.cover, + ), + ); + + Widget _buildTabBar() => TabBar( + isScrollable: true, + controller: _tabController, + indicatorColor: Colors.orangeAccent, + tabs: tabs.map((e) => Tab(text: e)).toList(), + ); + + Widget _buildBottomNavigationBar() => BottomNavigationBar( + onTap: (position) => setState(() => _position = position), + currentIndex: _position, + elevation: 1, + backgroundColor: Colors.white, + iconSize: 25, + selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold), + showUnselectedLabels: false, + showSelectedLabels: true, + items: iconsMap.keys + .map((key) => BottomNavigationBarItem( + title: Text( + key, + ), + icon: Icon(iconsMap[key]), + backgroundColor: _colors[_position])) + .toList(), + ); + + Widget _buildTableBarView() => TabBarView( + controller: _tabController, + children: tabs + .map((e) => Center( + child: Text( + e, + style: TextStyle(color: Colors.blue, fontSize: 20), + ))) + .toList()); +} diff --git a/lib/views/widgets/StatefulWidget/Scrollable.dart b/lib/views/widgets/StatefulWidget/Scrollable.dart new file mode 100644 index 0000000..3309479 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Scrollable.dart @@ -0,0 +1,58 @@ +//import 'package:flutter/material.dart'; +// +///// create by 张风捷特烈 on 2020-03-28 +///// contact me by email 1981462002@qq.com +///// 说明: +// +//class CustomScrollable extends StatelessWidget { +// final data = [ +// Colors.blue[50], +// Colors.blue[100], +// Colors.blue[200], +// Colors.blue[300], +// Colors.blue[400], +// Colors.blue[500], +// Colors.blue[600], +// Colors.blue[700], +// Colors.blue[800], +// Colors.blue[900], +// ]; +// +// @override +// Widget build(BuildContext context) { +// return Container( +// height: 200, +// child: Scrollable( +// viewportBuilder: (ctx, p) => Viewport(offset: p, +// slivers: [ +// +// ], +// ), +// ), +// ); +// } +// +// Column buildColumn() { +// return Column( +// children: data +// .map((color) => Container( +// alignment: Alignment.center, +// height: 50, +// color: color, +// child: Text( +// colorString(color), +// style: TextStyle(color: Colors.white, shadows: [ +// Shadow( +// color: Colors.black, +// offset: Offset(.5, .5), +// blurRadius: 2) +// ]), +// ), +// )) +// .toList(), +// ); +// } +// +// String colorString(Color color) => +// "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +//} diff --git a/lib/views/widgets/StatefulWidget/Scrollbar.dart b/lib/views/widgets/StatefulWidget/Scrollbar.dart new file mode 100644 index 0000000..af04fac --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Scrollbar.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 194, +// "name": 'Scrollbar基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【controller】 : 控制器 【ScrollController】", +// } +class CustomScrollbar extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: Scrollbar( + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 5), + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/SelectableText.dart b/lib/views/widgets/StatefulWidget/SelectableText.dart new file mode 100644 index 0000000..41aa2a0 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/SelectableText.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 53, +// "name": 'SelectableText基本使用', +// "priority": 1, +// "subtitle": +// "【入参】 : 显示文字 【String】\n" +// "【style】 : 文字样式 【TextStyle】\n" +// "【cursorRadius】 : 光标半径 【Radius】\n" +// "【cursorColor】 : 光标颜色 【Color】\n" +// "【cursorWidth】 : 光标宽度 【double】\n" +// "【showCursor】 : 是否显示光标 【bool】\n" +// "【autofocus】 : 自动聚焦 【bool】" +// } +class CustomSelectableText extends StatelessWidget { + final text = " 始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时," + "臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然," + "技经肯綮之未尝,而况大軱乎!良庖岁更刀,割也;族庖月更刀,折也。" + "今臣之刀十九年矣,所解数千牛矣,而刀刃若新发于硎。彼节者有间,而刀刃者无厚;" + "以无厚入有间,恢恢乎其于游刃必有余地矣,是以十九年而刀刃若新发于硎。" + "虽然,每至于族,吾见其难为,怵然为戒,视为止,行为迟。动刀甚微,謋然已解,如土委地。" + "提刀而立,为之四顾,为之踌躇满志,善刀而藏之."; + + @override + Widget build(BuildContext context) { + return SelectableText( + text, + style: TextStyle(fontSize: 18, color: Colors.orange), + cursorColor: Colors.green, + cursorRadius: Radius.circular(3), + cursorWidth: 5, + showCursor: true, + autofocus: false, + ); + } +} + +// { +// "widgetId": 53, +// "name": 'SelectableText对齐属性', +// "priority": 2, +// "subtitle": +// "【textAlign】 : 对齐方式*6 【textAlign】\n" +// "【textDirection】 : 文字方向*2 【TextDirection】", +// } +class AlignSelectableText extends StatefulWidget { + @override + _AlignSelectableTextState createState() => _AlignSelectableTextState(); +} + +class _AlignSelectableTextState extends State { + final text = + "The [SelectableText] widget displays a string of text with a single style." + "The string might break across multiple lines or might all be displayed on" + "the same line depending on the layout constraints."; + var _textAlign = TextAlign.left; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSelector(), + SelectableText( + text, + style: TextStyle(fontSize: 18, color: Colors.red), + cursorColor: Colors.green, + cursorRadius: Radius.circular(3), + cursorWidth: 5, + showCursor: true, + textAlign: _textAlign, + textDirection: TextDirection.ltr, + + autofocus: false, + ), + ], + ); + } + + Widget _buildSelector() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + "textAlign属性选择:", + style: TextStyle( + fontSize: 16, color: Colors.blue, fontWeight: FontWeight.bold), + ), + DropdownButton( + underline: Container(), + value: _textAlign, + items: TextAlign.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.toString()), + )) + .toList(), + onChanged: (e) { + setState(() { + _textAlign = e; + }); + }), + ], + ); + } +} diff --git a/lib/views/widgets/StatefulWidget/Slider.dart b/lib/views/widgets/StatefulWidget/Slider.dart new file mode 100644 index 0000000..f4fe001 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Slider.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 42, +// "name": 'Slider基本使用', +// "priority": 1, +// "subtitle": +// "【value】 : 数值 【double】\n" +// "【min】 : 最小值 【double】\n" +// "【max】 : 最大值 【double】\n" +// "【activeColor】 : 激活颜色 【Color】\n" +// "【inactiveColor】 : 非激活颜色 【Color】\n" +// "【onChanged】 : 改变时回调 【Function(double)】", +// } +class CustomSlider extends StatefulWidget { + @override + _CustomSliderState createState() => _CustomSliderState(); +} + +class _CustomSliderState extends State { + double _value = 0.0; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text('当前值:${_value.toStringAsFixed(1)}'), + Slider( + value: _value, + min: 0.0, + max: 360.0, + activeColor: Colors.orangeAccent, + inactiveColor: Colors.green.withAlpha(99), + onChanged: (value) { + setState(() { + _value = value; + }); + }), + ], + ); + } +} + +// { +// "widgetId": 42, +// "name": 'Slider的分段与标签', +// "priority": 2, +// "subtitle": +// "【divisions】 : 分段数 【int】\n" +// "【label】 : 提示气泡文字 【String】\n" +// "【onChangeStart】 : 开始滑动时监听 【Function(double)】\n" +// "【onChangeEnd】 : 滑动结束时监听 【Function(double)】", +// } +class DivisionsSlider extends StatefulWidget { + @override + _DivisionsSliderState createState() => _DivisionsSliderState(); +} + +class _DivisionsSliderState extends State { + double _value = 0.0; + + @override + Widget build(BuildContext context) { + return Slider( + value: _value, + min: 0.0, + max: 360.0, + divisions: 10, + label: '${_value.toStringAsFixed(1)}', + activeColor: Colors.orangeAccent, + inactiveColor: Colors.green.withAlpha(99), + onChangeStart: (value) { + print('开始滑动:$value'); + }, + onChangeEnd: (value) { + print('滑动结束:$value'); + }, + onChanged: (value) { + setState(() { + _value = value; + }); + }); + } +} diff --git a/lib/views/widgets/StatefulWidget/Stepper.dart b/lib/views/widgets/StatefulWidget/Stepper.dart new file mode 100644 index 0000000..2b06d00 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Stepper.dart @@ -0,0 +1,213 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-01 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 200, +// "name": 'Stepper基本使用', +// "priority": 1, +// "subtitle": +// "【steps】 : 步骤列表 【List】\n" +// "【currentStep】 : 当前步骤 【double】\n" +// "【onStepTapped】 : 点击回调 【ValueChanged】\n" +// "【onStepCancel】 : 上一步回调 【VoidCallback】\n" +// "【controlsBuilder】 : 控制器构造 【ControlsWidgetBuilder】", +// } +class StepperDemo extends StatefulWidget { + @override + _StepperDemoState createState() => _StepperDemoState(); +} + +class _StepperDemoState extends State { + int _position = 0; + + final stepsData = { + "填写表单":'请按表单填写个人信息。', + "邮箱校验":'已将邮件发送至您的邮箱,请按照相关指示对您的账号进行邮箱校验。', + "注册完成":'恭喜您,注册完成!', + }; + + final steps = [ + Step( + title: Text("填写表单"), + content: Container(height: 60, child: Text("请按表单填写个人信息")), + ), + Step(title: Text("邮箱校验"), content: Text("请对您的账号进行邮箱校验")), + Step(title: Text("注册完成"), content: Text("恭喜您,注册完成")), + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: Stepper( + type:StepperType.horizontal, + currentStep: _position, + onStepTapped: (index) { + setState(() { + _position = index; + }); + }, + onStepContinue: () { + setState(() { + if (_position < 2) { + _position++; + } + }); + }, + onStepCancel: () { + if (_position > 0) { + setState(() { + _position--; + }); + } + }, + controlsBuilder: (_, + {VoidCallback onStepContinue, VoidCallback onStepCancel}) { + return Row( + children: [ + RaisedButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: onStepContinue, + child: Icon( + Icons.check, + color: Colors.white, + ), + ), + RaisedButton( + color: Colors.red, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: onStepCancel, + child: Icon( + Icons.keyboard_backspace, + color: Colors.white, + ), + ), + ], + ); + }, + steps: stepsData.keys.map((e){ + bool isActive = stepsData.keys.toList().indexOf(e) ==_position; + return Step( + title: Text(e,style: TextStyle(color: isActive?Colors.blue:Colors.black),), + isActive: isActive, + state: _getState(stepsData.keys.toList().indexOf(e)), + content: Container(height: 60, child: Text(stepsData[e])), + ); + }).toList()), + ); + } + _getState(index){ + if(_position==index) return StepState.editing; + if(_position>index) return StepState.complete; + return StepState.indexed; + } +} + +// { +// "widgetId": 200, +// "name": 'Stepper的方向', +// "priority": 2, +// "subtitle": +// "【type】 : 方向 【StepperType】", +// } +class VerticalStepper extends StatefulWidget { + @override + _VerticalStepperState createState() => _VerticalStepperState(); +} + +class _VerticalStepperState extends State { + int _position = 0; + + final stepsData = { + "填写表单":'请按表单填写个人信息。', + "邮箱校验":'已将邮件发送至您的邮箱,请按照相关指示对您的账号进行邮箱校验。', + "注册完成":'恭喜您,注册完成!', + }; + + final steps = [ + Step( + title: Text("填写表单"), + content: Container(height: 60, child: Text("请按表单填写个人信息")), + ), + Step(title: Text("邮箱校验"), content: Text("请对您的账号进行邮箱校验")), + Step(title: Text("注册完成"), content: Text("恭喜您,注册完成")), + ]; + + @override + Widget build(BuildContext context) { + return Container( + child: Stepper( + type:StepperType.vertical, + currentStep: _position, + onStepTapped: (index) { + setState(() { + _position = index; + }); + }, + onStepContinue: () { + setState(() { + if (_position < 2) { + _position++; + } + }); + }, + onStepCancel: () { + if (_position > 0) { + setState(() { + _position--; + }); + } + }, + controlsBuilder: (_, + {VoidCallback onStepContinue, VoidCallback onStepCancel}) { + return Row( + children: [ + RaisedButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: onStepContinue, + child: Icon( + Icons.check, + color: Colors.white, + ), + ), + RaisedButton( + color: Colors.red, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: onStepCancel, + child: Icon( + Icons.keyboard_backspace, + color: Colors.white, + ), + ), + ], + ); + }, + steps: stepsData.keys.map((e){ + bool isActive = stepsData.keys.toList().indexOf(e) ==_position; + return Step( + title: Text(e,style: TextStyle(color: isActive?Colors.blue:Colors.black),), + isActive: isActive, + state: _getState(stepsData.keys.toList().indexOf(e)), + content: Container(height: 60, child: Text(stepsData[e])), + ); + }).toList()), + ); + } + _getState(index){ + if(_position==index) return StepState.editing; + if(_position>index) return StepState.complete; + return StepState.indexed; + } +} diff --git a/lib/views/widgets/StatefulWidget/StreamBuilder.dart b/lib/views/widgets/StatefulWidget/StreamBuilder.dart new file mode 100644 index 0000000..61a23f7 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/StreamBuilder.dart @@ -0,0 +1,111 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 173, +// "name": 'StreamBuilder基本使用', +// "priority": 1, +// "subtitle": +// "【stream】 : 子组件 【Stream】\n" +// "【initialData】 : 初始数据 【T】\n" +// "【builder】 : 点击事件 【AsyncWidgetBuilder】", +// } +class CustomStreamBuilder extends StatefulWidget { + @override + _CustomStreamBuilderState createState() => _CustomStreamBuilderState(); +} + +class _CustomStreamBuilderState extends State { + CountGenerator _generator = CountGenerator()..increment(); + + @override + void dispose() { + _generator.dispose(); //关闭控制器 + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + FlatButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + child: Icon( + Icons.add, + color: Colors.white, + ), + onPressed: () async { + await _generator.increment(); + }, + ), + _buildStreamBuilder(), + FlatButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + child: Icon( + Icons.remove, + color: Colors.white, + ), + onPressed: () async { + await _generator.minus(); + }, + ), + ], + ), + ); + } + + Widget _buildStreamBuilder() => StreamBuilder( + stream: _generator.state, + builder: (BuildContext context, AsyncSnapshot snap) { + print(snap); + if (snap.connectionState == ConnectionState.done) { + return Text('Done'); + } + if (snap.connectionState == ConnectionState.active) { + return Text( + snap.data.toString(), + style: Theme.of(context).textTheme.display1, + ); + } + if (snap.connectionState == ConnectionState.waiting) { + return CircularProgressIndicator(); + } + if (snap.hasError) { + return Text('Error'); + } + return Container(); + }); +} + +class CountGenerator { + int _count = 0; //计数器数据 + final StreamController _controller = StreamController(); //控制器 + + Stream get state => _controller.stream; //获取状态流 + int get count => _count; //获取计数器数据 + + void dispose() {//关闭控制器 + _controller.close(); + } + + Future increment() async {//增加记数方法 + _controller.add(++_count); + } + + Future minus() async {//增加记数方法 + _controller.add(--_count); + } +} diff --git a/lib/views/widgets/StatefulWidget/Switch.dart b/lib/views/widgets/StatefulWidget/Switch.dart new file mode 100644 index 0000000..ccfbba2 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Switch.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-14 +/// contact me by email 1981462002@qq.com +/// 说明: + +/// { +// "widgetId": 40, +// "name": 'Switch基础语法', +// "priority": 1, +// "subtitle": +// "【inactiveThumbColor】 : 未选中小圈颜色 【Color】\n" +// "【inactiveTrackColor】 : 未选中滑槽颜色 【Color】\n" +// "【activeColor】 : 选中时小圈颜色 【Color】\n" +// "【activeTrackColor】 : 选中时滑槽颜色 【Color】\n" +// "【onChanged】 : 切换回调 【Function(double)】" +// " onChanged时,回调true、null、false三种状态", +// } +class CustomSwitch extends StatefulWidget { + @override + _CustomSwitchState createState() => _CustomSwitchState(); +} + +class _CustomSwitchState extends State { + final colors = [Colors.red, Colors.yellow, Colors.blue, Colors.green]; + bool _checked = false; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: colors + .map((e) => + Switch( + value: _checked, + inactiveThumbColor: e, + inactiveTrackColor: Colors.grey.withAlpha(88), + activeColor: Colors.green, + activeTrackColor: Colors.orange, + onChanged: (v) { + setState(() => _checked = v); + })) + .toList(), + ); + } +} + +// { +// "widgetId": 40, +// "name": 'Switch图片', +// "priority": 2, +// "subtitle": +// "【inactiveThumbImage】 : 未选中小圈图片 【ImageProvider】\n" +// "【activeThumbImage】 : 选中时滑槽颜色 【ImageProvider】" +// } +class ImageSwitch extends StatefulWidget { + @override + _ImageSwitchState createState() => _ImageSwitchState(); +} + +class _ImageSwitchState extends State { + final imgs = [ + "assets/images/head_icon/icon_5.jpg", + "assets/images/head_icon/icon_6.jpg", + "assets/images/head_icon/icon_7.jpg", + "assets/images/head_icon/icon_8.jpg"]; + bool _checked = false; + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: imgs + .map((e) => + Switch( + value: _checked, + inactiveThumbImage: AssetImage(e), + activeThumbImage: AssetImage('assets/images/pica.gif'), + onChanged: (v) { + setState(() => _checked = v); + })) + .toList(), + ); + } +} + diff --git a/lib/views/widgets/StatefulWidget/TabBarView.dart b/lib/views/widgets/StatefulWidget/TabBarView.dart new file mode 100644 index 0000000..7e73db8 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/TabBarView.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 59, +// "name": 'TabBarView需要与TabBar联用', +// "priority": 1, +// "subtitle": +// "【controller】 : 控制器 【TabController】\n" +// "【children】 : 孩子们 【指示器颜色】\n" +// "【physics】 : 表现 【ScrollPhysics】" +// } +class CustomTabBarView extends StatefulWidget { + @override + _CustomTabBarViewState createState() => _CustomTabBarViewState(); +} + +class _CustomTabBarViewState extends State with SingleTickerProviderStateMixin { + final tabs = ['风画庭', '雨韵舍', '雷鸣殿', '电疾堂', '霜寒阁', '雪月楼']; + TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + _buildTabBar(), + Container( + color: Colors.purple, + width: MediaQuery.of(context).size.width, + height: 200, + child: _buildTableBarView()) + ], + ), + ); + } + + Widget _buildTabBar() => TabBar( + onTap: (tab) => print(tab), + labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + unselectedLabelStyle: TextStyle(fontSize: 16), + isScrollable: true, + controller: _tabController, + labelColor: Colors.blue, + indicatorWeight: 3, + indicatorPadding: EdgeInsets.symmetric(horizontal: 10), + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.orangeAccent, + tabs: tabs.map((e) => Tab(text: e)).toList(), + ); + + Widget _buildTableBarView() => TabBarView( + controller: _tabController, + children: tabs.map((e) => Center( + child: Text(e, style: TextStyle(color: Colors.white, fontSize: 20), + ))).toList()); +} diff --git a/lib/views/widgets/StatefulWidget/TableRowInkWell.dart b/lib/views/widgets/StatefulWidget/TableRowInkWell.dart new file mode 100644 index 0000000..a5c8285 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/TableRowInkWell.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 151, +// "name": 'TableRowInkWell基本事件', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onTap】 : 点击事件 【Function()】\n" +// "【onDoubleTap】 : 双击事件 【Function()】\n" +// "【onLongPress】 : 长按事件 【Function()】\n" +// "【onHighlightChanged】 : 高亮变化回调 【Function(bool)】", +// } +class CustomTableRowInkWell extends StatelessWidget { + @override + Widget build(BuildContext context) { + var title = _ItemBean("单位称", "量纲", "单位", "单位名称", "单位符号"); + var m = _ItemBean("长度", "L", "1m", "米", "m"); + var kg = _ItemBean("质量", "M", "1Kg", "千克", "Kg"); + var s = _ItemBean("时间", "T", "1s", "秒", "s"); + var a = _ItemBean("安培", "Ι", "1A", "安培", "A"); + var k = _ItemBean("热力学温度", "θ", "1K", "开尔文", "K"); + var mol = _ItemBean("物质的量", "N", "1mol", "摩尔", "mol"); + var cd = _ItemBean("发光强度", "J", "1cd", "坎德拉", "cd"); + + var data = <_ItemBean>[title, m, kg, s, a, k, mol, cd]; + + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Table( + columnWidths: const { + 0: FixedColumnWidth(80.0), + 1: FixedColumnWidth(80.0), + 2: FixedColumnWidth(80.0), + 3: FixedColumnWidth(80.0), + 4: FixedColumnWidth(80.0), + }, + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + border: TableBorder.all( + color: Colors.orangeAccent, width: 1.0, style: BorderStyle.solid), + children: data + .map((item) => TableRow(children: [ + TableRowInkWell( + onTap: () => print('onTap'), + onDoubleTap: () => print('onDoubleTap'), + onLongPress: () => print('onLongPress'), + onHighlightChanged: (v) => print('onHighlightChanged:$v'), + child: Center( + child: Text( + item.name, + style: TextStyle(color: Colors.blue), + )), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.symbol)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unitSymbol)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unitName)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(item.unit)), + ), + ])) + .toList(), + ), + ); + } +} + +class _ItemBean { + String name; + String symbol; + String unit; + String unitName; + String unitSymbol; + + _ItemBean(this.name, this.symbol, this.unit, this.unitName, this.unitSymbol); +} + diff --git a/lib/views/widgets/StatefulWidget/TextField.dart b/lib/views/widgets/StatefulWidget/TextField.dart new file mode 100644 index 0000000..c3747a0 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/TextField.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +// { +// "widgetId": 54, +// "name": 'TextField基本用法', +// "priority": 1, +// "subtitle": +// "【controller】 : 控制器 【TextEditingController】\n" +// "【style】 : 文字样式 【TextStyle】\n" +// "【decoration】 : 装饰线 【InputDecoration】\n" +// "【onEditingComplete】 : 输入完成事件 【Function()】\n" +// "【onSubmitted】 : 提交事件 【Function(String)】\n" +// "【onChanged】 : 输入事件 【Function(String)】", +// } +class CustomTextField extends StatefulWidget { + @override + _CustomTextFieldState createState() => _CustomTextFieldState(); +} + +class _CustomTextFieldState extends State { + final FocusNode _focusNode = FocusNode(); + TextEditingController _controller; + + void initState() { + super.initState(); + _controller = TextEditingController(); + } + + @override + void dispose() { + _controller.dispose(); + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: 300, + child: TextField( + controller: _controller, + style: TextStyle(color: Colors.blue), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'username', + ), + onEditingComplete: () { + print('onEditingComplete'); + }, + onChanged: (v) { + print('onChanged:' + v); + }, + onSubmitted: (v) { + FocusScope.of(context).requestFocus(_focusNode); + print('onSubmitted:' + v); + _controller.clear(); + }, + )); + } +} + +// { +// "widgetId": 54, +// "name": 'TextField基本语法', +// "priority": 2, +// "subtitle": +// "【minLines】 : 最小行数 【int】\n" +// "【maxLines】 : 最大行数 【int】\n" +// "【cursorRadius】 : 光标半径 【Radius】\n" +// "【cursorColor】 : 光标颜色 【Color】\n" +// "【cursorWidth】 : 光标宽度 【double】\n" +// "【showCursor】 : 是否显示光标 【bool】\n" +// "【autofocus】 : 自动聚焦 【bool】", +// } +class CursorTextField extends StatefulWidget { + @override + _CursorTextFieldState createState() => _CursorTextFieldState(); +} + +class _CursorTextFieldState extends State { + final FocusNode _focusNode = FocusNode(); + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + _buildSubmitBtn(), + _buildTextField(context), + ], + ); + } + + Container _buildTextField(BuildContext context) { + return Container( + width: 300, + child: TextField( + style: TextStyle(color: Colors.blue), + minLines: 3, + maxLines: 5, + cursorColor: Colors.green, + cursorRadius: Radius.circular(3), + cursorWidth: 5, + showCursor: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(10), + hintText: "请输入...", + border: OutlineInputBorder(), + ), + onChanged: (v) {}, + ), + ); + } + + _buildSubmitBtn() => FlatButton( + color: Colors.blue, + child: Text( + "提交", + style: TextStyle(color: Colors.white, fontSize: 16), + ), + onPressed: () => FocusScope.of(context).requestFocus(_focusNode)); +} + +// { +// "widgetId": 54, +// "name": 'decoration的复杂装饰', +// "priority": 3, +// "subtitle": +// "InputDecoration有非常多的装饰点,对应点缀见代码:\n" +// "border: 边线相关\n" +// "helper: 左下角相关提示\n" +// "counter: 右下角相关提示\n" +// "prefix: 输入框内部最左侧\n" +// "suffix: 输入框内部最右侧\n" +// "label: 无焦点时文字\n" +// "label: 无焦点时文字\n" +// "hint: 提示文字相关\n" +// "border: 边线相关", +// } +class ComplexTextField extends StatelessWidget { + @override + Widget build(BuildContext context) { + return TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blue), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), bottomLeft: Radius.circular(10))), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.deepPurpleAccent), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), bottomLeft: Radius.circular(10))), + labelText: 'username', + labelStyle: TextStyle(color: Colors.purple), + helperText: "help me", + helperStyle: TextStyle(color: Colors.blue), + + suffixText: "suffix", + suffixIcon: Icon(Icons.done), + suffixStyle: TextStyle(color: Colors.green), + + counterText: "counter", + counterStyle: TextStyle(color: Colors.orange), + + prefixText: "ID ", + prefixStyle: TextStyle(color: Colors.blue), + prefixIcon: Icon(Icons.language), + + fillColor: Color(0x110099ee), + filled: true, + + // errorText: "error", + // errorMaxLines: 1, + // errorStyle: TextStyle(color: Colors.red), + // errorBorder: UnderlineInputBorder(), + + hintText: "请输入用户名", + hintMaxLines: 1, + hintStyle: TextStyle(color: Colors.black38), + icon: Icon(Icons.assignment_ind), + )); + } +} diff --git a/lib/views/widgets/StatefulWidget/TextFormField.dart b/lib/views/widgets/StatefulWidget/TextFormField.dart new file mode 100644 index 0000000..97d1f02 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/TextFormField.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-04-01 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 199, +// "name": 'TextFormField基本使用', +// "priority": 1, +// "subtitle": +// " 基本属性和TextField一致,详见之\n" +// "【validator】 : 验证函数 【FormFieldValidator 】\n" +// "【onFieldSubmitted】 : 提交回调 【ValueChanged】\n" +// "【onSaved】 : 表单save时回调 【FormFieldSetter】", +// } +class CustomTextFormField extends StatefulWidget { + @override + _CustomTextFormFieldState createState() => _CustomTextFormFieldState(); +} + +class _CustomTextFormFieldState extends State { + GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Container( + child: Form( + key: _formKey, + child: + Stack( + alignment: Alignment.centerRight, + children: [ + Container( + width: 350, + child: UnconstrainedBox( + child: Container( + width: 200, + height: 70, + child: TextFormField( + style: TextStyle(textBaseline: TextBaseline.alphabetic), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'username', + ), + validator: _validateUsername, + onFieldSubmitted: _onFieldSubmitted, + onSaved: _onSaved, + ), + ), + ), + ), + Positioned( + top: 0, right: 0, child: _buildSubmitButton(context)), + ], + ), + ), + ); + } + + String _validateUsername(value) { + if (value.isEmpty) { + return '用户名不能为空'; + } + return null; + } + _onSaved(value){ + print('onSaved:'+value); + } + + void _onFieldSubmitted(value) { + print('onFieldSubmitted:'+value); + } + + RaisedButton _buildSubmitButton(BuildContext context) { + return RaisedButton( + color: Colors.blue, + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onPressed: _onSubmit, + child: Icon( + Icons.check, + color: Colors.white, + ), + ); + } + + _onSubmit(){ + _formKey.currentState.save(); + if (_formKey.currentState.validate()) { + FocusScope.of(context).requestFocus(FocusNode()); + } + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatefulWidget/Tooltip.dart b/lib/views/widgets/StatefulWidget/Tooltip.dart new file mode 100644 index 0000000..cd9f771 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/Tooltip.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; + +// { +// "widgetId": 50, +// "name": 'Tooltip基本使用', +// "priority": 1, +// "subtitle": +// "【preferBelow】 : 是否首选下方 【bool】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】\n" +// "【margin】 : 外边距 【EdgeInsetsGeometry】\n" +// "【message】 : 消息内容 【String】\n" +// "【showDuration】 : 展示时间 【Duration】\n" +// "【waitDuration】 : 悬浮出现时间 【Duration】\n" +// "【child】 : 孩子 【Widget】" +// } +class CustomTooltip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Tooltip( + preferBelow: true, + padding: EdgeInsets.all(5), + margin: EdgeInsets.all(5), + message: "天王盖地虎", + showDuration: Duration(seconds: 3), + waitDuration: Duration(milliseconds: 200), + child: Icon(Icons.info_outline), + ); + } +} + +// { +// "widgetId": 50, +// "name": 'Tooltip的装饰', +// "priority": 2, +// "subtitle": +// "【decoration】 : 装饰对象 【Decoration】\n" +// "【textStyle】 : 文字样式 【double】" +// } +class DecorationTooltip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Tooltip( + preferBelow: false, + padding: EdgeInsets.all(5), + margin: EdgeInsets.all(2), + message: "宝塔镇河妖", + textStyle: TextStyle( + color: Colors.red, + shadows: [Shadow(color: Colors.white, + offset: Offset(1, 1))]), + decoration: BoxDecoration(boxShadow: [ + BoxShadow( + color: Colors.orangeAccent, + offset: Offset(1, 1), blurRadius: 8) + ]), + child: Icon(Icons.info_outline)); + } +} diff --git a/lib/views/widgets/StatefulWidget/stateful_unit.dart b/lib/views/widgets/StatefulWidget/stateful_unit.dart new file mode 100644 index 0000000..efabb81 --- /dev/null +++ b/lib/views/widgets/StatefulWidget/stateful_unit.dart @@ -0,0 +1,74 @@ +library stateful_unit; + +export 'AppBar.dart'; +export 'BottomAppBar.dart'; +export 'BottomNavigationBar.dart'; +export 'Checkbox.dart'; +export 'ExpandIcon.dart'; +export 'ExpansionTile.dart'; +export 'Radio.dart'; +export 'Tooltip.dart'; +export 'CircularProgressIndicator.dart'; +export 'CupertinoActivityIndicator.dart'; +export 'CupertinoSlider.dart'; +export 'CupertinoSwitch.dart'; +export 'Image.dart'; +export 'RangerSlider.dart'; +export 'Slider.dart'; +export 'Switch.dart'; +export 'TextField.dart'; +export 'RefreshIndicator.dart'; +export 'SelectableText.dart'; +export 'CupertinoNavigationBar.dart'; +export 'CupertinoTabBar.dart'; +export 'DropdownButton.dart'; + +export 'AnimatedCrossFade.dart'; +export 'AnimatedList.dart'; +export 'AnimatedSwitcher.dart'; +export 'AnimatedWidget/AlignTransition.dart'; +export 'AnimatedWidget/DecoratedBoxTransition.dart'; +export 'AnimatedWidget/DefaultTextStyleTransition.dart'; +export 'AnimatedWidget/RelativePositionedTransition.dart'; +export 'CupertinoScrollbar.dart'; +export '../StatelessWidget/DataTable.dart'; +export 'Dismissible.dart'; +export 'DragTarget.dart'; +export 'Draggable.dart'; +export 'ExpansionPanelList.dart'; +export 'Form.dart'; +export 'FutureBuilder.dart'; +export 'Hero.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedAlign.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedContainer.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedDefaultTextStyle.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedOpacity.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedPadding.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedPositioned.dart'; +export 'ImplicitlyAnimatedWidget/AnimatedPositionedDirectional.dart'; +export 'Ink.dart'; +export 'InkResponse.dart'; +export 'InkWell.dart'; +export 'LicensePage.dart'; +export 'ListWheelScrollView.dart'; +export 'LongPressDraggable.dart'; +export 'Material.dart'; +export 'Overlay.dart'; +export 'PageView.dart'; +export 'PopupMenuButton.dart'; +export 'PopupMenuDivider.dart'; +export 'RawChip.dart'; +export 'RawMaterialButton.dart'; +export 'ReorderableListView.dart'; +export 'Scrollbar.dart'; +export 'Stepper.dart'; +export 'StreamBuilder.dart'; +export 'TableRowInkWell.dart'; +export 'TextFormField.dart'; +export 'LinearProgressIndicator.dart'; +export 'CupertinoApp.dart'; +export 'CupertinoPageScaffold.dart'; +export 'CupertinoTabScaffold.dart'; +export 'MaterialApp.dart'; +export 'Scaffold.dart'; +export 'TabBarView.dart'; \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/AboutDialog.dart b/lib/views/widgets/StatelessWidget/AboutDialog.dart new file mode 100644 index 0000000..aee35c2 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/AboutDialog.dart @@ -0,0 +1,72 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-24 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 130, +// "name": 'AboutDialog基本使用', +// "priority": 1, +// "subtitle": +// "【applicationIcon】 : 左上图标 【Widget】\n" +// "【applicationVersion】 : 版本号 【String】\n" +// "【applicationName】 : 应用名 【String】\n" +// "【applicationLegalese】 : 应用律术 【String】\n" +// "【children】 : 子组件列表 【List】", +// } +class CustomAboutDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + _buildAboutDialog(), + Positioned( + top: 50, + right: 20, + child: _buildRaisedButton(context)), + + ], + ); + } + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog(context: context, builder: (ctx) => _buildAboutDialog()); + }, + child: Text( + 'Just Show It', + style: TextStyle(color: Colors.white), + ), + ); + + AboutDialog _buildAboutDialog() { + return AboutDialog( + applicationIcon: FlutterLogo(), + applicationVersion: 'v0.0.1', + applicationName: 'Flutter Unit', + applicationLegalese: 'Copyright© 2018-2020 张风捷特烈', + children: [ + Container( + margin: EdgeInsets.only(top: 20), + width: 80, + height: 80, + child: Image.asset('assets/images/icon_head.png')), + Container( + margin: EdgeInsets.only(top: 10), + alignment: Alignment.center, + child: Text( + 'The King Of Coder.', + style: TextStyle(color: Colors.white, fontSize: 20, shadows: [ + Shadow( + color: Colors.blue, offset: Offset(.5, .5), blurRadius: 3) + ]), + )) + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/AboutListTile.dart b/lib/views/widgets/StatelessWidget/AboutListTile.dart new file mode 100644 index 0000000..fde88cf --- /dev/null +++ b/lib/views/widgets/StatelessWidget/AboutListTile.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-31 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 193, +// "name": 'AboutListTile基本使用', +// "priority": 1, +// "subtitle": +// "【icon】 : 左图标 【Widget】\n" +// "【applicationIcon】 : 左上图标 【Widget】\n" +// "【applicationVersion】 : 版本号 【String】\n" +// "【applicationName】 : 应用名 【String】\n" +// "【applicationLegalese】 : 应用律术 【String】\n" +// "【aboutBoxChildren】 : 弹框内容组件 【List】", +// } +class AboutListTileDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AboutListTile( + icon: Icon(Icons.info), + applicationIcon: FlutterLogo(), + applicationName: 'Flutter Unit', + applicationVersion: 'v0.0.1', + applicationLegalese: 'Copyright© 2018-2020 张风捷特烈', + aboutBoxChildren: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + ' FlutterUnit是【张风捷特烈】的开源项目,' + '收录Flutter的200+组件,并附加详细介绍以及操作交互,' + '希望帮助广大编程爱好者入门Flutter。' + '更多知识可以关注掘金账号、公众号【编程之王】。', + style: TextStyle(color: Color(0xff999999), fontSize: 16), + textAlign: TextAlign.justify, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/ActionChip.dart b/lib/views/widgets/StatelessWidget/ActionChip.dart new file mode 100644 index 0000000..ce775e7 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ActionChip.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + + +class CustomActionChip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ActionChip( + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + label: Text("This is a ActionChip."), + backgroundColor: Colors.grey.withAlpha(66), + avatar: Image.asset("assets/images/icon_head.png"), + shadowColor: Colors.orangeAccent, + elevation: 3, + pressElevation: 5, + onPressed: ()=> DialogAbout.show(context), + ); + } +} + diff --git a/lib/views/widgets/StatelessWidget/AlertDialog.dart b/lib/views/widgets/StatelessWidget/AlertDialog.dart new file mode 100644 index 0000000..3f4b287 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/AlertDialog.dart @@ -0,0 +1,109 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-24 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 127, +// "name": 'AlertDialog基本使用', +// "priority": 1, +// "subtitle": +// "【title】 : 顶部组件 【Widget】\n" +// "【content】 : 内容组件 【Widget】\n" +// "【titleTextStyle】 : 顶部文字样式 【TextStyle】\n" +// "【contentTextStyle】 : 内容文字样式 【TextStyle】\n" +// "【titlePadding】 : 顶部内边距 【EdgeInsetsGeometry】\n" +// "【contentPadding】 : 内容内边距 【EdgeInsetsGeometry】\n" +// "【actions】 : 右下角组件列表 【List】\n" +// "【backgroundColor】 : 右下角组件列表 【背景色】\n" +// "【elevation】 : 右下角组件列表 【背景色】\n" +// "【shape】 : 影深 【double】", +// } +class CustomAlertDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildRaisedButton(context), + _buildAlertDialog(), + ], + ); + } + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog(context: context, builder: (ctx) => _buildAlertDialog()); + }, + child: Text( + 'Just Show It !', + style: TextStyle(color: Colors.white), + ), + ); + + Widget _buildAlertDialog() { + return AlertDialog( + title: _buildTitle(), + titleTextStyle: TextStyle(fontSize: 20, color: Colors.black), + titlePadding: EdgeInsets.only( + top: 5, + left: 20, + ), + contentPadding: EdgeInsets.symmetric(horizontal: 5), + backgroundColor: Colors.white, + content: _buildContent(), + actions: [ + Icon(Icons.android, color: Colors.blue,), + Icon(Icons.add, color: Colors.blue,), + Icon(Icons.g_translate, color: Colors.blue,), + Icon(Icons.games, color: Colors.blue,), + ], + elevation: 4, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + ); + } + + Widget _buildTitle() { + return Row( + //标题 + children: [ + Image.asset( + "assets/images/icon_head.png", + width: 30, + height: 30, + ), + SizedBox(width: 10,), + Expanded( + child: Text( + "关于", + style: TextStyle(fontSize: 18), + )), + CloseButton() + ], + ); + } + + Widget _buildContent() { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + ' FlutterUnit是【张风捷特烈】的开源项目,' + '收录Flutter的200+组件,并附加详细介绍以及操作交互,' + '希望帮助广大编程爱好者入门Flutter。' + '更多知识可以关注掘金账号、公众号【编程之王】。', + style: TextStyle(color: Color(0xff999999), fontSize: 16), + textAlign: TextAlign.justify, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/AnimatedIcon.dart b/lib/views/widgets/StatelessWidget/AnimatedIcon.dart new file mode 100644 index 0000000..b17abbe --- /dev/null +++ b/lib/views/widgets/StatelessWidget/AnimatedIcon.dart @@ -0,0 +1,69 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// { +// "widgetId": 125, +// "name": 'AnimatedIcon基本使用', +// "priority": 1, +// "subtitle": +// "【icon】 : 动画图标数据 【AnimatedIcons】\n" +// "【size】 : 大小 【double】\n" +// "【color】 : 颜色 【Color】\n" +// "【progress】 : 动画 【Animation】", +// } +class CustomAnimatedIcon extends StatefulWidget { + @override + _CustomAnimatedIconState createState() => _CustomAnimatedIconState(); +} + +class _CustomAnimatedIconState extends State + with SingleTickerProviderStateMixin { + AnimationController _ctrl; + + @override + void initState() { + _ctrl = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _ctrl.forward(); + super.initState(); + } + + @override + void dispose() { + _ctrl.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() { + _ctrl.reset(); + _ctrl.forward(); + }); + }, + child: Wrap( + runSpacing: 30, + children: _buildChildren(), + ), + ); + } + + final data = { + Colors.orange: AnimatedIcons.menu_arrow, + Colors.blue: AnimatedIcons.ellipsis_search, + Colors.red: AnimatedIcons.close_menu, + Colors.green: AnimatedIcons.arrow_menu, + Colors.cyanAccent: AnimatedIcons.play_pause, + Colors.purple: AnimatedIcons.pause_play, + }; + + List _buildChildren() => data.keys + .map((e) => AnimatedIcon( + size: 50, + color: e, + icon: data[e], + progress: _ctrl, + )) + .toList(); +} diff --git a/lib/views/widgets/StatelessWidget/BackButton.dart b/lib/views/widgets/StatelessWidget/BackButton.dart new file mode 100755 index 0000000..476b383 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/BackButton.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + + +class CustomBackButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = [Colors.red,Colors.yellow,Colors.blue,Colors.green]; + return Wrap( + spacing: 10, + children: data.map((e)=>BackButton( + color: e, + )).toList() + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Banner.dart b/lib/views/widgets/StatelessWidget/Banner.dart new file mode 100644 index 0000000..11522a3 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Banner.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class CustomBanner extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + BannerLocation.topStart: Colors.red, + BannerLocation.topEnd: Colors.blue, + BannerLocation.bottomStart: Colors.green, + BannerLocation.bottomEnd: Colors.yellow, + }; + + return Wrap( + spacing: 10, + runSpacing: 10, + children: data.keys.map((e) => + Container( + color: Color(0xffD8F5FF), + width: 150, + height: 150 * 0.618, + child: Banner( + message: "Flutter 1.12发布", + location: e, + color: data[e], + child: Padding( + padding: EdgeInsets.all(20), + child: FlutterLogo(colors: Colors.blue, + style: FlutterLogoStyle.horizontal,)), + ), + )).toList()); + } +} diff --git a/lib/views/widgets/StatelessWidget/BottomSheet.dart b/lib/views/widgets/StatelessWidget/BottomSheet.dart new file mode 100644 index 0000000..5fa1589 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/BottomSheet.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 142, +// "name": 'BottomSheet基本使用', +// "priority": 1, +// "subtitle": +// "【builder】 : 组件构造器 【WidgetBuilder】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【elevation】 : 影深 【double】\n" +// "【shape】 : 形状 【ShapeBorder】\n" +// "【onClosing】 : 关闭回调 【Function()】", +// } +class CustomBottomSheet extends StatefulWidget { + @override + _CustomBottomSheetState createState() => _CustomBottomSheetState(); +} + +class _CustomBottomSheetState extends State { + bool opened = false; + + @override + Widget build(BuildContext context) { + return Container( + child: FlatButton( + color: Colors.blue, + onPressed: () { + opened = !opened; + opened + ? Scaffold.of(context) + .showBottomSheet((_) => _buildBottomSheet()) + : Navigator.of(context).pop(); + }, + child: Text( + '点我显隐BottomSheet', + style: TextStyle(color: Colors.white), + ))); + } + + Widget _buildBottomSheet() => BottomSheet( + enableDrag: true, + elevation: 4, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(60), + topLeft: Radius.circular(60), + ) + ), + backgroundColor: Colors.transparent, + onClosing: () => print('onClosing'), + builder: (_) => (Container( + height: 250, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/sabar_bar.jpg'), + fit: BoxFit.cover), + borderRadius: BorderRadius.only( + topRight: Radius.circular(60), + topLeft: Radius.circular(60), + )), + ))); +} diff --git a/lib/views/widgets/StatelessWidget/ButtonBar.dart b/lib/views/widgets/StatelessWidget/ButtonBar.dart new file mode 100755 index 0000000..09e22ac --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ButtonBar.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + + +class CustomButtonBar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ButtonBar( + alignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + child: Text("Raised"), + onPressed: () => DialogAbout.show(context)), + OutlineButton( + child: Text("Outline"), + onPressed: () => DialogAbout.show(context)), + FlatButton( + color: Colors.blue, + onPressed: () => DialogAbout.show(context), + child: Text("Flat"), + ) + ], + ); + } +} + +class PaddingButtonBar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ButtonBar( + alignment: MainAxisAlignment.center, + buttonHeight: 40, + buttonPadding: EdgeInsets.only(left: 15,right: 15), + children: [ + RaisedButton( + color: Colors.blue, + child: Text("Raised"), + onPressed: () => DialogAbout.show(context)), + OutlineButton( + child: Text("Outline"), + onPressed: () => DialogAbout.show(context)), + FlatButton( + color: Colors.blue, + onPressed: () => DialogAbout.show(context), + child: Text("Flat"), + ) + ], + ); + } +} + +//class AxisSizeButtonBar extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return ButtonBar( +// alignment: MainAxisAlignment.center, +// buttonHeight: 40, +// mainAxisSize: MainAxisSize.min, +// buttonPadding: EdgeInsets.only(left: 15,right: 15), +// children: [ +// RaisedButton( +// color: Colors.blue, +// child: Text("Raised"), +// onPressed: () => DialogAbout.show(context)), +// OutlineButton( +// child: Text("Outline"), +// onPressed: () => DialogAbout.show(context)), +// FlatButton( +// color: Colors.blue, +// onPressed: () => DialogAbout.show(context), +// child: Text("Flat"), +// ) +// ], +// ); +// } +//} + +//class ButtonBarPage extends StatelessWidget { +// ButtonBarPage({Key key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// var btnBar = ButtonBar( +// alignment: MainAxisAlignment.center, +// children: [RaisedButtonPage(), FloatingActionButtonPage(), CupertinoButtonPage()], +// ); +// return btnBar; +// } +//} diff --git a/lib/views/widgets/StatelessWidget/Card.dart b/lib/views/widgets/StatelessWidget/Card.dart new file mode 100644 index 0000000..963a644 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Card.dart @@ -0,0 +1,65 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/pather.dart'; + + +class CustomCard extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Card( + color: Color(0xffB3FE65), + elevation: 4, + margin: EdgeInsets.all(10), + child: Container( + alignment: Alignment.topLeft, + width: 200, + height: 0.618*200, + margin: EdgeInsets.all(10), + child: Text("Card", style: TextStyle(fontSize: 20)), + ), + ); + } +} + +class ShapeCard extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Card( + color: Color(0xffB3FE65), + elevation: 6, + shape: StarShapeBorder(), + child: Container( + alignment: Alignment.center, + width: 100, + height: 100, + child: Text("Card", style: TextStyle(fontSize: 20)), + ), + ); + } +} + + +class StarShapeBorder extends ShapeBorder { + @override + EdgeInsetsGeometry get dimensions => null; + + @override + Path getInnerPath(Rect rect, {TextDirection textDirection}) { + return null; + } + + @override + Path getOuterPath(Rect rect, {TextDirection textDirection}) => + Pather.create.nStarPath(9, 50, 40, dx: 50, dy: 50); + + @override + void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { + } + + @override + ShapeBorder scale(double t) { + return null; + } +} diff --git a/lib/views/widgets/StatelessWidget/CheckboxListTile.dart b/lib/views/widgets/StatelessWidget/CheckboxListTile.dart new file mode 100644 index 0000000..0ddbf04 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CheckboxListTile.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + + +class CustomCheckBoxListTile extends StatefulWidget { + @override + _CustomCheckBoxListTileState createState() => _CustomCheckBoxListTileState(); +} + +class _CustomCheckBoxListTileState extends State { + var _selected = false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: CheckboxListTile( + value: _selected, + checkColor: Colors.yellow, + activeColor: Colors.orangeAccent, + secondary: Image.asset("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _selected = !_selected), + ), + ); + } +} + +class SelectCheckBoxListTile extends StatefulWidget { + @override + _SelectCheckBoxListTileState createState() => _SelectCheckBoxListTileState(); +} + +class _SelectCheckBoxListTileState extends State { + var _selected = false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: CheckboxListTile( + value: _selected, + selected: _selected, + checkColor: Colors.yellow, + activeColor: Colors.orangeAccent, + secondary: Image.asset("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _selected = !_selected), + ), + ); + } +} + +class DenseCheckBoxListTile extends StatefulWidget { + @override + _DenseCheckBoxListTileState createState() => _DenseCheckBoxListTileState(); +} + +class _DenseCheckBoxListTileState extends State { + var _selected = false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: CheckboxListTile( + value: _selected, + dense: true, + checkColor: Colors.yellow, + activeColor: Colors.orangeAccent, + secondary: Image.asset("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _selected = !_selected), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/Chip.dart b/lib/views/widgets/StatelessWidget/Chip.dart new file mode 100644 index 0000000..93e206a --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Chip.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +class CustomChip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + children: [ + Chip( + avatar: Image.asset("assets/images/icon_head.png"), + label: Text("张风捷特烈"), + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(5), + ), + Chip( + avatar: CircleAvatar( + backgroundImage: + AssetImage("assets/images/wy_200x300.jpg")), + label: Text("百里巫缨"), + padding: EdgeInsets.all(8), + labelPadding: EdgeInsets.all(6), + ), + ], + ); + } +} + +class ColorOfChip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + children: [ + Chip( + avatar: Image.asset("assets/images/icon_head.png"), + label: Text("张风捷特烈"), + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(5), + backgroundColor: Colors.grey.withAlpha(66), + shadowColor: Colors.orangeAccent, + elevation: 3, + ), + Chip( + avatar: Image.asset("assets/images/icon_head.png"), + label: Text("张风捷特烈"), + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(5), + backgroundColor: Colors.cyanAccent.withAlpha(11), + shadowColor: Colors.blue.withAlpha(88), + elevation: 4, + ), + ], + ); + } +} + +class DeleteOfChip extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Chip( + avatar: Image.asset("assets/images/icon_head.png"), + label: Text("张风捷特烈"), + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + backgroundColor: Colors.grey.withAlpha(66), + shadowColor: Colors.orangeAccent, +// deleteIcon: Icon(Icons.close,size: 18), + deleteIconColor: Colors.red, + onDeleted: () => DialogAbout.show(context), + elevation: 3, + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/ChoiceChip.dart b/lib/views/widgets/StatelessWidget/ChoiceChip.dart new file mode 100644 index 0000000..c7bef32 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ChoiceChip.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + + +class CustomChoiceChip extends StatefulWidget { + @override + _CustomChoiceChipState createState() => _CustomChoiceChipState(); +} + +class _CustomChoiceChipState extends State { + bool _select = false; + + @override + Widget build(BuildContext context) { + return ChoiceChip( + selected: _select, + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(5), + label: Text( + _select ? + "You are selected it." : + "This is a ChoiceChip.", + style: TextStyle(fontSize: 16), + ), + backgroundColor: Colors.grey.withAlpha(66), + avatar: Image.asset("assets/images/icon_head.png"), + selectedColor: Colors.orangeAccent.withAlpha(44), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + elevation: 3, + onSelected: (value) => setState(() => _select = value), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/CircleAvatar.dart b/lib/views/widgets/StatelessWidget/CircleAvatar.dart new file mode 100644 index 0000000..41477d3 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CircleAvatar.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + + +class CustomCircleAvatar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CircleAvatar( + radius: 50, + backgroundImage: AssetImage("assets/images/wy_200x300.jpg"), + foregroundColor: Colors.white, + child: Icon( + Icons.check, + size: 50, + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CloseButton.dart b/lib/views/widgets/StatelessWidget/CloseButton.dart new file mode 100755 index 0000000..659ea8f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CloseButton.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + + +class CustomCloseButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CloseButton(); + } +} diff --git a/lib/views/widgets/StatelessWidget/Container.dart b/lib/views/widgets/StatelessWidget/Container.dart new file mode 100644 index 0000000..d01d83b --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Container.dart @@ -0,0 +1,114 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/res/cons.dart'; + +class CustomContainer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + width: 200, + height: 200 * 0.618, + color: Colors.red.withAlpha(88), + ); + } +} + +class ContainerWithChild extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.all(20), + margin: EdgeInsets.all(10), + width: 200, + height: 200 * 0.618, + color: Colors.grey.withAlpha(88), + child: Icon(Icons.android), + ); + } +} + +class ContainerAlignment extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.bottomRight, + width: 200, + height: 200 * 0.618, + color: Colors.grey.withAlpha(88), + child: Icon( + Icons.android, + color: Colors.green, + ), + ); + } +} + +class ContainerDecoration extends StatelessWidget { + @override + Widget build(BuildContext context) { + var stops = [0.0, 1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6, 1.0]; + return Container( + //容器 + alignment: Alignment.center, + width: 200, + height: 200 * 0.618, + margin: EdgeInsets.all(20), + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + //添加渐变色 + gradient: LinearGradient( + stops: stops, + colors: Cons.rainbow.map((e) => Color(e)).toList()), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(50), + bottomRight: Radius.circular(50)), + boxShadow: [ + BoxShadow( + color: Colors.grey, + offset: Offset(1, 1), + blurRadius: 10, + spreadRadius: 1), + ]), + child: Text( + "Container", + style: TextStyle(fontSize: 20), + ), + ); + } +} + +class ContainerTransform extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + //容器 + alignment: Alignment.center, + color: Colors.cyanAccent, + width: 150, + height: 150 * 0.618, + transform: Matrix4.skew(-pi / 10, 0), + child: Text( + "Container", + style: TextStyle(fontSize: 20), + ), + ); + } +} + +class ContainerConstraints extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + //容器 + color: Colors.blue, + width: 200, + height: 200 * 0.618, + constraints: BoxConstraints( + minWidth: 100, maxWidth: 150, + minHeight: 20, maxHeight: 100), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoActionSheet.dart b/lib/views/widgets/StatelessWidget/CupertinoActionSheet.dart new file mode 100644 index 0000000..054be09 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoActionSheet.dart @@ -0,0 +1,60 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 131, +// "name": 'CupertinoActionSheet基本使用', +// "priority": 1, +// "subtitle": +// "【title】 : 第一行组件 【Widget】\n" +// "【message】 : 第二行组件 【Widget】\n" +// "【cancelButton】 : 取消按钮处组件 【Widget】\n" +// "【actions】 : 中间组件列表 【List】", +// } +class CustomCupertinoActionSheet extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildRaisedButton(context), + _buildCupertinoActionSheet(context), + ], + ); + } + + Widget _buildCupertinoActionSheet(BuildContext context) => + Container( + alignment: Alignment.bottomCenter, + child: CupertinoActionSheet( + title: Text("Please chose a language"), + message: Text('the language you use in this application.'), + cancelButton: CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context), child: Text("Cancel")), + actions: [ + CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context), child: Text('Dart')), + CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context), child: Text('Java')), + CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context), child: Text('Kotlin')), + ], + ), + ); + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () => showDialog( + context: context, + builder: (ctx) => _buildCupertinoActionSheet(context)), + child: Text( + 'Just Show It !', + style: TextStyle(color: Colors.white), + ), + ); +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoActionSheetAction.dart b/lib/views/widgets/StatelessWidget/CupertinoActionSheetAction.dart new file mode 100644 index 0000000..9064b5c --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoActionSheetAction.dart @@ -0,0 +1,41 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 132, +// "name": 'CupertinoActionSheet基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【isDefaultAction】 : 是否默认选中 【bool】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class CustomCupertinoActionSheetAction extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + margin: EdgeInsets.all(5), + color: Colors.grey.withAlpha(33), + child: CupertinoActionSheetAction( + isDefaultAction: true, + onPressed: () => DialogAbout.show(context), + child: Text('张风捷特烈')), + ), + Container( + color: Colors.grey.withAlpha(33), + margin: EdgeInsets.all(5), + child: CupertinoActionSheetAction( + isDefaultAction: false, + onPressed: () => DialogAbout.show(context), + child: Text('百里·巫缨')), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoAlertDialog.dart b/lib/views/widgets/StatelessWidget/CupertinoAlertDialog.dart new file mode 100644 index 0000000..6814b16 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoAlertDialog.dart @@ -0,0 +1,97 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-24 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 129, +// "name": 'CupertinoAlertDialog基本使用', +// "priority": 1, +// "subtitle": +// "【title】 : 顶部组件 【Widget】\n" +// "【content】 : 内容组件 【Widget】\n" +// "【actions】 : 顶部文字样式 【List】", +// } +class CustomCupertinoAlertDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildRaisedButton(context), + _buildCupertinoAlertDialog(context), + ], + ); + } + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog( + context: context, + builder: (ctx) => _buildCupertinoAlertDialog(context)); + }, + child: Text( + 'Just Show It !', + style: TextStyle(color: Colors.white), + ), + ); + + Widget _buildCupertinoAlertDialog(BuildContext context) { + return Material( + color: Colors.transparent, + child: CupertinoAlertDialog( + title: _buildTitle(context), + content: _buildContent(), + actions: [ + CupertinoButton( + child: Text("Yes, Delete"), + onPressed: () => Navigator.pop(context), + ), + CupertinoButton( + child: Text("Cancle"), + onPressed: () => Navigator.pop(context), + ), + ]), + ); + } + + Widget _buildTitle(context) { + return Row( + //标题 + children: [ + Icon( + CupertinoIcons.delete_solid, + color: Colors.red, + ), + Expanded( + child: Text( + 'Delete File', + style: TextStyle(color: Colors.red, fontSize: 20), + )), + InkWell( + child: Icon(CupertinoIcons.clear_thick), + onTap: () => Navigator.pop(context), + ) + ]); + } + + Widget _buildContent() { + return Padding( + padding: const EdgeInsets.only(top: 18.0), + child: Column( + children: [ + Text( + ' Hi toly! If you push the conform buttom ,' + ' You will lose this file. Are you sure wand to do that?', + style: TextStyle(color: Color(0xff999999), fontSize: 16), + textAlign: TextAlign.justify, + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoButton.dart b/lib/views/widgets/StatelessWidget/CupertinoButton.dart new file mode 100755 index 0000000..290146a --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoButton.dart @@ -0,0 +1,27 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +class CustomCupertinoButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + CupertinoColors.activeBlue:4.0, + Colors.blue:6.0, + CupertinoColors.activeOrange:8.0, + }; + return Wrap( + spacing: 20, + children:data.keys.map((e)=> CupertinoButton( + padding: EdgeInsets.zero, + onPressed: () => DialogAbout.show(context), + color: e, + pressedOpacity: 0.4, + borderRadius: BorderRadius.all(Radius.circular(data[e])), + child: Text("iOS"), + )).toList() + ); + } +} + diff --git a/lib/views/widgets/StatelessWidget/CupertinoContextMenu.dart b/lib/views/widgets/StatelessWidget/CupertinoContextMenu.dart new file mode 100644 index 0000000..14c3fd6 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoContextMenu.dart @@ -0,0 +1,47 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 143, +// "name": 'CupertinoContextMenu基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【actions】 : 行为组件集 【List】\n" +// "【previewBuilder】 : 动画构造器 【ContextMenuPreviewBuilder】", +// } +class CustomCupertinoContextMenu extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: _buildCupertinoContextMenu(context), + ); + } + + final info= ['保存图片','立刻呼叫','添加到收藏夹']; + + Widget _buildCupertinoContextMenu(context) => Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/sabar_bar.jpg'), + fit: BoxFit.cover), + borderRadius: BorderRadius.all(Radius.circular(50))), + width: 100, + height: 100, + child: CupertinoContextMenu( + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/sabar_bar.jpg'), + fit: BoxFit.cover), + borderRadius: BorderRadius.all(Radius.circular(50))), + ), + actions: info.map((e)=>CupertinoContextMenuAction( + child: Center(child: Text(e)), + onPressed: () => Navigator.pop(context), + )).toList()) + ); +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoContextMenuAction.dart b/lib/views/widgets/StatelessWidget/CupertinoContextMenuAction.dart new file mode 100644 index 0000000..98eac37 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoContextMenuAction.dart @@ -0,0 +1,44 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 144, +// "name": 'CupertinoContextMenuAction基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【isDefaultAction】 : 是否默认选中 【bool】\n" +// "【trailingIcon】 : 尾部 【bool】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class CustomCupertinoContextMenuAction extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + width: 200, + margin: EdgeInsets.all(5), + child: CupertinoContextMenuAction( + trailingIcon: CupertinoIcons.settings, + isDefaultAction: true, + onPressed: () => DialogAbout.show(context), + child: Text('张风捷特烈')), + ), + Container( + width: 200, + margin: EdgeInsets.all(5), + child: CupertinoContextMenuAction( + trailingIcon: CupertinoIcons.home, + isDefaultAction: false, + onPressed: () => DialogAbout.show(context), + child: Text('百里·巫缨')), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoDatePicker.dart b/lib/views/widgets/StatelessWidget/CupertinoDatePicker.dart new file mode 100644 index 0000000..25a87df --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoDatePicker.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 137, +// "name": 'CupertinoDatePicker基本使用', +// "priority": 1, +// "subtitle": +// "【initialDateTime】 : 初始日期 【DateTime】\n" +// "【minimumYear】 : 最小年份 【int】\n" +// "【maximumYear】 : 最大年份 【int】\n" +// "【onDateTimeChanged】 : 点击回调 【Function(DateTime)】\n" +// "【minuteInterval】 : 分钟间隔 【int】\n" +// "【use24hFormat】 : 是否是24小时制 【bool】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【mode】 : 模式*3 【CupertinoDatePickerMode】", +// } +class CustomCupertinoDatePicker extends StatefulWidget { + @override + _CustomCupertinoDatePickerState createState() => + _CustomCupertinoDatePickerState(); +} + +class _CustomCupertinoDatePickerState extends State { + DateTime _date = DateTime.now(); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text( + '当前日期:${_date.toIso8601String()}', + style: TextStyle(color: Colors.grey, fontSize: 16), + ), + _buildInfoTitle('CupertinoDatePickerMode.dateAndTime'), + buildPicker(CupertinoDatePickerMode.dateAndTime), + _buildInfoTitle('CupertinoDatePickerMode.date'), + buildPicker(CupertinoDatePickerMode.date), + _buildInfoTitle('CupertinoDatePickerMode.time'), + buildPicker(CupertinoDatePickerMode.time), + ], + ); + } + + Container buildPicker(CupertinoDatePickerMode mode) { + return Container( + margin: EdgeInsets.all(10), + height: 150, + child: CupertinoDatePicker( + mode: mode, + initialDateTime: DateTime.now(), +// maximumDate: DateTime(2018,8,8), +// minimumDate: DateTime(2030,8,8), + minimumYear: 2018, + maximumYear: 2030, + use24hFormat: false, + minuteInterval: 1, + backgroundColor: CupertinoColors.white, + onDateTimeChanged: (date) { + print(date); + setState(() => _date = date); + }, + ), + ); + } + + Widget _buildInfoTitle(info){ + return Padding( + padding: const EdgeInsets.only(left: 20,top: 20,bottom: 5), + child: Text( + info, + style: TextStyle(color: Colors.blue, fontSize: 16,fontWeight: FontWeight.bold), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoDialogAction.dart b/lib/views/widgets/StatelessWidget/CupertinoDialogAction.dart new file mode 100644 index 0000000..2b94e5d --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoDialogAction.dart @@ -0,0 +1,126 @@ +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CustomDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildRaisedButton(context), + _buildDialog(), + ], + ); + } + + Widget _buildDialog() => CupertinoDialogAction( + onPressed: (){ + + }, + child: Container( + width: 50, + child: DeleteDialog(), + ), + ); + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog(context: context, builder: (ctx) => _buildDialog()); + }, + child: Text( + 'Just Show It !', + style: TextStyle(color: Colors.white), + ), + + ); +} + +class DeleteDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildBar(context), + _buildTitle(), + _buildContent(), + _buildFooter(context), + ], + ), + ); + } + + Widget _buildTitle() { + return Text( + 'Delete Doucument', + style: TextStyle(color: Color(0xff5CC5E9), fontSize: 24), + ); + } + + Widget _buildContent() { + return Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + ' Hi toly! If you push the conform buttom ,' + ' You will lose this file. Are you sure wand to do that?', + style: TextStyle(color: Color(0xffCFCFCF), fontSize: 16), + textAlign: TextAlign.justify, + ), + ); + } + + Widget _buildFooter(context) { + return Padding( + padding: const EdgeInsets.only(bottom: 15.0, top: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + alignment: Alignment.center, + height: 40, + width: 120, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30)), + color: Color(0xff73D1EE)), + child: Text('Yes, Delete', + style: TextStyle(color: Colors.white, fontSize: 16)), + ), + InkWell( + onTap: ()=>Navigator.of(context).pop(), + child: Container( + alignment: Alignment.center, + height: 40, + width: 120, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30)), + color: Colors.orangeAccent), + child: Text('Cancle', + style: TextStyle(color: Colors.white, fontSize: 16)), + ), + ) + ], + ), + ); + } + + _buildBar(context) => Container( + height: 30, + alignment: Alignment.centerRight, + margin: EdgeInsets.only(right: 10, top: 5), + child: InkWell( + onTap: ()=>Navigator.of(context).pop(), + child: Icon( + Icons.close, + color: Color(0xff82CAE3), + ), + ), + ); +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoPicker.dart b/lib/views/widgets/StatelessWidget/CupertinoPicker.dart new file mode 100644 index 0000000..ac70297 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoPicker.dart @@ -0,0 +1,50 @@ +import 'package:flutter/cupertino.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 139, +// "name": 'CupertinoPicker基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【offAxisFraction】 : 轴偏移率 【double】\n" +// "【squeeze】 : 挤压率 【double】\n" +// "【diameterRatio】 : 高与圆柱直径比率 【double】\n" +// "【itemExtent】 : 间距 【double】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【onSelectedItemChanged】 : 选中事件 【Function(int)】", +// } +class CustomCupertinoPicker extends StatelessWidget { + final names = [ + 'Java', + 'Kotlin', + 'Dart', + 'Swift', + 'C++', + 'Python', + "JavaScript", + "PHP", + "Go", + "Object-c" + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 150, + child: CupertinoPicker( + backgroundColor: CupertinoColors.systemGrey.withAlpha(33), + diameterRatio: 1, + offAxisFraction: 0.4, + squeeze: 1.5, + itemExtent: 40, + onSelectedItemChanged: (position) { + print('当前条目 ${names[position]}'); + }, + children: names.map((e) => Center(child: Text(e))).toList()), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoSegmentedControlTest.dart b/lib/views/widgets/StatelessWidget/CupertinoSegmentedControlTest.dart new file mode 100755 index 0000000..e1e5607 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoSegmentedControlTest.dart @@ -0,0 +1,60 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; + + +//class CupertinoButtonTest extends StatelessWidget { +// CupertinoButtonTest({Key key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// return CupertinoSegmentedControl( +// onValueChanged: (v) { +// print(object) +// }, +// pressedColor: Color(0xff7c1c25), +// borderColor: Color(0xffac172a), +// selectedColor: Color(0xffac172a), +// groupValue: value, +// children: { +// 'a': Container( +// alignment: Alignment.center, +// width: 130.0, +// child: Text('a') +// ), +// 'c': Text('C'), +// 'b': Text('B'), +// }, +// ); +//} +// +class CupertinoSegmentedControlTest extends StatefulWidget { + _Demo createState() => _Demo(); +} + +class _Demo extends State { + String value = 'Java'; + @override + Widget build(BuildContext context) { + return CupertinoSegmentedControl( + onValueChanged: (v) { + this.setState(() { + value = v; + }); + }, + pressedColor: CupertinoColors.activeGreen,//点击时颜色 + borderColor: CupertinoColors.inactiveGray,//边框颜色 + selectedColor: CupertinoColors.activeBlue,//选中的颜色 + groupValue: value,//当前值 + children: {//对于组件 + 'Java': Container( + alignment: Alignment.center, + width: 100.0, + child: Text('Java') + ), + 'Kotlin': Text('Kotlin'), + 'Dart': Text('Dart'), + }, + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoTheme.dart b/lib/views/widgets/StatelessWidget/CupertinoTheme.dart new file mode 100644 index 0000000..7da2774 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoTheme.dart @@ -0,0 +1,102 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 168, +// "name": '文字样式-TextTheme', +// "priority": 1, +// "subtitle": +// "", +// } +class TextCupertinoTheme extends StatelessWidget { + @override + Widget build(BuildContext context) { + var queryData = CupertinoTheme.of(context).textTheme; + var styles = { + "tabLabelTextStyle: ": queryData.tabLabelTextStyle, + "actionTextStyle: ": queryData.actionTextStyle, + "navActionTextStyle: ": queryData.navActionTextStyle, + "textStyle: ": queryData.textStyle, + "navTitleTextStyle: ": queryData.navTitleTextStyle, + "pickerTextStyle: ": queryData.pickerTextStyle, + "dateTimePickerTextStyle: ": queryData.dateTimePickerTextStyle, + "navLargeTitleTextStyle: ": queryData.navLargeTitleTextStyle, + }; + + return Container( + child: Column( + children: styles.keys.map((e) => buildItem(e, styles[e])).toList(), + ), + ); + } + + Widget buildItem(String e, TextStyle style) => Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + "@toly", + style: style, + ) + ], + ), + ), + Divider( + height: 1, + ) + ], + ); +} + +// { +// "widgetId": 169, +// "name": 'CupertinoThemeData的使用', +// "priority": 2, +// "subtitle": +// "和Theme一样可以通过指定的属性,让它们在后代中共享,不过属性较少。注意如果需要使用主题,不能在当前的context中获取。", +// } + +class CustomCupertinoTheme extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CupertinoTheme( + data: CupertinoThemeData( + primaryColor: Colors.blue, + primaryContrastingColor: Colors.green + ), + child: _ChildUseTheme()); + } +} + +class _ChildUseTheme extends StatelessWidget { + const _ChildUseTheme({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Container( + width: 50, + height: 50, + color: CupertinoTheme.of(context).primaryContrastingColor, + ), + Container( + width: 150, + child: Slider(value: 0.8, onChanged: (v) => {})), + Container( width: 150,child: Divider(color:CupertinoTheme.of(context).primaryContrastingColor,thickness: 1,)) + ]); + } +} diff --git a/lib/views/widgets/StatelessWidget/CupertinoTimerPicker.dart b/lib/views/widgets/StatelessWidget/CupertinoTimerPicker.dart new file mode 100644 index 0000000..0b6934b --- /dev/null +++ b/lib/views/widgets/StatelessWidget/CupertinoTimerPicker.dart @@ -0,0 +1,72 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 138, +// "name": 'CupertinoTimerPicker基本使用', +// "priority": 1, +// "subtitle": +// "【initialTimerDuration】 : 初始时间 【Duration】\n" +// "【minuteInterval】 : 分钟间隔数 【double】\n" +// "【secondInterval】 : 秒间隔数 【double】\n" +// "【alignment】 : 对齐方式 【AlignmentGeometry】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【mode】 : 模式*3 【CupertinoTimerPickerMode】", +// } +class CustomCupertinoTimerPicker extends StatefulWidget { + @override + _CustomCupertinoTimerPickerState createState() => + _CustomCupertinoTimerPickerState(); +} + +class _CustomCupertinoTimerPickerState + extends State { + Duration _date = Duration(seconds: 30); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text( + '当前时间:${_date.toString()}', + style: TextStyle(color: Colors.grey, fontSize: 16), + ), + _buildInfoTitle('CupertinoTimerPickerMode.hms'), + buildPicker(CupertinoTimerPickerMode.hms), + _buildInfoTitle('CupertinoTimerPickerMode.hm'), + buildPicker(CupertinoTimerPickerMode.hm), + _buildInfoTitle('CupertinoTimerPickerMode.ms'), + buildPicker(CupertinoTimerPickerMode.ms), + ], + ); + } + + Widget _buildInfoTitle(info) { + return Padding( + padding: const EdgeInsets.only(left: 20, top: 20, bottom: 5), + child: Text( + info, + style: TextStyle( + color: Colors.blue, fontSize: 16, fontWeight: FontWeight.bold), + ), + ); + } + + Widget buildPicker(CupertinoTimerPickerMode mode) { + return Container( + margin: EdgeInsets.all(10), + height: 150, + child: CupertinoTimerPicker( + mode: mode, + initialTimerDuration: Duration(seconds: 30), + onTimerDurationChanged: (date) { + print(date); + setState(() => _date = date); + }, + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/DataTable.dart b/lib/views/widgets/StatelessWidget/DataTable.dart new file mode 100644 index 0000000..f3b5476 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/DataTable.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-21 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 102, +// "name": 'DataTable基本使用', +// "priority": 1, +// "subtitle": +// "【columns】 : 列 【List】\n" +// "【rows】 : 行 【List】", +// } +class _Bean { + final int id; + final String name; + final String type; + + _Bean(this.id, this.name, this.type); +} + +class CustomDataTable extends StatelessWidget { + final data = [ + _Bean(101, 'DataTable', 'StatelessWidget'), + _Bean(44, 'RangeSlider', 'StatefulWidget'), + _Bean(2, 'Text', 'StatelessWidget'), + _Bean(1, 'Image', 'StatefulWidget'), + ]; + + final columns = ['id', '名称', '类型']; + + @override + Widget build(BuildContext context) { + return DataTable( + columns: columns.map((e) => DataColumn(label: Text(e))).toList(), + rows: data + .map((e) => DataRow(cells: [ + DataCell(Text('${e.id}')), + DataCell(Text('${e.name}')), + DataCell(Text('${e.type}')), + ])) + .toList()); + } +} + +// { +// "widgetId": 102, +// "name": 'DataTable的sort', +// "priority": 2, +// "subtitle": +// "【sortColumnIndex】 : 列号 【int】\n" +// "【columnSpacing】 : 列间距 【double】\n" +// "【sortAscending】 : 是否顺序 【bool】", +// } + +class _BeanOp { + final int id; + final String name; + final String type; + bool select; + + _BeanOp(this.id, this.name, this.type, this.select); + + @override + String toString() { + return '_BeanOp{id: $id, name: $name, type: $type, select: $select}'; + } +} + +class SortDataTable extends StatefulWidget { + @override + _SortDataTableState createState() => _SortDataTableState(); +} + +class _SortDataTableState extends State { + var data = [ + _BeanOp(101, 'DataTable', 'StatelessWidget', false), + _BeanOp(44, 'RangeSlider', 'StatefulWidget', false), + _BeanOp(2, 'Text', 'StatelessWidget', false), + _BeanOp(1, 'Image', 'StatefulWidget', false), + ]; + + bool _sortAscending = false; + var selectData = <_BeanOp>[]; + + @override + Widget build(BuildContext context) { + return DataTable( + columnSpacing: 20, + sortColumnIndex: 1, + sortAscending: _sortAscending, + columns: [ + DataColumn( + label: Container( + child: Checkbox( + value: selectData.length == data.length, + onChanged: _onSelectAll, + ), + ), + ), + DataColumn(label: Text('id'), numeric: false, onSort: _onSortId), + DataColumn(label: Text('名称')), + DataColumn(label: Text('类型')), + ], + rows: data + .map((e) => DataRow(selected: false, cells: [ + DataCell(Checkbox( + value: e.select, + onChanged: (v) => _onSelectOne(v, e), + )), + DataCell(Text('${e.id}')), + DataCell(Text('${e.name}'), + showEditIcon: true, onTap: () {}), + DataCell(Text('${e.type}')), + ])) + .toList()); + } + + _onSortId(int index, bool ascending) { + setState(() { + _sortAscending = ascending; + data.sort( + (a, b) => ascending ? a.id.compareTo(b.id) : b.id.compareTo(a.id)); + }); + } + + _onSelectOne(bool selected, _BeanOp e) { + setState(() { + if (selected) { + //选中 + selectData.add(e); + } else { + selectData.remove(e); + } + e.select = selected; + print(selectData); + }); + } + + _onSelectAll(bool select) { + setState(() { + if (select) { + data.forEach((e) => e.select = true); + selectData = data.map((e) => e).toList(); + } else { + data.forEach((e) => e.select = false); + selectData = []; + } + }); + } +} diff --git a/lib/views/widgets/StatelessWidget/DayPicker.dart b/lib/views/widgets/StatelessWidget/DayPicker.dart new file mode 100644 index 0000000..c529c0d --- /dev/null +++ b/lib/views/widgets/StatelessWidget/DayPicker.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 134, +// "name": 'DayPicker基本使用', +// "priority": 1, +// "subtitle": +// "【selectedDate】 : 选中日期 【DateTime】\n" +// "【currentDate】 : 当前日期 【DateTime】\n" +// "【firstDate】 : 最前日期限制 【DateTime】\n" +// "【lastDate】 : 最后日期限制 【DateTime】\n" +// "【displayedMonth】 : 当前展示的月份 【DateTime】\n" +// "【onChanged】 : 点击回调 【Function(DateTime)】", +// } +class CustomDayPicker extends StatefulWidget { + @override + _CustomDayPickerState createState() => _CustomDayPickerState(); +} + +class _CustomDayPickerState extends State { + + DateTime _date = DateTime.now(); + + @override + Widget build(BuildContext context) { + return Container( + height: 350, + child: DayPicker( + selectedDate: _date, + currentDate: DateTime.now(), + onChanged: (date){ + setState(() => _date = date); + }, + firstDate: DateTime(2018), + lastDate: DateTime(2030), + displayedMonth: DateTime.now() + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Dialog.dart b/lib/views/widgets/StatelessWidget/Dialog.dart new file mode 100644 index 0000000..14a3024 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Dialog.dart @@ -0,0 +1,137 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-24 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 126, +// "name": 'Dialog基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 动画图标数据 【Widget】\n" +// "【elevation】 : 影深 【double】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【shape】 : 形状 【ShapeBorder】", +// } +class CustomDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildRaisedButton(context), + _buildDialog(), + ], + ); + } + + Widget _buildDialog() => Dialog( + backgroundColor: Colors.white, + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + child: Container( + width: 50, + child: DeleteDialog(), + ), + ); + + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog(context: context, builder: (ctx) => _buildDialog()); + }, + child: Text( + 'Just Show It !', + style: TextStyle(color: Colors.white), + ), + + ); +} + +class DeleteDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildBar(context), + _buildTitle(), + _buildContent(), + _buildFooter(context), + ], + ), + ); + } + + Widget _buildTitle() { + return Text( + 'Delete Doucument', + style: TextStyle(color: Color(0xff5CC5E9), fontSize: 24), + ); + } + + Widget _buildContent() { + return Padding( + padding: const EdgeInsets.all(15.0), + child: Text( + ' Hi toly! If you push the conform buttom ,' + ' You will lose this file. Are you sure wand to do that?', + style: TextStyle(color: Color(0xffCFCFCF), fontSize: 16), + textAlign: TextAlign.justify, + ), + ); + } + + Widget _buildFooter(context) { + return Padding( + padding: const EdgeInsets.only(bottom: 15.0, top: 10,left: 10,right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + alignment: Alignment.center, + height: 40, + width: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30)), + color: Color(0xff73D1EE)), + child: Text('Yes', + style: TextStyle(color: Colors.white, fontSize: 16)), + ), + InkWell( + onTap: ()=>Navigator.of(context).pop(), + child: Container( + alignment: Alignment.center, + height: 40, + width: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30)), + color: Colors.orangeAccent), + child: Text('Cancle', + style: TextStyle(color: Colors.white, fontSize: 16)), + ), + ) + ], + ), + ); + } + + _buildBar(context) => Container( + height: 30, + alignment: Alignment.centerRight, + margin: EdgeInsets.only(right: 10, top: 5), + child: InkWell( + onTap: ()=>Navigator.of(context).pop(), + child: Icon( + Icons.close, + color: Color(0xff82CAE3), + ), + ), + ); +} diff --git a/lib/views/widgets/StatelessWidget/Divider.dart b/lib/views/widgets/StatelessWidget/Divider.dart new file mode 100644 index 0000000..8cad054 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Divider.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +class CustomDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + var dataColor = [ + Colors.red, Colors.yellow, + Colors.blue, Colors.green]; + var dataThickness = [1.0, 2.0, 4.0, 6.0]; + var data = Map.fromIterables(dataColor, dataThickness); + return Column( + children: dataColor + .map((e) => Divider( + color: e, + thickness: data[e], + )) + .toList(), + ); + } +} + +class HeightDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + var dataColor = [ + Colors.red, Colors.yellow, + Colors.blue, Colors.green]; + var dataThickness = [10.0, 20.0, 30.0, 40.0]; + var data = Map.fromIterables(dataColor, dataThickness); + return Column( + children: dataColor + .map((e) => Divider( + color: e, + indent:data[e], + endIndent: data[e]*2, + height: data[e], + thickness: data[e]/10, + )) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Drawer.dart b/lib/views/widgets/StatelessWidget/Drawer.dart new file mode 100644 index 0000000..0a865a5 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Drawer.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 154, +// "name": 'Drawer基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【elevation】 : 影深 【double】", +// } +class CustomDrawer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + height: 400, + child: Scaffold( + appBar: AppBar( + title: Text('Flutter Unit'), + ), + drawer: Drawer( + elevation: 3, + child: _buildChild(), + ), + ), + ); + } + + Widget _buildChild() => ListView( + padding: EdgeInsets.zero, + children: const [ + DrawerHeader( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/caver.jpeg'), + fit: BoxFit.cover), + ), + child: Text( + '张风捷特烈', + style: TextStyle(fontSize: 24, color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(1, 1), blurRadius: 3) + ]), + ), + ), + ListTile( + leading: Icon( + Icons.star, + color: Colors.blue, + ), + title: Text('我的收藏'), + ), + ListTile( + leading: Icon( + Icons.palette, + color: Colors.orangeAccent, + ), + title: Text('我的绘画'), + ), + ListTile( + leading: Icon( + Icons.insert_drive_file, + color: Colors.green, + ), + title: Text('我的文件'), + ), + ], + ); +} diff --git a/lib/views/widgets/StatelessWidget/DrawerHeader.dart b/lib/views/widgets/StatelessWidget/DrawerHeader.dart new file mode 100644 index 0000000..60b0fc7 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/DrawerHeader.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-26 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 155, +// "name": 'DrawerHeader基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【decoration】 : 装饰 【Decoration】\n" +// "【margin】 : 外边距 【EdgeInsetsGeometry】\n" +// "【padding】 : 内边距 【EdgeInsetsGeometry】", +// } +class CustomDrawerHeader extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + height: 400, + child: Scaffold( + appBar: AppBar( + title: Text('Flutter Unit'), + ), + drawer: Drawer( + elevation: 3, + child: _buildChild(), + ), + ), + ); + } + + Widget _buildChild() => ListView( + padding: EdgeInsets.zero, + children: [ + _buildHeader(), + ListTile( + leading: Icon( + Icons.star, + color: Colors.blue, + ), + title: Text('我的收藏'), + ), + ListTile( + leading: Icon( + Icons.palette, + color: Colors.orangeAccent, + ), + title: Text('我的绘画'), + ), + ListTile( + leading: Icon( + Icons.insert_drive_file, + color: Colors.green, + ), + title: Text('我的文件'), + ), + ], + ); + + Widget _buildHeader() { + return DrawerHeader( + margin: EdgeInsets.all(10), + padding: EdgeInsets.only(left: 20,top: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft:Radius.circular(40), + topRight:Radius.circular(40) + ), + image: DecorationImage( + image: AssetImage('assets/images/caver.jpeg'), + fit: BoxFit.cover), + ), + child: Text( + '张风捷特烈', + style: TextStyle(fontSize: 24, color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(1, 1), blurRadius: 3) + ]), + ), + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/FadeInImage.dart b/lib/views/widgets/StatelessWidget/FadeInImage.dart new file mode 100644 index 0000000..fb58a7f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/FadeInImage.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class CustomFadeInImage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var placeholder = "assets/images/icon_head.png"; + var img = + "https://user-gold-cdn.xitu.io/2017/8/24/" + "d324efef8cbee6468a018aad7ab2ba6b?imageView2/" + "1/w/180/h/180/q/85/format/webp/interlace/1"; + return FadeInImage.assetNetwork( + placeholder: placeholder, + image: img, + width: 100, + height: 100, + fit: BoxFit.cover, + repeat:ImageRepeat.noRepeat, + alignment: Alignment.center, + fadeInDuration: Duration(seconds: 5), + fadeInCurve: Curves.easeInCubic, + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/FilterChip.dart b/lib/views/widgets/StatelessWidget/FilterChip.dart new file mode 100644 index 0000000..12a0c5e --- /dev/null +++ b/lib/views/widgets/StatelessWidget/FilterChip.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; + +class CustomFilterChip extends StatefulWidget { + @override + _CustomFilterChipState createState() => _CustomFilterChipState(); +} + +class _CustomFilterChipState extends State { + final Map map = { + 'A': 'Ant', + 'B': 'Bug', + 'C': 'Cat', + 'D': 'Dog', + }; + List _selected = []; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Wrap( + children: map.keys.map((key) => + _buildChild(key)).toList(), + ), + Container( + padding: EdgeInsets.all(10), + child: Text('您已选择: ${_selected.join(', ')}')), + ], + ); + } + + Padding _buildChild(String key) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: FilterChip( + selectedColor: Colors.orange.withAlpha(55), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + pressElevation: 5, + elevation: 3, + avatar: CircleAvatar(child: Text(key)), + label: Text(map[key]), + selected: _selected.contains(map[key]), + onSelected: (bool value) { + setState(() { + if (value) { + _selected.add(map[key]); + } else { + _selected.removeWhere((name) => name == map[key]); + } + }); + }, + ), + ); + } +} + +//class FilterChipPage extends StatefulWidget { +// @override +// _FilterChipPageState createState() => _FilterChipPageState(); +//} +// +//class _FilterChipPageState extends State { +// +// final Map map = { +// 'A': 'Ant', +// 'B': 'Bug', +// 'C': 'Cat', +// 'D': 'Dog', +// }; +// +// List _filters = []; +// +// @override +// Widget build(BuildContext context) { +// return Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Wrap( +// children: map.keys.map((key) => _buildChild(key)).toList(), +// ), +// Text('您已选择: ${_filters.join(', ')}'), +// ], +// ); +// } +// +// Padding _buildChild(String key) { +// return Padding( +// padding: const EdgeInsets.all(4.0), +// child: FilterChip( +// selectedColor: Colors.orange.withAlpha(55), +// selectedShadowColor:Colors.blue , +// shadowColor: Colors.orangeAccent, +// elevation: 3, +// avatar: CircleAvatar(child: Text(key)), +// label: Text(map[key]), +// selected: _filters.contains(map[key]), +// onSelected: (bool value) { +// setState(() { +// if (value) { +// _filters.add(map[key]); +// } else { +// _filters.removeWhere((String name) => name == map[key]); +// } +// }); +// }, +// ), +// ); +// } +//} diff --git a/lib/views/widgets/StatelessWidget/FlatButton.dart b/lib/views/widgets/StatelessWidget/FlatButton.dart new file mode 100755 index 0000000..cd830b8 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/FlatButton.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class CustomFlatButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return FlatButton( + onPressed: ()=>{}, + padding: EdgeInsets.all(8), + splashColor: Colors.green, + child: Text("FlatButton"), + textColor: Color(0xffFfffff), + color: Colors.blue, + highlightColor: Color(0xffF88B0A), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/FloatingActionButton.dart b/lib/views/widgets/StatelessWidget/FloatingActionButton.dart new file mode 100755 index 0000000..2ee8a5e --- /dev/null +++ b/lib/views/widgets/StatelessWidget/FloatingActionButton.dart @@ -0,0 +1,103 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/pather.dart'; + +class CustomFAB extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + Colors.red: Icons.add, + Colors.blue: Icons.bluetooth, + Colors.green: Icons.android, + }; + return Wrap( + spacing: 20, + children: data.keys + .map((e) => FloatingActionButton( + heroTag: e.toString()+"a", + onPressed: () {}, + backgroundColor: e, + foregroundColor: Colors.white, + child: Icon(data[e]), + tooltip: "android", + elevation: 5, //z-阴影盖度 + )) + .toList()); + } +} + +class MiniFAB extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + Colors.red: Icons.add, + Colors.blue: Icons.bluetooth, + Colors.green: Icons.android, + }; + return Wrap( + spacing: 20, + children: data.keys + .map((e) => FloatingActionButton( + heroTag: e.toString()+"b", + onPressed: () {}, + backgroundColor: e, + mini: true, + foregroundColor: Colors.white, + child: Icon(data[e]), + tooltip: "android", + elevation: 5, //z-阴影盖度 + )) + .toList()); + } +} + +class ShapeFAB extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + Colors.red: Icons.add, + Colors.blue: Icons.bluetooth, + Colors.green: Icons.android, + }; + return Wrap( + spacing: 20, + children: data.keys + .map((e) => FloatingActionButton( + heroTag: e.toString()+"c", + onPressed: () {}, + backgroundColor: e, + shape: StarBorder(), + foregroundColor: Colors.white, + child: Icon(data[e]), + tooltip: "android", + elevation: 5, + )) + .toList()); + } +} + +/// 边线形状类 +class StarBorder extends ShapeBorder { + @override + EdgeInsetsGeometry get dimensions => null; + + @override + Path getInnerPath(Rect rect, {TextDirection textDirection}) { + return null; + } + + @override + Path getOuterPath(Rect rect, {TextDirection textDirection}) { + return Pather.create.nStarPath(20, 25, 25 * cos((360 / 9 / 2) * pi / 180), + dx: rect.height / 2, dy: rect.width / 2); + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {} + + @override + ShapeBorder scale(double t) { + return null; + } +} diff --git a/lib/views/widgets/StatelessWidget/FlutterLogo.dart b/lib/views/widgets/StatelessWidget/FlutterLogo.dart new file mode 100644 index 0000000..2be6ca0 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/FlutterLogo.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + +class CustomFlutterLogo extends StatelessWidget { + @override + Widget build(BuildContext context) { + + var data = { + Colors.blue:50.0, + Colors.red:60.0, + Colors.green:70.0, + Colors.yellow:80.0, + }; + return Wrap( + children: data.keys + .map((e) => FlutterLogo( + size: data[e], + colors: e, + )) + .toList(), + ); + } +} + +class FlutterLogoWithText extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + FlutterLogoStyle.horizontal:Colors.blue, + FlutterLogoStyle.markOnly:Colors.red, + FlutterLogoStyle.stacked:Colors.green, + }; + + return Wrap( + spacing: 20, + children: data.keys.map((e) => FlutterLogo( + size: 80, + style: e, + textColor: data[e], + )) + .toList(), + ); + } +} + diff --git a/lib/views/widgets/StatelessWidget/GestureDetector.dart b/lib/views/widgets/StatelessWidget/GestureDetector.dart new file mode 100644 index 0000000..c85b0f6 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GestureDetector.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 146, +// "name": 'GestureDetector基本事件', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onTap】 : 点击事件 【Function()】\n" +// "【onDoubleTap】 : 双击事件 【Function()】\n" +// "【onLongPress】 : 长按事件 【Function()】", +// } + +class CustomGestureDetector extends StatefulWidget { + @override + _CustomGestureDetectorState createState() => _CustomGestureDetectorState(); +} + +class _CustomGestureDetectorState extends State { + var _info = ''; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => setState(() => _info = 'onTap'), + onDoubleTap: () => setState(() => _info = 'onDoubleTap'), + onLongPress: () => setState(() => _info = 'onLongPress'), + child: Container( + alignment: Alignment.center, + width: 300, + height: 300 * 0.4, + color: Colors.grey.withAlpha(33), + child: Text( + _info, + style: TextStyle(fontSize: 18, color: Colors.blue), + ), + ), + ); + } +} + +// { +// "widgetId": 146, +// "name": 'GestureDetector详情信息', +// "priority": 2, +// "subtitle": +// "【onTapDown】 : 按下回调 【Function(TapDownDetails)】\n" +// "【onTapUp】 : 子组件 【Function(TapUpDetails)】\n" +// "【onTapCancel】 : 点击取消 【Function()】", +// } +class TapGestureDetector extends StatefulWidget { + @override + _TapGestureDetectorState createState() => _TapGestureDetectorState(); +} + +class _TapGestureDetectorState extends State { + var _info = ''; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (detail) => setState(() => _info = + 'onTapDown:\n相对落点:${detail.localPosition}\n绝对落点:${detail.globalPosition}'), + onTapUp: (detail) => setState(() => _info = + 'onTapUp:\n相对落点:${detail.localPosition}\n绝对落点:${detail.globalPosition}'), + onTapCancel: () => setState(() => _info = 'onTapCancel'), + child: Container( + alignment: Alignment.center, + width: 300, + height: 300 * 0.618, + color: Colors.grey.withAlpha(33), + child: Text( + _info, + style: TextStyle(fontSize: 18, color: Colors.blue), + ), + ), + ); + } +} + +// { +// "widgetId": 146, +// "name": 'GestureDetector的Pan事件', +// "priority": 3, +// "subtitle": +// "【onPanDown】 : 按下回调 【Function(DragDownDetails)】\n" +// "【onPanEnd】 : 拖动结束 【Function(DragEndDetails)】\n" +// "【onPanStart】 : 开始拖动 【Function(DragStartDetails)】\n" +// "【onPanUpdate】 : 拖动更新 【Function(TapUpDetails)】\n" +// "【onPanCancel】 : 拖动取消 【Function()】", +// } +class PanGestureDetector extends StatefulWidget { + @override + _PanGestureDetectorState createState() => _PanGestureDetectorState(); +} + +class _PanGestureDetectorState extends State { + var _info = ''; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onPanDown: (detail) => setState(() => _info = + 'onPanDown:\n相对落点:${detail.localPosition}\n绝对落点:${detail.globalPosition}'), + onPanEnd: (detail) => setState(() => _info = + 'onPanEnd:\n初速度:${detail.primaryVelocity}\n最终速度:${detail.velocity}'), + onPanUpdate: (detail) => setState(() => _info = + 'onPanUpdate:\n相对落点:${detail.localPosition}\n绝对落点:${detail.globalPosition}'), + onPanStart: (detail) => setState(() => _info = + 'onPanStart:\n相对落点:${detail.localPosition}\n绝对落点:${detail.globalPosition}'), + onPanCancel: () => setState(() => _info = 'onTapCancel'), + child: SingleChildScrollView( + child: Container( + alignment: Alignment.center, + width: 300, + height: 300 * 0.618, + color: Colors.grey.withAlpha(33), + child: Text( + _info, + style: TextStyle(fontSize: 18, color: Colors.blue), + ), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/GirdView.dart b/lib/views/widgets/StatelessWidget/GirdView.dart new file mode 100644 index 0000000..561f8da --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GirdView.dart @@ -0,0 +1,203 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-27 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 163, +// "name": 'GridView.count构造', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【crossAxisCount】 : 主轴一行box数量 【int】\n" +// "【mainAxisSpacing】 : 主轴每行间距 【double】\n" +// "【crossAxisSpacing】 : 交叉轴每行间距 【double】\n" +// "【childAspectRatio】 : box主长/交叉轴长 【double】\n" +// "【crossAxisCount】 : 主轴一行数量 【int】", +// } +class CustomGridView extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFFFF00FF - 2*i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: GridView.count( + crossAxisCount: 4, + mainAxisSpacing: 2, + crossAxisSpacing: 2, + childAspectRatio: 1/0.618, + children: data + .map((color) => _buildItem(color)) + .toList(), + ), + ); + } + + Container _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 30, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 163, +// "name": 'GridView滑动方向', +// "priority": 2, +// "subtitle": +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【reverse】 : 是否反向滑动 【bool】\n" +// "【shrinkWrap】 : 无边界时是否包裹 【bool】", +// } +class HorizontalGridView extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF00FFFF - 2*i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: GridView.count( + scrollDirection: Axis.horizontal, + reverse: true, + crossAxisCount: 4, + mainAxisSpacing: 2, + crossAxisSpacing: 2, + childAspectRatio: 0.618, + children: data + .map((color) => _buildItem(color)) + .toList(), + ), + ); + } + + Container _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 30, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} +// { +// "widgetId": 163, +// "name": 'GridView.extent构造', +// "priority": 3, +// "subtitle": +// "【maxCrossAxisExtent】 : box轴向长度 【double】\n" +// "【reverse】 : 是否反向滑动 【bool】\n" +// "【shrinkWrap】 : 无边界时是否包裹 【bool】", +// } +class ExtentGridView extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF00FFFF - 2*i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: GridView.extent( + scrollDirection: Axis.horizontal, + maxCrossAxisExtent: 80.0, + mainAxisSpacing: 2, + crossAxisSpacing: 2, + childAspectRatio: 0.618, + children: data + .map((color) => _buildItem(color)) + .toList(), + ), + ); + } + + Container _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 30, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 163, +// "name": 'GridView.builder构造', +// "priority": 4, +// "subtitle": +// "【itemCount】 : 条目数量 【int】\n" +// "【gridDelegate】 : 网格代理 【SliverGridDelegate】\n" +// "【itemBuilder】 : 条目构造器 【IndexedWidgetBuilder】", +// } +class BuilderGridView extends StatelessWidget { + final data = List.generate(128, (i) => Color(0xFF33FFF - 2*i)); + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: GridView.builder( + itemCount: data.length, + scrollDirection: Axis.vertical, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(//网格代理:定交叉轴数目 + crossAxisCount: 4,//条目个数 + mainAxisSpacing: 5,//主轴间距 + crossAxisSpacing: 5,//交叉轴间距 + childAspectRatio:1/0.618), + itemBuilder: (_, int position)=> _buildItem(data[position]) + ), + ); + } + + Container _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 30, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + ); + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/GridPager.dart b/lib/views/widgets/StatelessWidget/GridPager.dart new file mode 100644 index 0000000..33371aa --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GridPager.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class CustomGridPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: 200, + height: 100, + child: GridPaper( + color: Colors.red, + interval: 50, + child: Image.asset( + "assets/images/wy_300x200.jpg", + fit: BoxFit.cover, + ))); + } +} + +class DivisionsGridPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: 200, + height: 100, + child: GridPaper( + color: Colors.red, + interval: 50, + divisions: 4, + subdivisions: 4, + child: Image.asset( + "assets/images/wy_300x200.jpg", + fit: BoxFit.cover, + ))); + } +} diff --git a/lib/views/widgets/StatelessWidget/GridTile.dart b/lib/views/widgets/StatelessWidget/GridTile.dart new file mode 100644 index 0000000..78f620e --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GridTile.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class CustomGridTile extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: 200, height: 200, + child: GridTile( + header: GridTileBar( + backgroundColor: Colors.blue.withAlpha(120), + trailing: Icon( + Icons.star, + color: Colors.red, + ), + leading: CircleAvatar( + backgroundImage: AssetImage("assets/images/wy_200x300.jpg"), + ), + title: Text("百里·巫缨"), + subtitle: Text("倾国必倾城"), + ), + child: Opacity( + opacity: 0.5, + child: Image.asset( + "assets/images/sabar.jpg", + fit: BoxFit.cover, + ), + ), + footer: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "ID:z\$ySX32&29", + style: TextStyle(shadows: [ + Shadow( + color: Colors.blue, + offset: Offset(.1, .1), + blurRadius: 2), + ]), + ), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/GridTileBar.dart b/lib/views/widgets/StatelessWidget/GridTileBar.dart new file mode 100644 index 0000000..a87740e --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GridTileBar.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + + +class CustomGridTileBar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return GridTileBar( + backgroundColor: Colors.blue.withAlpha(120), + trailing: Icon( + Icons.star, + color: Colors.red, + ), + leading: CircleAvatar( + backgroundImage: AssetImage("assets/images/wy_200x300.jpg"), + ), + title: Text("百里·巫缨"), + subtitle: Text("倾国必倾城"), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/GridView.dart b/lib/views/widgets/StatelessWidget/GridView.dart new file mode 100644 index 0000000..489328c --- /dev/null +++ b/lib/views/widgets/StatelessWidget/GridView.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_unit/app/utils/color_utils.dart'; + +class GridViewPage extends StatefulWidget { + + @override + _GridViewGridViewExtentState createState() => _GridViewGridViewExtentState(); +} +class _GridViewGridViewExtentState extends State { + List data; + + @override + void initState() { + data=List.generate(50, (i)=>i);//生成50个数字 + super.initState(); + } + + @override + Widget build(BuildContext context) { + var builder= GridView.builder( + itemCount: data.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(//网格代理:定交叉轴数目 + crossAxisCount: 4,//条目个数 + mainAxisSpacing: 10,//主轴间距 + crossAxisSpacing: 10,//交叉轴间距 + childAspectRatio:1/0.618,//交叉轴方向item尺寸/主轴方向item尺寸 + ), + itemBuilder: (_, int position) => Container( alignment: Alignment.center, + color: ColorUtils.randomColor(limitA: 255),child: Text("$position") ), + padding: EdgeInsets.all(10), + scrollDirection: Axis.vertical,//滑动方向 + ); + return builder; + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/Icon.dart b/lib/views/widgets/StatelessWidget/Icon.dart new file mode 100644 index 0000000..2d422eb --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Icon.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/style/TolyIcon.dart'; + +class CustomIcon extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Icon( + Icons.send, + color: Colors.orange, + size: 60, + ), + Icon( + Icons.android, + color: Colors.green, + size: 100, + ), + ], + ); + } +} + +class MyIcon extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + TolyIcon.icon_search, + TolyIcon.icon_star, + TolyIcon.icon_layout, + TolyIcon.icon_star_ok + ] + .map((e) => Icon( + e, + color: Colors.green, + size: 60, + )) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/IconButton.dart b/lib/views/widgets/StatelessWidget/IconButton.dart new file mode 100755 index 0000000..f3007a8 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/IconButton.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + + +class CustomIconButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + padding: EdgeInsets.only(), + onPressed: () {}, + icon: Icon(Icons.android, size: 40, color: Colors.green), + tooltip: "android", + highlightColor: Colors.orangeAccent, + splashColor: Colors.blue, + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/ImageIcon.dart b/lib/views/widgets/StatelessWidget/ImageIcon.dart new file mode 100644 index 0000000..e08ba94 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ImageIcon.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + + +class CustomImageIcon extends StatelessWidget { + @override + Widget build(BuildContext context) { + var data = { + Colors.blue: 50.0, + Colors.red: 60.0, + Colors.green: 70.0, + Colors.yellow: 80.0, + }; + return Wrap( + spacing: 10, + children: data.keys + .map((e) => ImageIcon( + AssetImage("assets/images/leaf.png"), + color: e, + size: data[e], + )) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/InputChip.dart b/lib/views/widgets/StatelessWidget/InputChip.dart new file mode 100644 index 0000000..b865f4d --- /dev/null +++ b/lib/views/widgets/StatelessWidget/InputChip.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + + +class PressInputChip extends StatefulWidget { + @override + _PressInputChipState createState() => _PressInputChipState(); +} + +class _PressInputChipState extends State { + bool _delete = false; + + @override + Widget build(BuildContext context) { + return InputChip( + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + label: Text( + !_delete ? + "This is a InputChip." : + "You are clicked delete icon."), + backgroundColor: Colors.grey.withAlpha(66), + avatar: Image.asset("assets/images/icon_head.png"), + selectedColor: Colors.orangeAccent.withAlpha(88), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + elevation: 3, + onPressed: () => DialogAbout.show(context), + onDeleted: () => setState(() => _delete = !_delete)); + } +} + +class SelectInputChip extends StatefulWidget { + @override + _SelectInputChipState createState() => _SelectInputChipState(); +} + +class _SelectInputChipState extends State { + bool _select = false; + + @override + Widget build(BuildContext context) { + return InputChip( + selected: _select, + padding: EdgeInsets.all(5), + labelPadding: EdgeInsets.all(3), + label: Text("This is a InputChip."), + backgroundColor: Colors.grey.withAlpha(66), + avatar: Image.asset("assets/images/icon_head.png"), + selectedColor: Colors.orangeAccent.withAlpha(88), + selectedShadowColor: Colors.blue, + shadowColor: Colors.orangeAccent, + elevation: 3, + onDeleted: () => DialogAbout.show(context), + onSelected: (bool value) { + setState(() { + _select = value; + }); + print("onSelected"); + }, + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/ListTile.dart b/lib/views/widgets/StatelessWidget/ListTile.dart new file mode 100644 index 0000000..68eabcf --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ListTile.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + + +class CustomListTile extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: ListTile( + leading: Image.asset("assets/images/icon_head.png"), + title: Text("以梦为马"), + subtitle: Text("海子"), + contentPadding: EdgeInsets.all(5), + trailing: Icon(Icons.more_vert), + onLongPress: () => DialogAbout.show(context), + ), + ); + } +} + +class SelectListTile extends StatefulWidget { + @override + _SelectListTileState createState() => _SelectListTileState(); +} + +class _SelectListTileState extends State { + bool _selected = false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: ListTile( + leading: Image.asset("assets/images/icon_head.png"), + selected: _selected, + title: Text("以梦为马"), + subtitle: Text("海子"), + contentPadding: EdgeInsets.all(5), + trailing: Icon(Icons.more_vert), + onTap: () => setState(() => _selected = !_selected), + ), + ); + } +} + +class DenseListTile extends StatefulWidget { + @override + _DenseListTileState createState() => _DenseListTileState(); +} + +class _DenseListTileState extends State { + bool _dense = false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: ListTile( + leading: Image.asset("assets/images/icon_head.png"), + title: Text("以梦为马"), + subtitle: Text("海子"), + selected: false, + contentPadding: EdgeInsets.all(5), + trailing: Icon(Icons.more_vert), + dense: _dense, + onTap: () => setState(() => _dense = !_dense), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/ListView.dart b/lib/views/widgets/StatelessWidget/ListView.dart new file mode 100644 index 0000000..c2f4c38 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ListView.dart @@ -0,0 +1,216 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-27 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 162, +// "name": 'ListView基本使用', +// "priority": 1, +// "subtitle": +// "【children】 : 子组件列表 【List】\n" +// "【padding】 : 点击事件 【EdgeInsetsGeometry】", +// } +class CustomListView extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 5), + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 162, +// "name": 'ListView横向滑动', +// "priority": 2, +// "subtitle": +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【reverse】 : 是否反向滑动 【bool】\n" +// "【shrinkWrap】 : 无边界时是否包裹 【bool】", +// } +class HorizontalListView extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView( + reverse: true, + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 162, +// "name": 'ListView.builder构造', +// "priority": 3, +// "subtitle": +// "【itemCount】 : 条目个数 【int】\n" +// "【itemBuilder】 : 条目构造器 【IndexedWidgetBuilder】", +// } +class BuilderListView extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView.builder( + itemCount: data.length, + itemBuilder: (context, index) => _buildItem(data[index]), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + Widget _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ); +} +// { +// "widgetId": 162, +// "name": 'ListView.separated构造', +// "priority": 3, +// "subtitle": +// "【separatorBuilder】 : 条目构造器 【IndexedWidgetBuilder】", +// } +class SeparatedListView extends StatelessWidget { + final data = [ + Colors.purple[50], + Colors.purple[100], + Colors.purple[200], + Colors.purple[300], + Colors.purple[400], + Colors.purple[500], + Colors.purple[600], + Colors.purple[700], + Colors.purple[800], + Colors.purple[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: ListView.separated( + separatorBuilder: (context, index) => Divider( + thickness: 1, + height: 1, + color: Colors.orange, + ), + itemCount: data.length, + itemBuilder: (context, index) => _buildItem(data[index]), + ), + ); + } + + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + Widget _buildItem(Color color) => Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) + ]), + ), + ); +} diff --git a/lib/views/widgets/StatelessWidget/Listener.dart b/lib/views/widgets/StatelessWidget/Listener.dart new file mode 100644 index 0000000..f515e9f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Listener.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 147, +// "name": 'Listener基本事件', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onPointerDown】 : 按下事件 【Function(PointerDownEvent)】\n" +// "【onPointerMove】 : 移动事件 【Function(PointerMoveEvent)】\n" +// "【onPointerMove】 : 抬起事件 【Function(PointerUpEvent)】\n" +// "【onPointerCancel】 : 取消事件 【Function(PointerUpEvent)】", +// } + +class CustomListener extends StatefulWidget { + @override + _CustomListenerState createState() => _CustomListenerState(); +} + +class _CustomListenerState extends State { + var _info = ''; + + @override + Widget build(BuildContext context) { + return Listener( + onPointerDown: (detail) => setState(() => _info = detail.toString()), + onPointerMove: (detail) => setState(() => _info = detail.toString()), + onPointerUp: (detail) => setState(() => _info = detail.toString()), + onPointerCancel: (detail) => setState(() => _info = detail.toString()), + + child: Container( + alignment: Alignment.center, + width: 300, + height: 300 * 0.618, + color: Colors.grey.withAlpha(33), + child: Text( + _info, + style: TextStyle(fontSize: 16, color: Colors.blue), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/MaterialButton.dart b/lib/views/widgets/StatelessWidget/MaterialButton.dart new file mode 100644 index 0000000..4091894 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/MaterialButton.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/pather.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +class CustomMaterialButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialButton( + height: 40, + elevation: 5, + color: Colors.orangeAccent, + textColor: Colors.white, + splashColor: Colors.blue, + padding: EdgeInsets.all(8), + child: Text("MaterialButton"), + onPressed: () => DialogAbout.show(context)); + } +} + +class LongPressMaterialButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialButton( + height: 40, + elevation: 5, + color: Colors.blue, + highlightColor: Colors.green, + textColor: Colors.white, + padding: EdgeInsets.all(8), + child: Text("MaterialButton"), + onLongPress: () => DialogAbout.show(context), + onPressed: () => DialogAbout.show(context)); + } +} + +class ShapeMaterialButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 20, + children: [ + Container( + width: 40, + height: 40, + child: MaterialButton( + padding: EdgeInsets.all(0), + textColor: Color(0xffFfffff), + elevation: 3, + color: Colors.blue, + highlightColor: Color(0xffF88B0A), + splashColor: Colors.red, + child: Icon( + Icons.add, + color: Colors.white, + ), + shape: CircleBorder( + side: BorderSide(width: 2.0, color: Color(0xFFFFDFDFDF)), + ), + onLongPress: () => DialogAbout.show(context), + onPressed: () => DialogAbout.show(context)), + ), + Container( + width: 100, + height: 40, + child: MaterialButton( + padding: EdgeInsets.all(0), + textColor: Color(0xffFfffff), + elevation: 3, + color: Colors.blue, + highlightColor: Color(0xffF88B0A), + splashColor: Colors.red, + child: Icon( + Icons.remove, + color: Colors.white, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15))), + onLongPress: () => DialogAbout.show(context), + onPressed: () => DialogAbout.show(context)), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/MonthPicker.dart b/lib/views/widgets/StatelessWidget/MonthPicker.dart new file mode 100644 index 0000000..ee72ab5 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/MonthPicker.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 135, +// "name": 'MonthPicker基本使用', +// "priority": 1, +// "subtitle": +// "【selectedDate】 : 选中日期 【DateTime】\n" +// "【firstDate】 : 最前日期限制 【DateTime】\n" +// "【lastDate】 : 最后日期限制 【DateTime】\n" +// "【onChanged】 : 点击回调 【Function(DateTime)】", +// } +class CustomMonthPicker extends StatefulWidget { + @override + _CustomMonthPickerState createState() => _CustomMonthPickerState(); +} + +class _CustomMonthPickerState extends State { + DateTime _date = DateTime.now(); + + @override + Widget build(BuildContext context) { + return Container( + height: 350, + child: MonthPicker( + selectedDate: _date, + onChanged: (date) => setState(() => _date = date), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/OutLineButton.dart b/lib/views/widgets/StatelessWidget/OutLineButton.dart new file mode 100755 index 0000000..16d5d1f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/OutLineButton.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + + +class CustomOutlineButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return OutlineButton(//边线按钮 + onPressed: () {}, + child: Text("OutlineButton"), + padding: EdgeInsets.all(8), + splashColor: Colors.green, + highlightColor: Colors.orangeAccent, + highlightedBorderColor: Colors.grey, + textColor: Color(0xff000000), + borderSide: BorderSide(color: Color(0xff0A66F8), width: 2), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Placeholder.dart b/lib/views/widgets/StatelessWidget/Placeholder.dart new file mode 100644 index 0000000..d75a62f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Placeholder.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + + +class CustomPlaceholder extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: 100, + height: 100*0.618, + child: Placeholder( + color: Colors.orangeAccent, + strokeWidth: 2, + ), + ); + } +} +class FallbackPlaceholder extends StatelessWidget { + @override + Widget build(BuildContext context) { + return UnconstrainedBox( + child: Placeholder( + color: Colors.blue, + strokeWidth: 2, + fallbackHeight: 100, + fallbackWidth: 150, + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/PositionedDirectional.dart b/lib/views/widgets/StatelessWidget/PositionedDirectional.dart new file mode 100644 index 0000000..2dc195f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/PositionedDirectional.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 159, +// "name": 'PositionedDirectional基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 组件 【Widget】\n" +// "【top】 : 到父顶距离 【double】\n" +// "【end】 : 到父右距离 【double】\n" +// "【start】 : 到父左距离 【double】\n" +// "【bottom】 : 到父底距离 【double】", +// } +class CustomPositionedDirectional extends StatelessWidget { + @override + Widget build(BuildContext context) { + var yellowBox = Container( + color: Colors.yellow, + height: 100, + width: 100, + ); + + var redBox = Container( + color: Colors.red, + height: 90, + width: 90, + ); + + var greenBox = Container( + color: Colors.green, + height: 80, + width: 80, + ); + + var cyanBox = Container( + color: Colors.cyanAccent, + height: 70, + width: 70, + ); + + return Container( + width: 200, + height: 120, + color: Colors.grey.withAlpha(33), + child: Stack( + children: [ + yellowBox, + redBox, + PositionedDirectional(top: 20, start: 20, child: greenBox), + PositionedDirectional( + child: cyanBox, + bottom: 10, + end: 10, + ) + ], + )); + } +} diff --git a/lib/views/widgets/StatelessWidget/RadioListTile.dart b/lib/views/widgets/StatelessWidget/RadioListTile.dart new file mode 100644 index 0000000..fbc80c3 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/RadioListTile.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + +enum ItemType { + java, + kotlin, + dart, +} + +class ItemBean { + final String title; + final String subTitle; + final String imgUrl; + + ItemBean(this.title, this.subTitle, this.imgUrl); +} + +class CustomRadioListTile extends StatefulWidget { + @override + _CustomRadioListTileState createState() => _CustomRadioListTileState(); +} + +class _CustomRadioListTileState extends State { + final Map languages = { + ItemType.java: + ItemBean("Java", "曾经世界上最流行的语言", "assets/images/java.jpeg"), + ItemType.kotlin: + ItemBean("Kotlin", "未来世界上最流行的语言", "assets/images/kotlin.jpg"), + ItemType.dart: + ItemBean("Dart", "世界上最优雅的语言", "assets/images/dart.jpg"), + }; + var _type = ItemType.java; + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.grey.withAlpha(11), + child: Column( + mainAxisSize: MainAxisSize.min, + children: languages.keys + .map((type) => RadioListTile( + value: type, + groupValue: _type, + title: Text(languages[type].title), + subtitle: Text(languages[type].subTitle), + selected: _type == type, + secondary: CircleAvatar( + backgroundImage: AssetImage(languages[type].imgUrl), + ), + onChanged: (type) => setState(() => _type = type), + )) + .toList()), + ); + } +} + +class DenseRadioListTile extends StatefulWidget { + @override + _DenseRadioListTileState createState() => _DenseRadioListTileState(); +} + +class _DenseRadioListTileState extends State { + final Map languages = { + ItemType.java: + ItemBean("Java", "曾经世界上最流行的语言", "assets/images/java.jpeg"), + ItemType.kotlin: + ItemBean("Kotlin", "未来世界上最流行的语言", "assets/images/kotlin.jpg"), + ItemType.dart: + ItemBean("Dart", "世界上最优雅的语言", "assets/images/dart.jpg"), + }; + var _type = ItemType.java; + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.grey.withAlpha(11), + child: Column( + mainAxisSize: MainAxisSize.min, + children: languages.keys + .map((type) => RadioListTile( + value: type, + groupValue: _type, + title: Text(languages[type].title), + activeColor: Colors.orangeAccent, + dense: true, + subtitle: Text(languages[type].subTitle), + selected: _type == type, + secondary: CircleAvatar( + backgroundImage: AssetImage(languages[type].imgUrl), + ), + onChanged: (type) => setState(() => _type = type), + )) + .toList()), + ); + } +} + + +//class RadioListTilePage extends StatefulWidget { +// @override +// _RadioListTilePageState createState() => _RadioListTilePageState(); +//} +// +//class _RadioListTilePageState extends State { +// +// final Map languages={ +// ItemType.java: ItemBean("Java", "曾经世界上最流行的语言", "assets/images/java.jpeg"), +// ItemType.kotlin: ItemBean("Kotlin", "未来世界上最流行的语言", "assets/images/kotlin.jpg"), +// ItemType.dart: ItemBean("Dart", "世界上最优雅的语言", "assets/images/dart.jpg"), +// }; +// var _type=ItemType.java; +// @override +// Widget build(BuildContext context) { +// +// return Container( +// color: Colors.grey.withAlpha(11), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: languages.keys.map((type)=>RadioListTile( +// value: type, +// groupValue: _type, +// title: Text(languages[type].title), +// subtitle: Text(languages[type].subTitle), +// selected: _type==type, +// secondary: CircleAvatar( +// backgroundImage: AssetImage(languages[type].imgUrl),), +// onChanged: (type)=> setState(() => _type=type), +// )).toList() +// ), +// ); +// } +//} +// +//enum ItemType{ +// java, +// kotlin, +// dart, +//} +//class ItemBean{ +// final String title; +// final String subTitle; +// final String imgUrl; +// ItemBean(this.title, this.subTitle, this.imgUrl); +//} + +//class LanguageChooser extends StatelessWidget{ +// +// @override +// Widget build(BuildContext context) { +// +// var map ={ +// LocaleState.zh().locale:"java", +// LocaleState.en().locale:I18N.of(context).english, +// LocaleState.fr().locale:I18N.of(context).french, +// }; +// +// return StoreBuilder(builder: (context, store) =>ExpansionTile( +// title: Text(I18N.of(context).switchLocal), +// leading: Icon(Icons.language,color: store.state.themeState.primaryColor,), +// children: map.keys.map((local)=>RadioListTile( +// activeColor: store.state.themeState.primaryColor, +// value: local, +// title: Text(map[local]), +// groupValue: store.state.localeState.locale, +// onChanged: (locale)=> store.dispatch(ActionSwitchLocal(locale)) +// )).toList(), +// )); +// } +//} diff --git a/lib/views/widgets/StatelessWidget/RaisedButton.dart b/lib/views/widgets/StatelessWidget/RaisedButton.dart new file mode 100755 index 0000000..2b1bba0 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/RaisedButton.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class CustomRaisedButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return RaisedButton( + color: Colors.blue, + splashColor: Colors.green, + onPressed: () {}, + child: Text("RaisedButton"), + textColor: Color(0xffFfffff), + padding: EdgeInsets.all(8), + elevation: 5, + highlightColor: Color(0xffF88B0A), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/SimpleDialog.dart b/lib/views/widgets/StatelessWidget/SimpleDialog.dart new file mode 100644 index 0000000..2ffcf48 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SimpleDialog.dart @@ -0,0 +1,122 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-24 +/// contact me by email 1981462002@qq.com +/// 说明: +/// +// { +// "widgetId": 128, +// "name": 'SimpleDialog基本使用', +// "priority": 1, +// "subtitle": +// "【title】 : 顶部组件 【Widget】\n" +// "【children】 : 子组件列表 【List】\n" +// "【titlePadding】 : 顶部内边距 【EdgeInsetsGeometry】\n" +// "【contentPadding】 : 内容内边距 【EdgeInsetsGeometry】\n" +// "【backgroundColor】 : 右下角组件列表 【背景色】\n" +// "【elevation】 : 右下角组件列表 【背景色】\n" +// "【shape】 : 影深 【double】", +// } +class CustomSimpleDialog extends StatelessWidget { + final info = [ + '性别: 男 未婚', + '微信: zdl1994328', + "掘金: 张风捷特烈", + "github: toly1994328", + "邮箱: 1981462008@qq.com", + ]; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + _buildSimpleDialog(context), + Positioned( + top: 70, + right: 30, + child: _buildRaisedButton(context)), + + ], + ); + } + Widget _buildRaisedButton(BuildContext context) => RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + color: Colors.blue, + onPressed: () { + showDialog(context: context, builder: (ctx) => _buildSimpleDialog(ctx)); + }, + child: Text( + 'Just Show It', + style: TextStyle(color: Colors.white), + ), + ); + + SimpleDialog _buildSimpleDialog(BuildContext context) { + return SimpleDialog( + title: _buildTitle(), + titlePadding: EdgeInsets.only( + top: 5, + left: 20, + ), + contentPadding: EdgeInsets.symmetric(horizontal: 5), + children: _buildChild(context), + backgroundColor: Colors.white, + elevation: 4, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + ); + } + + List _buildChild(BuildContext context) { + return info + .map((str) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SimpleDialogOption( + onPressed: () => print(str), + child: Container( + width: double.infinity, + child: Text( + str, + style: TextStyle(color: Color(0xff999999), fontSize: 16), + ), + ), + ), + Divider( + indent: 20, + height: 12, + color: info.indexOf(str) == info.length - 1 + ? Colors.transparent + : Theme.of(context).dividerColor, + ) + ], + )) + .toList(); + } + + Widget _buildTitle() { + return Row( + //标题 + children: [ + Image.asset( + "assets/images/icon_head.png", + width: 30, + height: 30, + ), + SizedBox( + width: 10, + ), + Expanded( + child: Text( + "张风捷特烈", + style: TextStyle(fontSize: 18), + )), + CloseButton() + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/SimpleDialogOption.dart b/lib/views/widgets/StatelessWidget/SimpleDialogOption.dart new file mode 100644 index 0000000..8b1654e --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SimpleDialogOption.dart @@ -0,0 +1,44 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/dialogs/dialog_about.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 133, +// "name": 'SimpleDialogOption基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onPressed】 : 点击事件 【Function()】", +// } +class CustomSimpleDialogOption extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + alignment: Alignment.center, + width: double.infinity, + height: 50, + margin: EdgeInsets.all(5), + color: Colors.grey.withAlpha(33), + child: SimpleDialogOption( + onPressed: () => DialogAbout.show(context), + child: Text('张风捷特烈')), + ), + Container( + height: 50, + alignment: Alignment.center, + width: double.infinity, + color: Colors.grey.withAlpha(33), + margin: EdgeInsets.all(5), + child: SimpleDialogOption( + onPressed: () => DialogAbout.show(context), + child: Text('百里·巫缨')), + ), + ], + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/SingleChildScrollView.dart b/lib/views/widgets/StatelessWidget/SingleChildScrollView.dart new file mode 100644 index 0000000..8c00d6b --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SingleChildScrollView.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-28 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 164, +// "name": 'SingleChildScrollView基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【padding】 : 点击事件 【EdgeInsetsGeometry】", +// } +class CustomSingleChildScrollView extends StatelessWidget { + final data = [ + Colors.blue[50], + Colors.blue[100], + Colors.blue[200], + Colors.blue[300], + Colors.blue[400], + Colors.blue[500], + Colors.blue[600], + Colors.blue[700], + Colors.blue[800], + Colors.blue[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Column( + children: data + .map((color) => Container( + alignment: Alignment.center, + height: 50, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + + ), + ); + } + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} + +// { +// "widgetId": 164, +// "name": 'SingleChildScrollView滑动方向', +// "priority": 2, +// "subtitle": +// "【scrollDirection】 : 滑动方向 【Axis】\n" +// "【reverse】 : 是否反向 【Axis】", +// } +class DirectionSingleChildScrollView extends StatelessWidget { + final data = [ + Colors.blue[50], + Colors.blue[100], + Colors.blue[200], + Colors.blue[300], + Colors.blue[400], + Colors.blue[500], + Colors.blue[600], + Colors.blue[700], + Colors.blue[800], + Colors.blue[900], + ]; + + @override + Widget build(BuildContext context) { + return Container( + height: 200, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + reverse: true, + padding: EdgeInsets.symmetric(horizontal: 10), + child: Row( + children: data + .map((color) => Container( + alignment: Alignment.center, + width: 90, + color: color, + child: Text( + colorString(color), + style: TextStyle(color: Colors.white, shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2) + ]), + ), + )) + .toList(), + ), + + ), + ); + } + String colorString(Color color) => + "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; +} diff --git a/lib/views/widgets/StatelessWidget/SnackBar.dart b/lib/views/widgets/StatelessWidget/SnackBar.dart new file mode 100644 index 0000000..5e6a0e9 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SnackBar.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 140, +// "name": 'SnackBar基本使用', +// "priority": 1, +// "subtitle": +// "【content】 : 中间内容组件 【Widget】\n" +// "【action】 : 右侧按钮 【SnackBarAction】\n" +// "【duration】 : 持续时长 【Widget】\n" +// "【backgroundColor】 : 背景色 【Color】\n" +// "【elevation】 : 影深 【double】\n" +// "【shape】 : 形状 【ShapeBorder】\n" +// "【onVisible】 : 显示时回调 【Function()】", +// } +class CustomSnackBar extends StatefulWidget { + @override + _CustomSnackBarState createState() => _CustomSnackBarState(); +} + +class _CustomSnackBarState extends State { + @override + Widget build(BuildContext context) { + return Container( + child: FlatButton( + color: Colors.blue, + onPressed: () => + Scaffold.of(context).showSnackBar(_buildSnackBar()), + child: Text( + '点我弹出SnackBar', + style: TextStyle(color: Colors.white), + ))); + } + + Widget _buildSnackBar() { + return SnackBar( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))), + content: Text('Wellcome to for join Flutter Unit!'), + duration: Duration(seconds: 3), + //持续时间 + backgroundColor: Colors.red, + onVisible: () => print('onVisible'), + action: SnackBarAction( + textColor: Colors.white, label: '确定', onPressed: () {}), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/SnackBarAction.dart b/lib/views/widgets/StatelessWidget/SnackBarAction.dart new file mode 100644 index 0000000..f15db88 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SnackBarAction.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 141, +// "name": 'SnackBarAction基本使用', +// "priority": 1, +// "subtitle": +// "【label】 : 标签 【String】\n" +// "【textColor】 : 文字颜色 【Color】\n" +// "【disabledTextColor】 : 文字失效色 【Color】\n" +// "【onPressed】 : 点击回调 【Function()】", +// } +class CustomSnackBarAction extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: SnackBarAction( + disabledTextColor: Colors.red, + textColor: Colors.blue, + label: '确定', + onPressed: () => print('onPressed'))); + } +} diff --git a/lib/views/widgets/StatelessWidget/Spacer.dart b/lib/views/widgets/StatelessWidget/Spacer.dart new file mode 100644 index 0000000..fdc827c --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Spacer.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/utils/color_utils.dart'; + +/// create by 张风捷特烈 on 2020-03-22 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 107, +// "name": 'Spacer基本使用', +// "priority": 1, +// "subtitle": +// "一个Spacer会占据可延伸区域", +// } +class OneSpacer extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return + Container( + color: Colors.grey.withAlpha(33), + child: Row(children: [ + Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: Colors.red, + ), + Spacer(), + Container( + alignment: Alignment.center, + width: 60, + height: 50, + color: Colors.blue, + ), + ],), + ); + } +} + +// { +// "widgetId": 107, +// "name": '多个Spacer空间分配', +// "priority": 2, +// "subtitle": +// "【flex】 : 剩余空间分配占比 【int】", +// } +class ManySpacer extends StatefulWidget { + @override + _ManySpacerState createState() => _ManySpacerState(); +} + +class _ManySpacerState extends State { + int _flexA=1; + int _flexB=1; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _buildSliders(), + Container( + color: Colors.grey.withAlpha(33), + child: Row(children: [ + Spacer(flex: _flexA), + Container( + alignment: Alignment.center, + width: 100, + height: 50, + color: Colors.red, + ), + Spacer(flex: _flexB), + Container( + alignment: Alignment.center, + width: 60, + height: 50, + color: Colors.blue, + ), + ],), + ) + ], + ); + } + + Widget _buildSliders() { + return Column( + children: [ + Slider( + divisions: 20, + min: 1, + max: 10, + label: "左边flex: $_flexA", + value: _flexA.toDouble(), + onChanged: (v) => setState(() => _flexA = v.round()) + ), + Slider( + divisions: 20, + label: "右边flex: $_flexB", + min: 1, + max: 10, + value: _flexB.toDouble(), + onChanged: (v) => setState(() => _flexB = v.round()) + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/StatelessWidget/SwitchListTile.dart b/lib/views/widgets/StatelessWidget/SwitchListTile.dart new file mode 100644 index 0000000..3baed1a --- /dev/null +++ b/lib/views/widgets/StatelessWidget/SwitchListTile.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + +class CustomSwitchListTile extends StatefulWidget { + @override + _CustomSwitchListTileState createState() => _CustomSwitchListTileState(); +} + +class _CustomSwitchListTileState extends State { + var _value=false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: SwitchListTile( + value: _value, + inactiveThumbColor:Colors.cyanAccent , + inactiveTrackColor: Colors.blue.withAlpha(88), + activeColor: Colors.orangeAccent, + activeTrackColor: Colors.orange, + secondary: Image.asset("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _value = !_value), + ), + ); + } +} + +class SelectSwitchListTile extends StatefulWidget { + @override + _SelectSwitchListTileState createState() => _SelectSwitchListTileState(); +} + +class _SelectSwitchListTileState extends State { + var _value=false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: SwitchListTile( + value: _value, + selected: _value, + activeColor: Colors.orangeAccent, + secondary: Image.asset("assets/images/icon_head.png"), + inactiveThumbImage: AssetImage("assets/images/pica.gif"), + activeThumbImage: AssetImage("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _value = !_value), + ), + ); + } +} + +class DenseSwitchListTile extends StatefulWidget { + @override + _DenseSwitchListTileState createState() => _DenseSwitchListTileState(); +} + +class _DenseSwitchListTileState extends State { + var _value=false; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(10), + color: Colors.grey.withAlpha(22), + child: SwitchListTile( + value: _value, + dense: true, + selected: _value, + activeColor: Colors.orangeAccent, + secondary: Image.asset("assets/images/icon_head.png"), + title: Text("张风捷特烈"), + subtitle: Text("@万花过尽知无物"), + onChanged: (v) => setState(() => _value = !_value), + ), + ); + } +} + + diff --git a/lib/views/widgets/StatelessWidget/Tab.dart b/lib/views/widgets/StatelessWidget/Tab.dart new file mode 100644 index 0000000..3ebd4b0 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Tab.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 148, +// "name": 'Tab基本使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【text】 : 文字 【String】\n" +// "【icon】 : 下方组件 【Widgit】\n" +// " text和child不能同时存在", +// } + +class CustomTab extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Tab( + icon:Icon( Icons.add,color: Colors.blue,), + child: Text('添加'), + ), + Tab( + icon:Icon( Icons.close,color: Colors.red,), + text: '删除', + ), + Tab( + icon:Icon( Icons.refresh,color: Colors.green), + text: '更新', + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/TabBar.dart b/lib/views/widgets/StatelessWidget/TabBar.dart new file mode 100644 index 0000000..8fc3f77 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/TabBar.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/flutter/no_shadow_tab_bar.dart'; + +/// create by 张风捷特烈 on 2020-03-16 +/// contact me by email 1981462002@qq.com +/// 说明: + +// { +// "widgetId": 58, +// "name": 'TabBar基本使用', +// "priority": 1, +// "subtitle": +// "【controller】 : 控制器 【TabController】\n" +// "【indicatorColor】 : 指示器颜色 【指示器颜色】\n" +// "【indicatorWeight】 : 指示器高 【double】\n" +// "【indicatorPadding】 : 指示器边距 【EdgeInsetsGeometry】\n" +// "【labelStyle】 : 页签文字样式 【TextStyle】\n" +// "【unselectedLabelStyle】 : 未选中文字样式 【TextStyle】\n" +// "【isScrollable】 : 是否可滑动 【bool】\n" +// "【onTap】 : 页签点击回调 【Function(int)】\n" +// "【tabs】 : 标签组件 【List】", +// } +class CustomTabBar extends StatefulWidget { + @override + _CustomTabBarState createState() => _CustomTabBarState(); +} + +class _CustomTabBarState extends State + with SingleTickerProviderStateMixin { + final tabs = ['风画庭', '雨韵舍', '雷鸣殿', '电疾堂', '霜寒阁', '雪月楼']; + TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return TabBar( + onTap: (tab) { + print(tab); + }, + labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + unselectedLabelStyle: TextStyle(fontSize: 16), + isScrollable: true, + controller: _tabController, + labelColor: Colors.blue, + indicatorWeight: 3, + indicatorPadding: EdgeInsets.symmetric(horizontal: 10), + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.orangeAccent, + tabs: tabs.map((e) => Tab(text: e)).toList(), + ); + } +} + +// { +// "widgetId": 58, +// "name": '通过修改源码可实现无水波纹', +// "priority": 1, +// "subtitle": +// "详见:components/flutter/no_shadow_tab_bar.dart", +// } +class NoShadowTabBarDemo extends StatefulWidget { + @override + _NSTabBarState createState() => _NSTabBarState(); +} + +class _NSTabBarState extends State + with SingleTickerProviderStateMixin { + final tabs = ['风画庭', '雨韵舍', '雷鸣殿', '电疾堂', '霜寒阁', '雪月楼']; + TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(vsync: this, length: tabs.length); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return NoShadowTabBar( + onTap: (tab) { + print(tab); + }, + labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + unselectedLabelStyle: TextStyle(fontSize: 16), + isScrollable: true, + controller: _tabController, + labelColor: Colors.blue, + indicatorWeight: 3, + indicatorPadding: EdgeInsets.symmetric(horizontal: 10), + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.orangeAccent, + tabs: tabs.map((e) => Tab(text: e)).toList(), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Text.dart b/lib/views/widgets/StatelessWidget/Text.dart new file mode 100644 index 0000000..9100624 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Text.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + +class CustomText extends StatelessWidget { + @override + Widget build(BuildContext context) { + var style = TextStyle( + color: Colors.blue, + fontSize: 20, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + letterSpacing: 10, + ); + return Container( + width: 200, + color: Colors.cyanAccent.withAlpha(33), + height: 200 * 0.618 * 0.618, + child: Text("toly-张风捷特烈-1994`", style: style), + ); + } +} + +class DecorationText extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Text( + "19940328", + style: TextStyle( + fontSize: 50, + fontWeight: FontWeight.bold, + decoration: TextDecoration.underline, + decorationThickness: 3, + decorationStyle: TextDecorationStyle.wavy, + decorationColor: Colors.blue, + fontStyle: FontStyle.italic, + fontFamily: "DancingScript", + letterSpacing: 10), + ); + } +} + +class ShadowText extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Text( + "张风捷特烈", + style: TextStyle( + fontSize: 50, + color: Colors.white, + backgroundColor: Colors.black, + shadows: [ + Shadow( + color: Colors.cyanAccent, + offset: Offset(1, 1), + blurRadius: 10), + Shadow( + color: Colors.blue, + offset: Offset(-0.1, 0.1), + blurRadius: 10), + ]), + ); + } +} + +class TextAlignText extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + runSpacing: 10, + children: TextAlign.values + .map((e) => Container( + width: 120, + color: Colors.cyanAccent.withAlpha(33), + height: 120 * 0.618, + child: Text( + " 张风捷特烈 toly " * 3, + textAlign: e, + ), + )) + .toList(), + ); + } +} + +class TextDirectionText extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 40, + runSpacing: 10, + children: TextDirection.values + .map((e) => Container( + width: 120, + color: Colors.cyanAccent.withAlpha(33), + height: 120 * 0.618, + child: Text( + " 张风捷特烈 toly " * 10, + textDirection: e, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + )) + .toList(), + ); + } +} + +class SoftWrapText extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + runSpacing: 10, + children: TextOverflow.values + .map((e) => Container( + width: 150, + color: Colors.cyanAccent.withAlpha(33), + height: 150 * 0.618 * 0.618, + child: Text(" 张风捷特烈 toly " * 5, + overflow: e, + softWrap: false), + )) + .toList(), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Theme.dart b/lib/views/widgets/StatelessWidget/Theme.dart new file mode 100644 index 0000000..66e1763 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Theme.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 168, +// "name": '文字样式-ThemeData#TextTheme', +// "priority": 1, +// "subtitle": +// "子组件可以通过ThemeData.of获取主题的数据进行使用。", +// } +class TextThemeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + var queryData = Theme.of(context).textTheme; + var styles = { + "headline: ": queryData.headline, + "title: ": queryData.title, + "subhead: ": queryData.subhead, + "subtitle: ": queryData.body1, + "body2: ": queryData.body2, + "button: ": queryData.button, + "overline: ": queryData.overline, + "subtitle: ": queryData.subtitle, + "button: ": queryData.caption, + "display1: ": queryData.display1, + "display2: ": queryData.display2, + "display3: ": queryData.display3, + "display4: ": queryData.display4, + }; + + return Container( + child: Column( + children: styles.keys.map((e) => buildItem(e, styles[e])).toList(), + ), + ); + } + + Widget buildItem(String e, TextStyle style) => Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + "@toly", + style: style, + ) + ], + ), + ), + Divider( + height: 1, + ) + ], + ); +} + +// { +// "widgetId": 168, +// "name": 'Theme的用法', +// "priority": 2, +// "subtitle": +// "使用Theme,可以指定非常多的属性作为主题,这些属性将应用于所有的后代组件,如指定字体、滑块、卡片、文字、分割线、按钮等属性。", +// } +class CustomTheme extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Theme( + data: ThemeData( + cardTheme: CardTheme(color: Colors.red, elevation: 4), + dividerTheme: DividerThemeData( + color: Colors.blue, + thickness: 2 + ), + sliderTheme: SliderThemeData( + thumbColor: Colors.red, + activeTrackColor: Colors.green, + inactiveTrackColor: Colors.grey, + )), + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Card( + child: Container( + width: 50, + height: 50, + color: Colors.transparent, + ), + ), + Container( + width: 150, + child: Slider(value: 0.8, onChanged: (v) => {})), + Container( width: 150,child: Divider()) + ])); + } +} diff --git a/lib/views/widgets/StatelessWidget/ToggleButtons.dart b/lib/views/widgets/StatelessWidget/ToggleButtons.dart new file mode 100755 index 0000000..88c3e53 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/ToggleButtons.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_unit/components/permanent/panel.dart'; + +class CustomToggleButtons extends StatefulWidget { + @override + _CustomToggleButtonsState createState() => _CustomToggleButtonsState(); +} + +class _CustomToggleButtonsState extends State { + var _isSelected = [true, false, false]; + + @override + Widget build(BuildContext context) { + return ToggleButtons( + children: [ + Icon(Icons.skip_previous), + Icon(Icons.pause), + Icon(Icons.skip_next), + ], + borderWidth: 1, + borderRadius: BorderRadius.circular(10), + isSelected: _isSelected, + onPressed: (value) => setState(() { + _isSelected = _isSelected.map((e) => false).toList(); + _isSelected[value] = true; + }), + ); + + } +} + +class ColorToggleButtons extends StatefulWidget { + @override + _ColorToggleButtonsState createState() => _ColorToggleButtonsState(); +} + +class _ColorToggleButtonsState extends State { + var _isSelected = [true, false, false]; + @override + Widget build(BuildContext context) { + return ToggleButtons( + children: [ + Icon(Icons.skip_previous), + Icon(Icons.pause), + Icon(Icons.skip_next), + ], + borderWidth: 1, + borderColor: Colors.orangeAccent, + selectedBorderColor: Colors.blue, + splashColor: Colors.purple.withAlpha(66), + borderRadius: BorderRadius.circular(10), + selectedColor: Colors.red, + fillColor: Colors.green.withAlpha(11), + isSelected: _isSelected, + onPressed: (value) => setState(() { + _isSelected = _isSelected.map((e) => false).toList(); + _isSelected[value] = true; + }), + ); + } +} + +class ProToggleButtons extends StatefulWidget { + @override + _ProToggleButtonsState createState() => _ProToggleButtonsState(); +} + +class _ProToggleButtonsState extends State { + var _isSelected = [false, false, false]; + @override + Widget build(BuildContext context) { + return ToggleButtons( + children: [ + Icon(Icons.skip_previous), + Icon(Icons.pause), + Icon(Icons.skip_next), + ], + borderWidth: 1, + borderColor: Colors.blue, + selectedBorderColor: Colors.orangeAccent, + splashColor: Colors.purple.withAlpha(66), + borderRadius: BorderRadius.circular(10), + selectedColor: Colors.red, + fillColor: Colors.green.withAlpha(11), + isSelected: _isSelected, + onPressed: (value) => setState(() { + _isSelected[value] = !_isSelected[value]; + }), + ); + } +} + + diff --git a/lib/views/widgets/StatelessWidget/UserAccountsDrawerHeader.dart b/lib/views/widgets/StatelessWidget/UserAccountsDrawerHeader.dart new file mode 100644 index 0000000..00bfba7 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/UserAccountsDrawerHeader.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; + +class CustomUAGHP extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width / 3 * 2, + child: UserAccountsDrawerHeader( + accountName: Container( + padding: const EdgeInsets.all(8.0), + child: Text( + "张风捷特烈", + style: + TextStyle(color: Colors.orangeAccent, fontSize: 22, shadows: [ + Shadow( + color: Colors.black, offset: Offset(.5, .5), blurRadius: 2), + ]), + ), + ), + accountEmail: Padding( + padding: const EdgeInsets.all(8.0), + child: Text("1981462002@qq.com", + style: TextStyle(color: Colors.white, fontSize: 14, shadows: [ + Shadow( + color: Colors.orangeAccent, + offset: Offset(.5, .5), + blurRadius: 2), + ])), + ), + currentAccountPicture: Container( + padding: const EdgeInsets.all(15.0), + child: CircleAvatar( + backgroundImage: AssetImage("assets/images/icon_head.png"), + ), + ), + decoration: BoxDecoration( + image: DecorationImage(image: AssetImage("assets/images/caver.jpeg")), + ), + ), + ); + } +} + +class ProUAGHP extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width / 3 * 2, + child: UserAccountsDrawerHeader( + margin: EdgeInsets.all(10), + accountName: Container( + padding: const EdgeInsets.all(8.0), + child: Text( + "张风捷特烈", + style: + TextStyle(color: Colors.orangeAccent, fontSize: 22, + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(.5, .5), + blurRadius: 2), + ]), + ), + ), + accountEmail: Padding( + padding: const EdgeInsets.all(8.0), + child: Text("1981462002@qq.com", + style: TextStyle( + color: Colors.white, fontSize: 14, + shadows: [ + Shadow( + color: Colors.orangeAccent, + offset: Offset(.5, .5), + blurRadius: 2), + ])), + ), + currentAccountPicture: Container( + padding: const EdgeInsets.all(15.0), + child: CircleAvatar( + backgroundImage: AssetImage("assets/images/icon_head.png"), + ), + ), + otherAccountsPictures: [ + FlutterLogo(colors: Colors.green), + ], + onDetailsPressed: () { + + }, + arrowColor: Colors.white, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/images/caver.jpeg")), + ), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/VerticalDivider.dart b/lib/views/widgets/StatelessWidget/VerticalDivider.dart new file mode 100644 index 0000000..3babd7f --- /dev/null +++ b/lib/views/widgets/StatelessWidget/VerticalDivider.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class CustomVerticalDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + var dataColor = [ + Colors.red, Colors.yellow, + Colors.blue, Colors.green]; + var dataThickness = [1.0, 2.0, 4.0, 6.0]; + var data = Map.fromIterables(dataColor, dataThickness); + return Container( + height: 150, + child: Row( + mainAxisSize: MainAxisSize.min, + children: dataColor + .map((e) => VerticalDivider( + color: e, + thickness: data[e], + )) + .toList(), + ), + ); + } +} + +class HeightVerticalDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + var dataColor = [ + Colors.red, Colors.yellow, + Colors.blue, Colors.green]; + var dataThickness = [10.0, 20.0, 30.0, 40.0]; + var data = Map.fromIterables(dataColor, dataThickness); + return Container( + height: 150, + child: Row( + mainAxisSize: MainAxisSize.min, + children: dataColor + .map((e) => VerticalDivider( + color: e, + indent:data[e], + endIndent: data[e]*2, + width: data[e], + thickness: data[e]/10, + )) + .toList(), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/Visibility.dart b/lib/views/widgets/StatelessWidget/Visibility.dart new file mode 100644 index 0000000..a477d08 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/Visibility.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; + +class CustomVisibility extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: [ + _buildVisibility(true), + _buildVisibility(false), + ], + ); + } + + _buildVisibility(bool visible) { + var box = Container( + height: 30, + width: 30, + color: Colors.blue, + ); + return Container( + width: 150, + height: 150 * 0.618, + color: Colors.cyanAccent.withAlpha(33), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + box, + Visibility( + visible: visible, + child: Container( + alignment: Alignment.center, + height: 80 * 0.618, + width: 80, + color: Colors.red, + child: Text( + "visible\ntrue", + style: TextStyle(fontSize: 20), + ), + )), + box, + ], + ), + ); + } +} + +class ReplacementVisibility extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 10, + children: [ + _buildVisibility(true), + _buildVisibility(false), + ], + ); + } + + _buildVisibility(bool visible) { + var box = Container( + height: 30, + width: 30, + color: Colors.blue, + ); + return Container( + width: 150, + height: 150 * 0.618, + color: Colors.cyanAccent.withAlpha(33), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + box, + Visibility( + visible: visible, + replacement: Container( + alignment: Alignment.center, + height: 80 * 0.618, + width: 80, + ), + child: Container( + alignment: Alignment.center, + height: 80 * 0.618, + width: 80, + color: Colors.red, + child: Text( + "visible\ntrue", + style: TextStyle(fontSize: 20), + ), + )), + box, + ], + ), + ); + } +} + +//class VisibilityPage extends StatefulWidget { +// @override +// _VisibilityPageState createState() => _VisibilityPageState(); +//} +// +//class _VisibilityPageState extends State { +// @override +// Widget build(BuildContext context) { +// var visibility = Visibility( +// visible: false, +// replacement: Container( +// alignment: Alignment.center, +// height: 100, +// width: 100, +// ), +// child: Container( +// alignment: Alignment.center, +// height: 100, +// width: 100, +// color: Colors.blue, +// child: Text( +// "Visibility", +// style: TextStyle(fontSize: 20), +// ), +// )); +// +// var radBox = Container( +// height: 50, +// width: 50, +// color: Colors.red, +// ); +// +// return Container( +// width: 200, +// height: 200, +// child: Row( +// children: [radBox, visibility, radBox], +// ), +// ); +// } +//} diff --git a/lib/views/widgets/StatelessWidget/WillPopScope.dart b/lib/views/widgets/StatelessWidget/WillPopScope.dart new file mode 100644 index 0000000..4c1f9ec --- /dev/null +++ b/lib/views/widgets/StatelessWidget/WillPopScope.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-29 +/// contact me by email 1981462002@qq.com +/// 说明: + + +// { +// "widgetId": 170, +// "name": 'WillPopScope使用', +// "priority": 1, +// "subtitle": +// "【child】 : 子组件 【Widget】\n" +// "【onWillPop】 : 返回回调 【WillPopCallback】", +// } +class CustomWillPopScope extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: WillPopScope(child: (BackButton()), + onWillPop: ()=>_willPop(context)), + ); + } + + Future _willPop(context) async{ + return await showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10))), + title: Text('提示'), + content: Text('你确定要离开此页吗?'), + actions: [ + FlatButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text('确定'), + ), + FlatButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text('取消'), + ), + + ], + ), + ) ?? false; + + } +} diff --git a/lib/views/widgets/StatelessWidget/YearPicker.dart b/lib/views/widgets/StatelessWidget/YearPicker.dart new file mode 100644 index 0000000..2d7dee6 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/YearPicker.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +/// create by 张风捷特烈 on 2020-03-25 +/// contact me by email 1981462002@qq.com +/// 说明: +// { +// "widgetId": 136, +// "name": 'YearPicker基本使用', +// "priority": 1, +// "subtitle": +// "【selectedDate】 : 选中日期 【DateTime】\n" +// "【firstDate】 : 最前日期限制 【DateTime】\n" +// "【lastDate】 : 最后日期限制 【DateTime】\n" +// "【onChanged】 : 点击回调 【Function(DateTime)】", +// } +class CustomYearPicker extends StatefulWidget { + @override + _CustomYearPickerState createState() => _CustomYearPickerState(); +} + +class _CustomYearPickerState extends State { + DateTime _date = DateTime.now(); + + @override + Widget build(BuildContext context) { + return Container( + height:150, + child: YearPicker( + selectedDate: _date, + onChanged: (date) => setState(() => _date = date), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + ), + ); + } +} diff --git a/lib/views/widgets/StatelessWidget/stateless_unit.dart b/lib/views/widgets/StatelessWidget/stateless_unit.dart new file mode 100644 index 0000000..cede636 --- /dev/null +++ b/lib/views/widgets/StatelessWidget/stateless_unit.dart @@ -0,0 +1,85 @@ +library stateless_unit; + +export 'Container.dart'; +export 'Text.dart'; +export 'Card.dart'; +export 'FlutterLogo.dart'; +export 'Banner.dart'; +export 'Icon.dart'; +export 'ImageIcon.dart'; +export 'FadeInImage.dart'; +export 'CircleAvatar.dart'; +export 'Visibility.dart'; + +export 'Chip.dart'; +export 'ChoiceChip.dart'; +export 'ActionChip.dart'; +export 'InputChip.dart'; +export 'FilterChip.dart'; + + +export 'ListTile.dart'; +export 'CheckboxListTile.dart'; +export 'SwitchListTile.dart'; +export 'RadioListTile.dart'; +export 'GridTileBar.dart'; +export 'GridTile.dart'; + +export 'MaterialButton.dart'; + +export 'Divider.dart'; + +export 'TabBar.dart'; + +export 'GridPager.dart'; + +export 'Placeholder.dart'; +export 'UserAccountsDrawerHeader.dart'; +export 'VerticalDivider.dart'; + +export 'BackButton.dart'; +export 'ButtonBar.dart'; +export 'CloseButton.dart'; +export 'CupertinoButton.dart'; +export 'FlatButton.dart'; +export 'FloatingActionButton.dart'; +export 'IconButton.dart'; +export 'OutLineButton.dart'; +export 'RaisedButton.dart'; +export 'ToggleButtons.dart'; + + + +export 'AboutListTile.dart'; +export 'CupertinoTheme.dart'; +export 'Drawer.dart'; +export 'DrawerHeader.dart'; +export 'GestureDetector.dart'; +export 'GirdView.dart'; +export 'ListView.dart'; +export 'Listener.dart'; +export 'PositionedDirectional.dart'; +export 'SingleChildScrollView.dart'; +export 'Tab.dart'; +export 'Theme.dart'; +export 'WillPopScope.dart'; +export 'AboutDialog.dart'; +export 'AlertDialog.dart'; +export 'AnimatedIcon.dart'; +export 'BottomSheet.dart'; +export 'CupertinoActionSheet.dart'; +export 'CupertinoActionSheetAction.dart'; +export 'CupertinoAlertDialog.dart'; +export 'CupertinoContextMenu.dart'; +export 'CupertinoContextMenuAction.dart'; +export 'CupertinoDatePicker.dart'; +export 'CupertinoPicker.dart'; +export 'CupertinoTimerPicker.dart'; +export 'DayPicker.dart'; +export 'Dialog.dart'; +export 'MonthPicker.dart'; +export 'SimpleDialog.dart'; +export 'SimpleDialogOption.dart'; +export 'SnackBar.dart'; +export 'SnackBarAction.dart'; +export 'YearPicker.dart'; \ No newline at end of file diff --git a/lib/views/widgets/widgets_map.dart b/lib/views/widgets/widgets_map.dart new file mode 100644 index 0000000..0b90844 --- /dev/null +++ b/lib/views/widgets/widgets_map.dart @@ -0,0 +1,945 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'ProxyWidget/InheritedWidget/ButtonTheme.dart'; +import 'ProxyWidget/InheritedWidget/DefaultTextStyle.dart'; +import 'ProxyWidget/InheritedWidget/DividerTheme.dart'; +import 'ProxyWidget/InheritedWidget/IconTheme.dart'; +import 'ProxyWidget/InheritedWidget/SliderTheme.dart'; +import 'RenderObjectWidget/SingleChildRenderObjectWidget/ShaderMask.dart'; +import 'StatefulWidget/stateful_unit.dart'; +import 'StatelessWidget/stateless_unit.dart'; + +import 'ProxyWidget/DropdownButtonHideUnderline.dart'; +import 'ProxyWidget/Flexible.dart'; +import 'ProxyWidget/InheritedWidget/MediaQuery.dart'; +import 'ProxyWidget/InheritedWidget/ScrollConfiguration.dart'; +import 'ProxyWidget/Positioned.dart'; +import 'StatelessWidget/Spacer.dart'; +import 'RenderObjectWidget/ErrorWidget.dart'; +import 'RenderObjectWidget/MultiChildRenderObjectWidget/Column.dart'; +import 'ProxyWidget/Expended.dart'; +import 'RenderObjectWidget/MultiChildRenderObjectWidget/IndexedStack.dart'; +import 'RenderObjectWidget/MultiChildRenderObjectWidget/Row.dart'; +import 'RenderObjectWidget/SingleChildRenderObjectWidget/AnimatedSize.dart'; +import 'RenderObjectWidget/SingleChildRenderObjectWidget/Center.dart'; +import 'RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/CustomPaint.dart'; +import 'RenderObjectWidget/SingleChildRenderObjectWidget/CustomPaint/colck_page/colck_page.dart'; +import 'RenderObjectWidget/render_object_widget.dart'; +import 'Sliver/CustomScrollView.dart'; +import 'Sliver/FlexibleSpaceBar.dart'; +import 'Sliver/SliverAppBar.dart'; +import 'Sliver/SliverFillViewport.dart'; +import 'Sliver/SliverFixedExtentList.dart'; +import 'Sliver/SliverGrid.dart'; +import 'Sliver/SliverList.dart'; +import 'Sliver/SliverOpacity.dart'; +import 'Sliver/SliverPadding.dart'; +import 'Sliver/SliverPersistentHeader.dart'; +import 'Sliver/SliverToBoxAdapter.dart'; + +/// create by 张风捷特烈 on 2020-03-04 +/// contact me by email 1981462002@qq.com +/// 说明: + +class WidgetsMap { + static List map(String name) { + switch (name) { + case "Container": + return [ + CustomContainer(), + ContainerWithChild(), + ContainerAlignment(), + ContainerDecoration(), + ContainerTransform(), + ContainerConstraints() + ]; + case "Text": + return [ + CustomText(), + ShadowText(), + DecorationText(), + TextAlignText(), + TextDirectionText(), + SoftWrapText() + ]; + case "Card": + return [ + CustomCard(), + ShapeCard(), + ]; + case "FlutterLogo": + return [ + CustomFlutterLogo(), + FlutterLogoWithText(), + ]; + case "Banner": + return [ + CustomBanner(), + ]; + case "Icon": + return [ + CustomIcon(), + MyIcon(), + ]; + case "ImageIcon": + return [ + CustomImageIcon(), + ]; + case "FadeInImage": + return [ + CustomFadeInImage(), + ]; + case "CircleAvatar": + return [ + CustomCircleAvatar(), + ]; + case "Visibility": + return [ + CustomVisibility(), + ReplacementVisibility(), + ]; + case "Chip": + return [ + CustomChip(), + ColorOfChip(), + DeleteOfChip(), + ]; + case "ChoiceChip": + return [CustomChoiceChip()]; + case "ActionChip": + return [CustomActionChip()]; + case "InputChip": + return [PressInputChip(), SelectInputChip()]; + case "FilterChip": + return [CustomFilterChip()]; + case "ListTile": + return [CustomListTile(), SelectListTile(), DenseListTile()]; + case "CheckboxListTile": + return [ + CustomCheckBoxListTile(), + SelectCheckBoxListTile(), + DenseCheckBoxListTile() + ]; + case "SwitchListTile": + return [ + CustomSwitchListTile(), + SelectSwitchListTile(), + DenseSwitchListTile() + ]; + + case "RadioListTile": + return [ + CustomRadioListTile(), + DenseRadioListTile(), + ]; + + case "GridTileBar": + return [ + CustomGridTileBar(), + ]; + + case "GridTile": + return [ + CustomGridTile(), + ]; + case "UserAccountsDrawerHeader": + return [ + CustomUAGHP(), + ProUAGHP(), + ]; + + case "MaterialButton": + return [ + CustomMaterialButton(), + LongPressMaterialButton(), + ShapeMaterialButton(), + ]; + case "CupertinoButton": + return [CustomCupertinoButton()]; + case "FlatButton": + return [CustomFlatButton()]; + case "RaisedButton": + return [CustomRaisedButton()]; + case "OutlineButton": + return [CustomOutlineButton()]; + case "FloatingActionButton": + return [CustomFAB(), MiniFAB(), ShapeFAB()]; + + case "ButtonBar": + return [ + CustomButtonBar(), + PaddingButtonBar(), + ]; + + case "IconButton": + return [ + CustomIconButton(), + ]; + case "BackButton": + return [ + CustomBackButton(), + ]; + + case "CloseButton": + return [ + CustomCloseButton(), + ]; + case "ToggleButtons": + return [ + CustomToggleButtons(), + ColorToggleButtons(), + ProToggleButtons(), + ]; + case "ToggleButtons": + return [ + CustomToggleButtons(), + ColorToggleButtons(), + ProToggleButtons(), + ]; + + case "Divider": + return [ + CustomDivider(), + HeightDivider(), + ]; + case "VerticalDivider": + return [ + CustomVerticalDivider(), + HeightVerticalDivider(), + ]; + case "Placeholder": + return [ + CustomPlaceholder(), + FallbackPlaceholder(), + ]; + case "GridPager": + return [ + CustomGridPage(), + DivisionsGridPage(), + ]; + case "Image": + return [ + LoadImage(), + FitImage(), + AlignmentImage(), + BlendModeImage(), + RepeatImage(), + CenterSliceImage(), + ]; + case "Checkbox": + return [ + CustomCheckbox(), + TristateCheckBok(), + ]; + case "Switch": + return [ + CustomSwitch(), + ImageSwitch(), + ]; + case "CupertinoSwitch": + return [ + CustomCupertinoSwitch(), + ]; + case "Slider": + return [ + CustomSlider(), + DivisionsSlider(), + ]; + case "CupertinoSlider": + return [ + CustomCupertinoSlider(), + ]; + case "RangeSlider": + return [ + CustomRangeSlider(), + ]; + case "Radio": + return [ + CustomRadio(), + ]; + case "CircularProgressIndicator": + return [ + CustomCircularProgressIndicator(), + ]; + case "LinearProgressIndicator": + return [ + CustomLinearProgressIndicator(), + ]; + case "CupertinoActivityIndicator": + return [ + CustomCupertinoActivityIndicator(), + ]; + case "RefreshIndicator": + return [ + CustomRefreshIndicator(), + ]; + case "Tooltip": + return [ + CustomTooltip(), + DecorationTooltip(), + ]; + case "ExpandIcon": + return [ + CustomExpandIcon(), + ]; + case "ExpansionTile": + return [ + CustomExpansionTile(), + ]; + case "SelectableText": + return [ + CustomSelectableText(), + AlignSelectableText(), + ]; + case "TextField": + return [ + CustomTextField(), + CursorTextField(), + ComplexTextField(), + ]; + case "DropdownButton": + return [ + CustomDropDownButton(), + StyleDropDownButton(), + ]; + case "PopupMenuButton": + return [ + CustomPopupMenuButton(), + ]; + case "AppBar": + return [ + CustomAppBar(), + TabAppBar(), + ]; + case "TabBar": + return [ + CustomTabBar(), + NoShadowTabBarDemo(), + ]; + case "TabBarView": + return [ + CustomTabBarView(), + ]; + case "BottomNavigationBar": + return [CustomBottomNavigationBar(), BottomNavigationBarWithPageView()]; + case "BottomAppBar": + return [ + CustomBottomAppBar(), + ]; + case "CupertinoNavigationBar": + return [ + CustomCupertinoNavigationBar(), + ]; + case "CupertinoTabBar": + return [ + CustomCupertinoTabBar(), + ]; + case "Scaffold": + return [ + CustomScaffold(), + ]; + case "MaterialApp": + return [ + CustomMaterialApp(), + ]; + case "ClipOval": + return [ + CustomClipOval(), + ]; + case "ClipRect": + return [ + CustomClipRect(), + ]; + case "ClipRRect": + return [ + CustomClipRRect(), + ]; + case "ClipPath": + return [ + CustomClipPath(), + ]; + case "DecoratedBox": + return [ + CustomDecoratedBox(), + ]; + case "Offstage": + return [ + CustomOffstage(), + ]; + case "RotatedBox": + return [ + CustomRotatedBox(), + ]; + case "Opacity": + return [ + CustomOpacity(), + ]; + case "Padding": + return [ + CustomPadding(), + ]; + case "Baseline": + return [ + CustomBaseline(), + ]; + case "SizedBox": + return [ + CustomSizedBox(), + ]; + case "AspectRatio": + return [ + CustomAspectRatio(), + ]; + case "Transform": + return [ + SkewTransform(), + TranslationTransform(), + ScaleTransform(), + RotateTransform(), + R3C2(), + ]; + case "LimitedBox": + return [ + CustomLimitedBox(), + ]; + case "ConstrainedBox": + return [ + CustomConstrainedBox(), + ]; + case "UnconstrainedBox": + return [ + CustomUnConstrainedBox(), + ]; + case "FractionallySizedBox": + return [ + CustomFractionallySizedBox(), + ]; + case "OverflowBox": + return [ + CustomOverflowBox(), + ]; + case "SizedOverflowBox": + return [ + CustomSizedOverflowBox(), + ]; + case "Align": + return [CustomAlign(), SinLayout()]; + case "Center": + return [ + CustomCenter(), + ]; + case "FittedBox": + return [ + CustomFittedBox(), + ]; + case "ColorFiltered": + return [ + CustomColorFiltered(), + ]; + case "FadeTransition": + return [ + CustomFadeTransition(), + ]; + case "RotationTransition": + return [ + CustomRotationTransition(), + ]; + case "ScaleTransition": + return [ + CustomScaleTransition(), + ]; + case "SizeTransition": + return [ + CustomSizeTransition(), + ]; + case "PositionedTransition": + return [ + CustomPositionedTransition(), + ]; + case "Flex": + return [ + DirectionFlex(), + MainAxisAlignmentFlex(), + CrossAxisAlignmentFlex(), + VerticalDirectionFlex(), + TextDirectionFlex(), + ]; + case "Row": + return [ + CustomRow(), + ]; + case "Column": + return [ + CustomColumn(), + ]; + case "Stack": + return [CustomStack(), PositionedStack()]; + case "Wrap": + return [ + DirectionWrap(), + WrapAlignmentWrap(), + CrossAxisAlignmentWrap(), + TextDirectionWrap(), + VerticalDirectionWrap(), + ]; + case "Flow": + return [ + CircleFlow(), + BurstFlow.show, + ]; + case "AnimatedCrossFade": + return [ + CustomAnimatedCrossFade(), + CurveAnimatedCrossFade(), + ]; + case "RichText": + return [ + CustomRichText(), + RichTextWithWidget(), + ]; + case "DataTable": + return [ + CustomDataTable(), + SortDataTable(), + ]; + case "Draggable": + return [ + CustomDraggable(), + DraggablePage(), + DeleteDraggable(), + ]; + case "DragTarget": + return [ + CustomDragTarget(), + ]; + case "LongPressDraggable": + return [ + CustomLongPressDraggable(), + ]; + case "Expanded": + return [ + CustomExpended(), + ]; + case "Spacer": + return [ + OneSpacer(), + ManySpacer(), + ]; + case "Positioned": + return [ + CustomPositioned(), + ]; + case "Flexible": + return [ + CustomFlexible(), + ]; + case "Table": + return [ + CustomTable(), + ]; + case "AlignTransition": + return [ + CustomAlignTransition(), + ]; + case "DecoratedBoxTransition": + return [ + CustomDecoratedBoxTransition(), + ]; + case "DefaultTextStyleTransition": + return [ + CustomDefaultTextStyleTransition(), + ]; + case "RelativePositionedTransition": + return [ + CustomRelativePositionedTransition(), + ]; + case "AnimatedSwitcher": + return [ + CustomAnimatedSwitcher(), + ]; + case "AnimatedList": + return [ + CustomAnimatedList(), + ]; + case "AnimatedOpacity": + return [ + CustomAnimatedOpacity(), + ]; + case "AnimatedPadding": + return [ + CustomAnimatedPadding(), + ]; + case "AnimatedAlign": + return [ + CustomAnimatedAlign(), + ]; + case "AnimatedPositioned": + return [ + CustomAnimatedPositioned(), + ]; + case "AnimatedPositionedDirectional": + return [ + CustomAnimatedPositionedDirectional(), + ]; + case "AnimatedContainer": + return [ + CustomAnimatedContainer(), + ]; + case "AnimatedDefaultTextStyle": + return [ + CustomAnimatedDefaultTextStyle(), + ]; + case "AnimatedIcon": + return [ + CustomAnimatedIcon(), + ]; + case "Dialog": + return [ + CustomDialog(), + ]; + case "AlertDialog": + return [ + CustomAlertDialog(), + ]; + case "SimpleDialog": + return [ + CustomSimpleDialog(), + ]; + case "CupertinoAlertDialog": + return [ + CustomCupertinoAlertDialog(), + ]; + case "AboutDialog": + return [ + CustomAboutDialog(), + ]; + case "CupertinoActionSheet": + return [ + CustomCupertinoActionSheet(), + ]; + case "CupertinoActionSheetAction": + return [ + CustomCupertinoActionSheetAction(), + ]; + case "SimpleDialogOption": + return [ + CustomSimpleDialogOption(), + ]; + case "DayPicker": + return [ + CustomDayPicker(), + ]; + case "MonthPicker": + return [ + CustomMonthPicker(), + ]; + case "YearPicker": + return [ + CustomYearPicker(), + ]; + case "CupertinoDatePicker": + return [ + CustomCupertinoDatePicker(), + ]; + case "CupertinoTimerPicker": + return [ + CustomCupertinoTimerPicker(), + ]; + case "CupertinoPicker": + return [ + CustomCupertinoPicker(), + ]; + case "SnackBar": + return [ + CustomSnackBar(), + ]; + case "SnackBarAction": + return [ + CustomSnackBarAction(), + ]; + case "BottomSheet": + return [ + CustomBottomSheet(), + ]; + case "CupertinoContextMenu": + return [ + CustomCupertinoContextMenu(), + ]; + case "CupertinoContextMenuAction": + return [ + CustomCupertinoContextMenuAction(), + ]; + case "LicensePage": + return [ + CustomLicensePage(), + ]; + case "GestureDetector": + return [ + CustomGestureDetector(), + TapGestureDetector(), + PanGestureDetector(), + ]; + case "Listener": + return [ + CustomListener(), + ]; + case "Tab": + return [ + CustomTab(), + ]; + case "InkResponse": + return [ + CustomInkResponse(), + ColorInkResponse(), + ]; + case "InkWell": + return [ + CustomInkWell(), + ColorInkWell(), + ]; + case "TableRowInkWell": + return [ + CustomTableRowInkWell(), + ]; + case "Ink": + return [ + CustomInk(), + InkImage(), + ]; + case "RawChip": + return [ + PressRawChip(), + SelectRawChip(), + ]; + case "Drawer": + return [ + CustomDrawer(), + ]; + case "DrawerHeader": + return [ + CustomDrawerHeader(), + ]; + case "CupertinoApp": + return [ + CustomCupertinoApp(), + ]; + case "CupertinoPageScaffold": + return [ + CustomCupertinoPageScaffold(), + ]; + case "CupertinoTabScaffold": + return [ + CustomCupertinoTabScaffold(), + ]; + case "PositionedDirectional": + return [ + CustomPositionedDirectional(), + ]; + case "Material": + return [ + CustomMaterial(), + ShapeMaterial(), + ]; + case "IndexedStack": + return [ + CustomIndexedStack(), + ]; + case "ListView": + return [ + CustomListView(), + HorizontalListView(), + BuilderListView(), + SeparatedListView(), + ]; + case "GridView": + return [ + CustomGridView(), + HorizontalGridView(), + ExtentGridView(), + BuilderGridView() + ]; + case "SingleChildScrollView": + return [ + CustomSingleChildScrollView(), + DirectionSingleChildScrollView(), + ]; + case "PageView": + return [ + CustomPageView(), + DirectionPageView(), + CtrlPageView(), + ]; + case "CustomPaint": + return [ + ClockPage(), + PlayBezier3Page(), + ]; + case "MediaQuery": + return [ + CustomMediaQuery(), + ]; + case "Theme": + return [TextThemeDemo(), CustomTheme()]; + case "CupertinoTheme": + return [TextCupertinoTheme(), CustomCupertinoTheme()]; + case "WillPopScope": + return [ + CustomWillPopScope(), + ]; + case "Hero": + return [ + CustomHero(), + ]; + case "FutureBuilder": + return [ + CustomFutureBuilder(), + ]; + case "StreamBuilder": + return [ + CustomStreamBuilder(), + ]; + case "PopupMenuDivider": + return [ + CustomPopupMenuDivider(), + ]; + case "RawMaterialButton": + return [ + CustomRawMaterialButton(), + ShapeRawMaterialButton(), + ]; + case "Dismissible": + return [ + CustomDismissible(), + DirectionDismissible(), + ]; + case "ReorderableListView": + return [ + CustomReorderableListView(), + DirectionReorderableListView(), + ]; + case "ExpansionPanelList": + return [ + CustomExpansionPanelList(), + ]; + case "ListWheelScrollView": + return [ + CustomListWheelScrollView(), + ]; + case "ScrollConfiguration": + return [ + CustomScrollConfiguration(), + ]; + case "DropdownButtonHideUnderline": + return [ + CustomDropDownButtonHideUnderline(), + ]; + case "Overlay": + return [ + CustomOverlay(), + ]; + case "CustomScrollView": + return [ + CustomScrollViewDemo(), + ]; + case "SliverAppBar": + return [ + SliverAppBarDemo(), + ]; + case "SliverList": + return [ + SliverListDemo(), + ]; + case "SliverFixedExtentList": + return [ + SliverFixedExtentListDemo(), + ]; + case "SliverFillViewport": + return [ + SliverFillViewportDemo(), + ]; + case "SliverGird": + return [ + SliverGirdDemo(), + ]; + case "SliverToBoxAdapter": + return [ + SliverToBoxAdapterDemo(), + ]; + case "SliverPersistentHeader": + return [ + SliverPersistentHeaderDemo(), + ]; + case "SliverPadding": + return [ + SliverPaddingDemo(), + ]; + case "SliverOpacity": + return [ + SliverOpacityDemo(), + ]; + case "AboutListTile": + return [ + AboutListTileDemo(), + ]; + case "Scrollbar": + return [ + CustomScrollbar(), + ]; + case "CupertinoScrollbar": + return [ + CustomCupertinoScrollbar(), + ]; + case "FlexibleSpaceBar": + return [ + FlexibleSpaceBarDemo(), + ]; + case "ErrorWidget": + return [ + ErrorWidgetDemo(), + ]; + case "Form": + return [ + CustomForm(), + ]; + case "TextFormField": + return [ + CustomTextFormField(), + ]; + case "Stepper": + return [ + StepperDemo(), + VerticalStepper(), + ]; + case "AnimatedSize": + return [ + CustomAnimatedSize(), + ]; + case "ShaderMask": + return [ + RadialShaderMask(), + LinearShaderMask(), + ]; + case "DefaultTextStyle": + return [ + DefaultTextStyleDemo(), + ]; + case "IconTheme": + return [ + IconThemeDemo(), + ]; + case "ButtonTheme": + return [ + ButtonThemeDemo(), + ]; + case "DividerTheme": + return [ + DividerThemeDemo(), + ]; + case "SliderTheme": + return [ + SliderThemeDemo(), + DIYSliderTheme(), + ]; + } + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..f2b6415 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,348 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.11" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.2" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + bloc: + dependency: transitive + description: + name: bloc + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.11" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.2.0" + flutter_star: + dependency: "direct main" + description: + name: flutter_star + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.0+1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + provider: + dependency: transitive + description: + name: provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.4" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.5" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.23.1" + share: + dependency: "direct main" + description: + name: share + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.3+6" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.6+3" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+6" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.3" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2+4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.5" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.11" + toggle_rotate: + dependency: "direct main" + description: + name: toggle_rotate + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.5" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.4.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+4" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.6" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.1+1" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.5.0" +sdks: + dart: ">=2.7.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..384863c --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,88 @@ +name: flutter_unit +description: A new Flutter application. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.3.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_bloc: ^3.2.0 + equatable: ^1.0.3 + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + sqflite: ^1.2.1 #数据库 + toggle_rotate: ^0.0.5 + flutter_star: ^0.1.2 # 星星组件 + shared_preferences: ^0.5.6+3 # xml 固化 + url_launcher: ^5.4.2 # url + share: ^0.6.3+6 +dev_dependencies: + flutter_test: + sdk: flutter + + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + assets: + - assets/images/ + - assets/images/head_icon/ + - assets/images/widgets/ + # - assets/data/widget.json + - assets/flutter.db + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + fonts: # 配置字体,可配置多个,支持ttf和otf,ttc等字体资源 + - family: IndieFlower #字体名 + fonts: + - asset: assets/fonts/IndieFlower-Regular.ttf + - family: BalooBhai2 #字体名 + fonts: + - asset: assets/fonts/BalooBhai2-Regular.ttf + - family: Inconsolata #字体名 + fonts: + - asset: assets/fonts/Inconsolata-Regular.ttf + - family: Neucha #字体名 + fonts: + - asset: assets/fonts/Neucha-Regular.ttf + - family: ComicNeue #字体名 + fonts: + - asset: assets/fonts/ComicNeue-Regular.ttf + - family: TolyIcon + fonts: + - asset: assets/iconfont/iconfont.ttf \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..3cefce4 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +//// This is a basic Flutter widget test. +//// +//// To perform an interaction with a widget in your test, use the WidgetTester +//// utility that Flutter provides. For example, you can send tap and scroll +//// gestures. You can also use WidgetTester to find child widgets in the widget +//// tree, read text, and verify that the values of widget properties are correct. +// +//import 'package:flutter/material.dart'; +//import 'package:flutter_test/flutter_test.dart'; +// +//import 'package:flutter_unit/main.dart'; +// +//void main() { +// testWidgets('Counter increments smoke test', (WidgetTester tester) async { +// // Build our app and trigger a frame. +// await tester.pumpWidget(MyApp()); +// +// // Verify that our counter starts at 0. +// expect(find.text('0'), findsOneWidget); +// expect(find.text('1'), findsNothing); +// +// // Tap the '+' icon and trigger a frame. +// await tester.tap(find.byIcon(Icons.add)); +// await tester.pump(); +// +// // Verify that our counter has incremented. +// expect(find.text('0'), findsNothing); +// expect(find.text('1'), findsOneWidget); +// }); +//}