From 53b87b34150a69da5172ef5d868ca74f02a0d559 Mon Sep 17 00:00:00 2001 From: violinday Date: Sat, 2 Apr 2022 10:51:17 +0800 Subject: [PATCH 01/19] update version to 2.1.1 (#168) --- CHANGELOG.md | 2 +- README.en-US.md | 2 +- README.md | 2 +- pubspec.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e17668..aca34a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [2.1.0-nullsafety] - 2022-4-1 +## [2.1.1] - 2022-4-1 ### Changed diff --git a/README.en-US.md b/README.en-US.md index 7da4eada..56120bac 100644 --- a/README.en-US.md +++ b/README.en-US.md @@ -48,7 +48,7 @@ If you cannot access the demo, you can directly watch [Overview](https://github. | ---------- | ---------------- | | 1.0.0 | 1.22.4 | | 2.0.0 | 2.2.2 | -| 2.1.0-nullsafety | 2.2.2 | +| 2.1.1 (support nullsafety) | 2.2.2 | ## Preparing for use diff --git a/README.md b/README.md index 4c0b5ea9..11d3ef29 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ | ---------- | ---------------- | | 1.0.0 | 1.22.4 | | 2.0.0 | 2.2.2 | -| 2.1.0-nullsafety | 2.2.2 | +| 2.1.1 (支持空安全) | 2.2.2 | diff --git a/pubspec.yaml b/pubspec.yaml index 1f6220b4..6ed0939a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bruno description: An enterprise-class package of Flutter components for mobile applications. -version: 2.1.0-nullsafety +version: 2.1.1 homepage: https://github.com/LianjiaTech/bruno environment: From 4ea6e5b2f283a97a02e613428d0dc77c46a707f9 Mon Sep 17 00:00:00 2001 From: violinday Date: Wed, 6 Apr 2022 15:00:28 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E5=AE=9A=E5=88=B6=E6=96=87=E6=A1=A3=E7=BB=86=E8=8A=82=E3=80=82?= =?UTF-8?q?=20(#173)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/theme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/theme.md b/doc/theme.md index c6bf0f39..a569b59c 100644 --- a/doc/theme.md +++ b/doc/theme.md @@ -113,6 +113,6 @@ BrnMultiChoiceInputFormItem( subTitle: "这里是副标题", tipLabel: "标签", ... - themeData: BrnFormItemV2Config(titleTextStyle:BrnTextStyle(color: Colors.red)), + themeData: BrnFormItemConfig(titleTextStyle:BrnTextStyle(color: Colors.red)), ) ``` From 2d022e5e32912484490f5672744faaf3211f36a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E9=99=86?= Date: Mon, 11 Apr 2022 18:00:09 +0800 Subject: [PATCH 03/19] fix: maxLength 100 -> 10 (#176) --- example/lib/sample/components/dialog/dialog_entry_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/sample/components/dialog/dialog_entry_page.dart b/example/lib/sample/components/dialog/dialog_entry_page.dart index a4be831e..704f85bd 100644 --- a/example/lib/sample/components/dialog/dialog_entry_page.dart +++ b/example/lib/sample/components/dialog/dialog_entry_page.dart @@ -533,7 +533,7 @@ class DialogEntryPage extends StatelessWidget { hintText: '提示信息', cancelText: '取消', confirmText: '确定', - maxLength: 100, + maxLength: 10, barrierDismissible: false, textInputAction: TextInputAction.done, onConfirm: (value) { From b4b5a9230fdee4ae3982e910a171a1424cdd3b2b Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Tue, 19 Apr 2022 11:52:05 +0800 Subject: [PATCH 04/19] fix BrnTitleFormItem attribute isRequire doesn't work (#183) --- lib/src/components/form/items/misc/brn_title_item.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/components/form/items/misc/brn_title_item.dart b/lib/src/components/form/items/misc/brn_title_item.dart index 7c786007..6582b5cf 100644 --- a/lib/src/components/form/items/misc/brn_title_item.dart +++ b/lib/src/components/form/items/misc/brn_title_item.dart @@ -100,6 +100,8 @@ class BrnTitleFormItemState extends State { widget.isRequire, widget.themeData!), child: Row( children: [ + // 必填项 + BrnFormUtil.buildRequireWidget(widget.isRequire), // 主标题 Container( child: Text( @@ -107,7 +109,6 @@ class BrnTitleFormItemState extends State { style: BrnFormUtil.getHeadTitleTextStyle( widget.themeData!), )), - // 问号提示 BrnFormUtil.buildTipLabelWidget( widget.tipLabel, widget.onTip, widget.themeData!), From 9ab6b08fd7b9065f794b21a82c9c91194025cfcc Mon Sep 17 00:00:00 2001 From: xiao luobei <56096275+liu-cn@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:34:14 +0800 Subject: [PATCH 05/19] =?UTF-8?q?BrnTextBlockInputFormItem=20maxLines?= =?UTF-8?q?=E3=80=81minLines=20=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=8F=AF=E4=B8=BA=20nulll=EF=BC=8C=E6=94=AF=E6=8C=81=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=B3=95=E6=8D=A2=E8=A1=8C=EF=BC=8C=E4=B8=94=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E8=A1=8C=E6=95=B0=E9=9A=8F=E9=94=AE=E5=85=A5=E7=9A=84?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E8=87=AA=E5=8A=A8=E6=89=A9=E9=95=BF=20(#181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BrnTextBlockInputFormItem maxLines 参数设置可为null,为null输入法可以换行,并且行数随键入的文本自动扩长 * BrnTextBlockInputFormItem maxLines minLines 参数设置可为null,为null输入法可以换行,并且行数随键入的文本自动扩长 --- .../form/items/general/brn_text_block_input_item.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/components/form/items/general/brn_text_block_input_item.dart b/lib/src/components/form/items/general/brn_text_block_input_item.dart index 3bc7699d..a2ec5da3 100644 --- a/lib/src/components/form/items/general/brn_text_block_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_block_input_item.dart @@ -75,10 +75,10 @@ class BrnTextBlockInputFormItem extends StatefulWidget { final TextEditingController? controller; /// 最小行数,默认值4 - final int minLines; + final int? minLines; /// 最大行数,默认值20 - final int maxLines; + final int? maxLines; /// form配置 BrnFormItemConfig? themeData; From dda5c23b0f83c8959ae440aa7048f261e925e45b Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 22 Apr 2022 17:00:03 +0800 Subject: [PATCH 06/19] fix: Build failed due to use of deprecated Android v1 embedding. (#188) --- .github/workflows/build_test.yml | 4 +- example/android/app/build.gradle | 22 ++++-- .../android/app/src/debug/AndroidManifest.xml | 7 ++ .../android/app/src/main/AndroidManifest.xml | 75 ++++++++----------- .../com/example/example/MainActivity.java | 12 --- .../kotlin/com/example/bruno/MainActivity.kt | 6 ++ .../res/drawable-v21/launch_background.xml | 12 +++ .../app/src/main/res/values-night/styles.xml | 18 +++++ .../app/src/main/res/values/styles.xml | 13 +++- .../app/src/profile/AndroidManifest.xml | 7 ++ example/android/build.gradle | 8 +- example/android/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 18 ++--- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- 15 files changed, 124 insertions(+), 83 deletions(-) create mode 100644 example/android/app/src/debug/AndroidManifest.xml delete mode 100644 example/android/app/src/main/java/com/example/example/MainActivity.java create mode 100644 example/android/app/src/main/kotlin/com/example/bruno/MainActivity.kt create mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/android/app/src/main/res/values-night/styles.xml create mode 100644 example/android/app/src/profile/AndroidManifest.xml diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index b35a486c..e544af93 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -20,7 +20,7 @@ jobs: java-version: '8.x' - uses: subosito/flutter-action@v1 with: - flutter-version: '2.2.3' + flutter-version: '2.10.3' - run: dart --version - run: flutter --version - run: flutter pub get @@ -40,7 +40,7 @@ jobs: java-version: '8.x' - uses: subosito/flutter-action@v1 with: - flutter-version: '2.2.3' + flutter-version: '2.10.3' - run: dart --version - run: flutter --version - run: flutter pub get diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index c36a549e..749c220f 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -22,20 +22,30 @@ if (flutterVersionName == null) { } apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion flutter.compileSdkVersion - lintOptions { - disable 'InvalidPackage' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.beike.bruno" - minSdkVersion 21 - targetSdkVersion 28 + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } @@ -54,5 +64,5 @@ flutter { } dependencies { - implementation 'androidx.appcompat:appcompat:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..d06bf725 --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index c642e689..b049f539 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,45 +1,34 @@ - - - - - - - - - - - - - - - - - - - + package="com.example.bruno"> + + + + + + + + + + + + diff --git a/example/android/app/src/main/java/com/example/example/MainActivity.java b/example/android/app/src/main/java/com/example/example/MainActivity.java deleted file mode 100644 index b55ae6e0..00000000 --- a/example/android/app/src/main/java/com/example/example/MainActivity.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.example; - -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; - -public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } -} diff --git a/example/android/app/src/main/kotlin/com/example/bruno/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/bruno/MainActivity.kt new file mode 100644 index 00000000..03c56933 --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/bruno/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.bruno + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..3db14bb5 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index c745a5ef..d460d1e9 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,11 +1,18 @@ - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..d06bf725 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle index bb8a3038..4256f917 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,18 +1,20 @@ buildscript { + ext.kotlin_version = '1.6.10' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index a5965ab8..4d3226ab 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,3 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2819f022..bc6a58af 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14fb..44e62bcf 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,11 @@ include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..f2872cf4 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 From 6f2b484311e901e51ec4ed6ec2a2cd0b074162bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E9=99=86?= Date: Sun, 24 Apr 2022 09:59:49 +0800 Subject: [PATCH 07/19] =?UTF-8?q?fix:=20selection=20"=E4=B8=8D=E9=99=90"?= =?UTF-8?q?=20=E9=80=89=E9=A1=B9=E6=97=A0=E6=95=88=20(#185)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../brn_selection_single_list_widget.dart | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart index c7f30183..246900ac 100644 --- a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart @@ -204,8 +204,17 @@ class _BrnSelectionSingleListWidgetState void configMultiLevelList( BrnSelectionEntity selectedEntity, int currentListIndex) { - /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 - if (BrnSelectionFilterType.radio == selectedEntity.filterType) { + /// 选中【不限】清除同一级别其他的状态 + if(selectedEntity.isUnLimit()){ + selectedEntity.parent?.children + .where((f) => f != selectedEntity) + .forEach((f) { + f.clearChildSelection(); + f.isSelected = false; + }); + selectedEntity.isSelected = true; + } else if (BrnSelectionFilterType.radio == selectedEntity.filterType) { + /// 单选,清除同一级别选中的状态,则其他的设置为未选中。 selectedEntity.parent?.children .where((f) => f != selectedEntity) .forEach((f) { @@ -214,16 +223,6 @@ class _BrnSelectionSingleListWidgetState }); selectedEntity.isSelected = true; } else if (BrnSelectionFilterType.checkbox == selectedEntity.filterType) { - /// 选中【不限】清除同一级别其他的状态 - if (selectedEntity.isUnLimit()) { - selectedEntity.parent?.children - .where((f) => f != selectedEntity) - .forEach((f) { - f.clearChildSelection(); - f.isSelected = false; - }); - selectedEntity.isSelected = true; - } else { ///清除【不限】类型。 List brotherItems; if (selectedEntity.parent == null) { @@ -238,7 +237,6 @@ class _BrnSelectionSingleListWidgetState } } selectedEntity.isSelected = !selectedEntity.isSelected; - } } } } From 3794e12015abdb5a81ab3b4bced27d0c2f3d923d Mon Sep 17 00:00:00 2001 From: violinday Date: Sun, 24 Apr 2022 10:02:04 +0800 Subject: [PATCH 08/19] perf: flutter analyze issues. (#189) * perf: flutter analyze issues. * perf: flutter analyze issues. --- .../lib/sample/components/card/bubble/bubble_entry_page.dart | 1 - .../components/card/content/text_content_entry_page.dart | 1 - .../form/items_example/text_quick_select_input_example.dart | 1 - .../components/form/items_example/text_select_example.dart | 1 - example/lib/sample/components/guide/guide_entry_page.dart | 1 - example/lib/sample/components/input/input_example.dart | 1 - example/lib/sample/components/step/step_example.dart | 1 - example/lib/sample/home/expandable_container_widget.dart | 1 - example/lib/sample/theme/config_test_utils.dart | 3 --- .../components/card/content_card/brn_enhance_number_card.dart | 1 - lib/src/components/form/items/group/brn_expandable_group.dart | 1 - .../components/form/items/group/element_expand_widget.dart | 1 - lib/src/components/picker/base/brn_picker.dart | 1 - lib/src/components/picker/brn_bottom_picker.dart | 1 - lib/src/components/picker/brn_picker_cliprrect.dart | 2 -- .../components/picker/brn_select_tags_with_input_picker.dart | 1 - .../selection/controller/brn_selection_view_controller.dart | 1 - .../controller/brn_selection_view_date_picker_controller.dart | 1 - .../components/selection/widget/brn_flat_selection_item.dart | 1 - .../selection/widget/brn_layer_more_selection_page.dart | 2 +- .../selection/widget/brn_selection_range_widget.dart | 1 - lib/src/components/sugsearch/brn_search_text.dart | 1 - lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart | 4 +--- .../tabbar/indicator/brn_fixed_underline_decoration.dart | 3 --- lib/src/components/tabbar/normal/brn_tab_bar.dart | 2 +- lib/src/components/tag/tagview/brn_delete_tag.dart | 1 - lib/src/theme/configs/brn_all_config.dart | 2 +- lib/src/theme/configs/brn_card_title_config.dart | 2 +- 28 files changed, 5 insertions(+), 35 deletions(-) diff --git a/example/lib/sample/components/card/bubble/bubble_entry_page.dart b/example/lib/sample/components/card/bubble/bubble_entry_page.dart index 139d169c..618e1fdc 100644 --- a/example/lib/sample/components/card/bubble/bubble_entry_page.dart +++ b/example/lib/sample/components/card/bubble/bubble_entry_page.dart @@ -4,7 +4,6 @@ import 'package:bruno/bruno.dart'; import 'package:example/sample/components/card/bubble/common_bubble_example.dart'; import 'package:example/sample/components/card/bubble/brn_expanded_bubble_example.dart'; import 'package:example/sample/home/list_item.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class BubbleEntryPage extends StatelessWidget { diff --git a/example/lib/sample/components/card/content/text_content_entry_page.dart b/example/lib/sample/components/card/content/text_content_entry_page.dart index a38c6a4b..938931c6 100644 --- a/example/lib/sample/components/card/content/text_content_entry_page.dart +++ b/example/lib/sample/components/card/content/text_content_entry_page.dart @@ -9,7 +9,6 @@ import 'package:example/sample/components/card/content/brn_two_rich_content_exam import 'package:example/sample/components/card/content/brn_two_text_content_example.dart'; import 'package:example/sample/components/card/content/brn_two_text_expanded_example.dart'; import 'package:example/sample/home/list_item.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class TextContentEntryPage extends StatelessWidget { diff --git a/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart b/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart index e4a8ede0..aa3d9205 100644 --- a/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart +++ b/example/lib/sample/components/form/items_example/text_quick_select_input_example.dart @@ -2,7 +2,6 @@ import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class TextQuickSelectInputExamplePage extends StatefulWidget { final String _title; diff --git a/example/lib/sample/components/form/items_example/text_select_example.dart b/example/lib/sample/components/form/items_example/text_select_example.dart index 7a689bbd..0fccc6c9 100644 --- a/example/lib/sample/components/form/items_example/text_select_example.dart +++ b/example/lib/sample/components/form/items_example/text_select_example.dart @@ -2,7 +2,6 @@ import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class TextSelectInputExamplePage extends StatelessWidget { final String _title; diff --git a/example/lib/sample/components/guide/guide_entry_page.dart b/example/lib/sample/components/guide/guide_entry_page.dart index 7b991338..20faacbd 100644 --- a/example/lib/sample/components/guide/guide_entry_page.dart +++ b/example/lib/sample/components/guide/guide_entry_page.dart @@ -4,7 +4,6 @@ import 'package:bruno/bruno.dart'; import 'package:example/sample/components/guide/force_guide_example.dart'; import 'package:example/sample/components/guide/soft_intro_example.dart'; import 'package:example/sample/home/list_item.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class GuideEntryPage extends StatelessWidget { diff --git a/example/lib/sample/components/input/input_example.dart b/example/lib/sample/components/input/input_example.dart index 1b15e211..7321205a 100644 --- a/example/lib/sample/components/input/input_example.dart +++ b/example/lib/sample/components/input/input_example.dart @@ -2,7 +2,6 @@ import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class TextModel { String? text; diff --git a/example/lib/sample/components/step/step_example.dart b/example/lib/sample/components/step/step_example.dart index 03d7833d..7f506f22 100644 --- a/example/lib/sample/components/step/step_example.dart +++ b/example/lib/sample/components/step/step_example.dart @@ -4,7 +4,6 @@ import 'package:bruno/bruno.dart'; import 'package:example/sample/components/step/brn_horizontal_step_example.dart'; import 'package:example/sample/components/step/step_line_example.dart'; import 'package:example/sample/home/list_item.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class StepExample extends StatelessWidget { diff --git a/example/lib/sample/home/expandable_container_widget.dart b/example/lib/sample/home/expandable_container_widget.dart index d181f177..61c3dfb1 100644 --- a/example/lib/sample/home/expandable_container_widget.dart +++ b/example/lib/sample/home/expandable_container_widget.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// A single-line [ListTile] with a trailing button that expands or collapses /// the tile to reveal or hide the [children]. diff --git a/example/lib/sample/theme/config_test_utils.dart b/example/lib/sample/theme/config_test_utils.dart index cffa9237..d0aab072 100644 --- a/example/lib/sample/theme/config_test_utils.dart +++ b/example/lib/sample/theme/config_test_utils.dart @@ -1,7 +1,4 @@ - -import 'dart:ui'; - import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; diff --git a/lib/src/components/card/content_card/brn_enhance_number_card.dart b/lib/src/components/card/content_card/brn_enhance_number_card.dart index 155db31f..9fae5469 100644 --- a/lib/src/components/card/content_card/brn_enhance_number_card.dart +++ b/lib/src/components/card/content_card/brn_enhance_number_card.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/constants/brn_strings_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 强化数字展示的组件 /// diff --git a/lib/src/components/form/items/group/brn_expandable_group.dart b/lib/src/components/form/items/group/brn_expandable_group.dart index 33419c5b..debd5420 100644 --- a/lib/src/components/form/items/group/brn_expandable_group.dart +++ b/lib/src/components/form/items/group/brn_expandable_group.dart @@ -10,7 +10,6 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// A single-line [ListTile] with a trailing button that expands or collapses /// the tile to reveal or hide the [children]. diff --git a/lib/src/components/form/items/group/element_expand_widget.dart b/lib/src/components/form/items/group/element_expand_widget.dart index 2d082ed1..6cb1f8e6 100644 --- a/lib/src/components/form/items/group/element_expand_widget.dart +++ b/lib/src/components/form/items/group/element_expand_widget.dart @@ -10,7 +10,6 @@ import 'package:bruno/src/theme/configs/brn_form_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// A single-line [ListTile] with a trailing button that expands or collapses /// the tile to reveal or hide the [children]. diff --git a/lib/src/components/picker/base/brn_picker.dart b/lib/src/components/picker/base/brn_picker.dart index c44c3037..2b08b40f 100644 --- a/lib/src/components/picker/base/brn_picker.dart +++ b/lib/src/components/picker/base/brn_picker.dart @@ -8,7 +8,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; /// Color of the 'magnifier' lens border. const Color _kHighlighterBorder = Color(0xFFF0F0F0); diff --git a/lib/src/components/picker/brn_bottom_picker.dart b/lib/src/components/picker/brn_bottom_picker.dart index 91a531c9..2d6ba65e 100644 --- a/lib/src/components/picker/brn_bottom_picker.dart +++ b/lib/src/components/picker/brn_bottom_picker.dart @@ -5,7 +5,6 @@ import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_picker_cliprrect.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; /// 该picker用于显示自定的底部弹出框: 对话框结构如下: /// column diff --git a/lib/src/components/picker/brn_picker_cliprrect.dart b/lib/src/components/picker/brn_picker_cliprrect.dart index ca5ac7e3..288acaf6 100644 --- a/lib/src/components/picker/brn_picker_cliprrect.dart +++ b/lib/src/components/picker/brn_picker_cliprrect.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; /// Picker 顶端 圆角装饰类,参考系统 [ClipRRect], diff --git a/lib/src/components/picker/brn_select_tags_with_input_picker.dart b/lib/src/components/picker/brn_select_tags_with_input_picker.dart index 23f93c8c..ec480659 100644 --- a/lib/src/components/picker/brn_select_tags_with_input_picker.dart +++ b/lib/src/components/picker/brn_select_tags_with_input_picker.dart @@ -3,7 +3,6 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; ///传入的泛型数据转换为值 以填充Widget typedef SelectTagWithInputValueGetter = String Function(V data); diff --git a/lib/src/components/selection/controller/brn_selection_view_controller.dart b/lib/src/components/selection/controller/brn_selection_view_controller.dart index 2dc25955..1da1450c 100644 --- a/lib/src/components/selection/controller/brn_selection_view_controller.dart +++ b/lib/src/components/selection/controller/brn_selection_view_controller.dart @@ -1,5 +1,4 @@ import 'package:bruno/src/utils/brn_event_bus.dart'; -import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; class BrnSelectionListViewController extends ChangeNotifier { diff --git a/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart b/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart index 7a121008..092bcfd5 100644 --- a/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart +++ b/lib/src/components/selection/controller/brn_selection_view_date_picker_controller.dart @@ -1,4 +1,3 @@ -import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; class BrnSelectionDatePickerController extends ChangeNotifier { diff --git a/lib/src/components/selection/widget/brn_flat_selection_item.dart b/lib/src/components/selection/widget/brn_flat_selection_item.dart index 2154786c..fd8c4de2 100644 --- a/lib/src/components/selection/widget/brn_flat_selection_item.dart +++ b/lib/src/components/selection/widget/brn_flat_selection_item.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:ui'; import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; diff --git a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart index 24880dd1..949514ce 100644 --- a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart +++ b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart @@ -140,7 +140,7 @@ class _BrnLayerMoreSelectionPageState extends State Navigator.pop(context, widget.entityData); }, ), - brightness: Brightness.light, + systemOverlayStyle: SystemUiOverlayStyle.dark, backgroundColor: Colors.white, title: Text( '选择${widget.entityData.title}', diff --git a/lib/src/components/selection/widget/brn_selection_range_widget.dart b/lib/src/components/selection/widget/brn_selection_range_widget.dart index b9d28714..22c1b0dc 100644 --- a/lib/src/components/selection/widget/brn_selection_range_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_widget.dart @@ -18,7 +18,6 @@ import 'package:bruno/src/utils/brn_event_bus.dart'; import 'package:bruno/src/utils/brn_text_util.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; typedef void BrnOnRangeSelectionBgClick(); diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index ebd7befb..51b85212 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -1,7 +1,6 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// 搜索框内容变化回调 diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index 70776a9e..d1da1a05 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -4,8 +4,6 @@ import 'dart:collection' show Queue; import 'dart:math' as math; import 'package:bruno/bruno.dart'; -import 'package:bruno/src/components/tabbar/bottom/brn_bottom_tab_bar_item.dart'; -import 'package:bruno/src/theme/configs/brn_all_config.dart'; import 'package:flutter/material.dart'; /// 定义一些UI常量,根据UI稿进行填写 @@ -213,7 +211,7 @@ class _BottomTabBarState extends State with TickerProviderState themeColor = themeData.primaryColor; break; case Brightness.dark: - themeColor = themeData.accentColor; + themeColor = themeData.colorScheme.secondary; break; } final ColorTween colorTween = ColorTween( diff --git a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart index b7f15bc1..59f15900 100644 --- a/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_fixed_underline_decoration.dart @@ -2,10 +2,7 @@ // 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:flutter/widgets.dart'; /// Used with [TabBar.indicator] to draw a horizontal line below the /// selected tab. diff --git a/lib/src/components/tabbar/normal/brn_tab_bar.dart b/lib/src/components/tabbar/normal/brn_tab_bar.dart index 1e813c4f..3b4f5090 100644 --- a/lib/src/components/tabbar/normal/brn_tab_bar.dart +++ b/lib/src/components/tabbar/normal/brn_tab_bar.dart @@ -134,7 +134,7 @@ class BrnTabBar extends StatefulWidget { this.tagSpacing, this.preLineTagCount, this.tagHeight, - }) : assert(tabs == null || tabs is List) { + }) : assert(tabs == null) { this.themeData ??= BrnTabBarConfig(); this.themeData = this.themeData!.merge(BrnTabBarConfig( backgroundColor: backgroundcolor, diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index 2fb00e75..1ae47149 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -2,7 +2,6 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; /// 删除模式的标签 /// 支持下下流式和横向滑动布局 diff --git a/lib/src/theme/configs/brn_all_config.dart b/lib/src/theme/configs/brn_all_config.dart index fe244f36..fa281b52 100644 --- a/lib/src/theme/configs/brn_all_config.dart +++ b/lib/src/theme/configs/brn_all_config.dart @@ -1,4 +1,4 @@ -import 'package:bruno/bruno.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_abnormal_state_config.dart'; import 'package:bruno/src/theme/configs/brn_action_sheet_config.dart'; diff --git a/lib/src/theme/configs/brn_card_title_config.dart b/lib/src/theme/configs/brn_card_title_config.dart index 95ea6a70..2d95fa42 100644 --- a/lib/src/theme/configs/brn_card_title_config.dart +++ b/lib/src/theme/configs/brn_card_title_config.dart @@ -1,5 +1,5 @@ -import 'package:bruno/bruno.dart'; import 'package:bruno/src/theme/base/brn_base_config.dart'; +import 'package:bruno/src/theme/base/brn_default_config_utils.dart'; import 'package:bruno/src/theme/base/brn_text_style.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_common_config.dart'; From fb2dc9e9ac8c5add7094f8f7b8a0525f7a7cc957 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Mon, 25 Apr 2022 09:57:57 +0800 Subject: [PATCH 09/19] add type attribute and optimize iconColor usage (#192) --- .../components/bottom_tabbar/bottom_tabbar_example.dart | 2 ++ .../components/tabbar/bottom/brn_bottom_tab_bar_main.dart | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart index 80473add..df185807 100644 --- a/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart +++ b/example/lib/sample/components/bottom_tabbar/bottom_tabbar_example.dart @@ -175,6 +175,7 @@ class BottomTabbarExampleState extends State BrnBottomTabBar( fixedColor: Colors.blue, currentIndex: _selectedIndexTest2, + type: BrnBottomTabBarDisplayType.shifting, onTap: _onItemSelectedTest2, items: [ BrnBottomTabBarItem(icon: Icon(icons[0]), title: Text(titles[0])), @@ -187,6 +188,7 @@ class BottomTabbarExampleState extends State ), BrnBottomTabBar( fixedColor: Colors.blue, + type: BrnBottomTabBarDisplayType.shifting, currentIndex: _selectedIndexTest3, onTap: _onItemSelectedTest3, items: _getTabBarItems(count: 8), diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index d1da1a05..810a2ce7 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -31,7 +31,7 @@ class BrnBottomTabBar extends StatefulWidget { required this.items, this.onTap, this.currentIndex = 0, - BrnBottomTabBarDisplayType type = BrnBottomTabBarDisplayType.fixed, + this.type = BrnBottomTabBarDisplayType.fixed, this.fixedColor, this.iconSize = 24.0, this.isAnimation = false, @@ -43,9 +43,6 @@ class BrnBottomTabBar extends StatefulWidget { 'Every item must have a non-null title', ), assert(0 <= currentIndex && currentIndex < items.length), - type = items.length <= 3 - ? BrnBottomTabBarDisplayType.fixed - : BrnBottomTabBarDisplayType.shifting, super(key: key); /// 动画是否可见,默认:true @@ -427,7 +424,7 @@ class _BottomNavigationTile extends StatelessWidget { break; case BrnBottomTabBarDisplayType.shifting: tweenStart = 16.0; - iconColor = Colors.blue; + iconColor = selected ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary : null; break; } return Align( From e8ea4c3396c02000cbe679081c698b8a74218def Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Tue, 26 Apr 2022 12:29:08 +0800 Subject: [PATCH 10/19] fix theme merge order error (#194) * fix theme merge order error * fix BrnMultiSelectTagsPicker tag show error * revert BrnTextStyle change * fix import --- .../BrnBottomTabBar/BrnBottomTabBar.md | 2 +- doc/components/tabbar/BrnTabBar/BrnTabBar.md | 10 ++-- .../tag/BrnSelectTag/BrnSelectTag.md | 8 +-- .../content_card/brn_pair_info_rich_grid.dart | 4 +- .../content_card/brn_pair_info_table.dart | 32 ++++++------ .../picker/brn_mulit_select_tags_picker.dart | 50 +++++++++---------- .../components/picker/brn_multi_picker.dart | 17 +++---- .../picker/brn_tags_common_picker.dart | 7 +-- .../picker/brn_tags_picker_config.dart | 5 +- .../components/tabbar/normal/brn_tab_bar.dart | 24 ++++----- .../tag/tagview/brn_delete_tag.dart | 6 +-- .../tag/tagview/brn_select_tag.dart | 8 +-- 12 files changed, 83 insertions(+), 90 deletions(-) diff --git a/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md index 10c268e4..3e8deced 100644 --- a/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md +++ b/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md @@ -29,7 +29,7 @@ BrnBottomTabBar({ required this.items, this.onTap, this.currentIndex = 0, - BrnBottomTabBarDisplayType type = BrnBottomTabBarDisplayType.fixed, + this.type = BrnBottomTabBarDisplayType.fixed, this.fixedColor, this.iconSize = 24.0, this.isAnimation = false, diff --git a/doc/components/tabbar/BrnTabBar/BrnTabBar.md b/doc/components/tabbar/BrnTabBar/BrnTabBar.md index d4e558ae..76c0b3d6 100644 --- a/doc/components/tabbar/BrnTabBar/BrnTabBar.md +++ b/doc/components/tabbar/BrnTabBar/BrnTabBar.md @@ -65,8 +65,12 @@ BrnTabBar({ this.tagSpacing, this.preLineTagCount, this.tagHeight, -}) : assert(tabs == null || tabs is List) { +}) : assert(tabs != null) { this.themeData ??= BrnTabBarConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .tabBarConfig + .merge(this.themeData); this.themeData = this.themeData!.merge(BrnTabBarConfig( tabHeight: tabHeight, indicatorHeight: indicatorWeight, @@ -77,10 +81,6 @@ BrnTabBar({ preLineTagCount: preLineTagCount, tagHeight: tagHeight, )); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData!.configId) - .tabBarConfig - .merge(this.themeData); } ``` diff --git a/doc/components/tag/BrnSelectTag/BrnSelectTag.md b/doc/components/tag/BrnSelectTag/BrnSelectTag.md index 8ffca7df..6365f454 100644 --- a/doc/components/tag/BrnSelectTag/BrnSelectTag.md +++ b/doc/components/tag/BrnSelectTag/BrnSelectTag.md @@ -58,6 +58,10 @@ BrnSelectTag({ assert(initTagState == null || (initTagState!.length <= 1)); } this.themeData ??= BrnTagConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .tagConfig + .merge(this.themeData); this.themeData = this.themeData!.merge(BrnTagConfig( tagBackgroundColor: this.tagBackgroundColor, tagTextStyle: BrnTextStyle.withStyle(this.tagTextStyle), @@ -65,10 +69,6 @@ BrnSelectTag({ tagWidth: this.tagWidth, tagHeight: this.tagHeight, selectedTagBackgroundColor: this.selectedTagBackgroundColor)); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData!.configId) - .tagConfig - .merge(this.themeData); } ``` diff --git a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart index 4a7ccb51..3e74a527 100644 --- a/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart +++ b/lib/src/components/card/content_card/brn_pair_info_rich_grid.dart @@ -215,12 +215,12 @@ class BrnRichGridInfo { BrnPairRichInfoGridConfig? themeData, }) { themeData ??= BrnPairRichInfoGridConfig(); - themeData = themeData.merge(BrnPairRichInfoGridConfig( - linkTextStyle: BrnTextStyle(color: clickColor))); themeData = BrnThemeConfigurator.instance .getConfig(configId: themeData.configId) .pairRichInfoGridConfig .merge(themeData); + themeData = themeData.merge(BrnPairRichInfoGridConfig( + linkTextStyle: BrnTextStyle(color: clickColor))); Widget _getQuestionImage(bool isKey) { return GestureDetector( diff --git a/lib/src/components/card/content_card/brn_pair_info_table.dart b/lib/src/components/card/content_card/brn_pair_info_table.dart index c1e10fdd..463beac3 100644 --- a/lib/src/components/card/content_card/brn_pair_info_table.dart +++ b/lib/src/components/card/content_card/brn_pair_info_table.dart @@ -749,6 +749,10 @@ class BrnInfoModal { BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); + themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData.configId) + .pairInfoTableConfig + .merge(themeData); themeData = themeData.merge(BrnPairInfoTableConfig( itemSpacing: itemSpacing, keyTextStyle: BrnTextStyle(fontSize: fontSize), @@ -756,10 +760,6 @@ class BrnInfoModal { .merge(BrnTextStyle.withStyle(valueTextStyle)), linkTextStyle: BrnTextStyle(fontSize: fontSize, color: linkColor) .merge(BrnTextStyle.withStyle(valueTextStyle)))); - themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) - .pairInfoTableConfig - .merge(themeData); Widget valueWidget; if (isArrow) { @@ -845,16 +845,16 @@ class BrnInfoModal { BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); + themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData.configId) + .pairInfoTableConfig + .merge(themeData); themeData = themeData.merge(BrnPairInfoTableConfig( itemSpacing: itemSpacing, keyTextStyle: BrnTextStyle(fontSize: fontSize) .merge(BrnTextStyle.withStyle(keyTextStyle)), valueTextStyle: BrnTextStyle(fontSize: fontSize) .merge(BrnTextStyle.withStyle(valueTextStyle)))); - themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) - .pairInfoTableConfig - .merge(themeData); dynamic valueWidget; dynamic keyWidget; @@ -986,16 +986,16 @@ class BrnInfoModal { BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); + themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData.configId) + .pairInfoTableConfig + .merge(themeData); themeData = themeData.merge(BrnPairInfoTableConfig( itemSpacing: itemSpacing, keyTextStyle: BrnTextStyle(fontSize: fontSize) .merge(BrnTextStyle.withStyle(keyTextStyle)), valueTextStyle: BrnTextStyle(fontSize: fontSize) .merge(BrnTextStyle.withStyle(valueTextStyle)))); - themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) - .pairInfoTableConfig - .merge(themeData); BrnRichTextGenerator keyGen = BrnRichTextGenerator(); if (headIcon != null) { @@ -1036,15 +1036,15 @@ class BrnInfoModal { BrnPairInfoTableConfig? themeData, }) { themeData ??= BrnPairInfoTableConfig(); + themeData = BrnThemeConfigurator.instance + .getConfig(configId: themeData.configId) + .pairInfoTableConfig + .merge(themeData); themeData = themeData.merge(BrnPairInfoTableConfig( itemSpacing: itemSpacing, keyTextStyle: BrnTextStyle(fontSize: fontSize), valueTextStyle: BrnTextStyle(fontSize: fontSize) .merge(BrnTextStyle.withStyle(valueTextStyle)))); - themeData = BrnThemeConfigurator.instance - .getConfig(configId: themeData.configId) - .pairInfoTableConfig - .merge(themeData); return BrnInfoModal( keyPart: keyTitle, diff --git a/lib/src/components/picker/brn_mulit_select_tags_picker.dart b/lib/src/components/picker/brn_mulit_select_tags_picker.dart index dd16cff6..a1507a0f 100644 --- a/lib/src/components/picker/brn_mulit_select_tags_picker.dart +++ b/lib/src/components/picker/brn_mulit_select_tags_picker.dart @@ -3,8 +3,7 @@ import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; import 'package:bruno/src/components/picker/brn_tags_common_picker.dart'; import 'package:bruno/src/components/picker/brn_tags_picker_config.dart'; -import 'package:bruno/src/theme/brn_theme_configurator.dart'; -import 'package:bruno/src/theme/configs/brn_picker_config.dart'; +import 'package:bruno/src/theme/brn_theme.dart'; import 'package:flutter/material.dart'; ///样式的枚举类型 @@ -217,22 +216,24 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { ///流式布局 Widget _buildWrapViewWidget(BuildContext context, VoidCallback? onUpdate) { - Color selectedTagTitleColor = this.tagPickerConfig.selectedTagTitleColor ?? - BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary; - Color tagTitleColor = this.tagPickerConfig.tagTitleColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .colorTextImportant; - Color tagBackgroundColor = - this.tagPickerConfig.tagBackgroudColor ?? Color(0xffF8F8F8); - Color selectedTagBackgroundColor = - this.tagPickerConfig.selectedTagBackgroudColor ?? - BrnThemeConfigurator.instance - .getConfig() - .commonConfig - .brandPrimary - .withAlpha(0x14); + BrnTagConfig tagConfig = BrnThemeConfigurator.instance + .getConfig(configId: themeData!.configId) + .tagConfig + .merge(BrnTagConfig()); + tagConfig = tagConfig.merge(BrnTagConfig( + selectTagTextStyle: BrnTextStyle( + height: 1, + color: this.tagPickerConfig.selectedTagTitleColor, + fontSize: this.tagPickerConfig.tagTitleFontSize, + fontWeight: FontWeight.w600), + tagTextStyle: BrnTextStyle( + height: 1, + color: this.tagPickerConfig.tagTitleColor, + fontSize: this.tagPickerConfig.tagTitleFontSize, + fontWeight: FontWeight.w400), + tagBackgroundColor: this.tagPickerConfig.tagBackgroudColor, + selectedTagBackgroundColor: + this.tagPickerConfig.selectedTagBackgroudColor)); return Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16), @@ -240,16 +241,15 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { spacing: 15.0, children: this._sourceTags.map((choice) { bool selected = choice.isSelect; - Color titleColor = selected ? selectedTagTitleColor : tagTitleColor; - EdgeInsets edgeInsets = this.tagPickerConfig.chipPadding ?? EdgeInsets.only(top: 9.0, left: 10.0, right: 10, bottom: 11.0); return ChoiceChip( selected: selected, padding: edgeInsets, pressElevation: 0, - backgroundColor: tagBackgroundColor, - selectedColor: selectedTagBackgroundColor, + backgroundColor: tagConfig.tagBackgroundColor, + selectedColor: tagConfig.selectedTagBackgroundColor + .withAlpha(0x14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(2.0)), label: Text( @@ -257,11 +257,7 @@ class BrnMultiSelectTagsPicker extends CommonTagsPicker { textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, strutStyle: StrutStyle(forceStrutHeight: true, height: 1), - style: TextStyle( - height: 1, - color: titleColor, - fontWeight: selected ? FontWeight.w600 : FontWeight.w400, - fontSize: this.tagPickerConfig.tagTitleFontSize), + style: TextStyle(color: Colors.grey), ), onSelected: (bool value) { if (_selectedTags.length > this.maxSelectItemCount && diff --git a/lib/src/components/picker/brn_multi_picker.dart b/lib/src/components/picker/brn_multi_picker.dart index 5b2ab14b..3c4aa26f 100644 --- a/lib/src/components/picker/brn_multi_picker.dart +++ b/lib/src/components/picker/brn_multi_picker.dart @@ -120,19 +120,18 @@ class BrnMultiDataPicker extends StatefulWidget { this.themeData, this.sync = true}) { this.themeData ??= BrnPickerConfig(); - this.themeData = this.themeData!.merge(BrnPickerConfig( - cancelTextStyle: BrnTextStyle.withStyle(cancelTextStyle), - confirmTextStyle: BrnTextStyle.withStyle(confirmTextStyle), - titleTextStyle: BrnTextStyle.withStyle(titleTextStyle), - itemTextStyle: BrnTextStyle(color: textColor, fontSize: textFontSize), - itemTextSelectedStyle: - BrnTextStyle(color: textSelectedColor, fontSize: textFontSize), - )); - this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData!.configId) .pickerConfig .merge(this.themeData); + this.themeData = this.themeData!.merge(BrnPickerConfig( + cancelTextStyle: BrnTextStyle.withStyle(cancelTextStyle), + confirmTextStyle: BrnTextStyle.withStyle(confirmTextStyle), + titleTextStyle: BrnTextStyle.withStyle(titleTextStyle), + itemTextStyle: BrnTextStyle(color: textColor, fontSize: textFontSize), + itemTextSelectedStyle: + BrnTextStyle(color: textSelectedColor, fontSize: textFontSize), + )); } @override diff --git a/lib/src/components/picker/brn_tags_common_picker.dart b/lib/src/components/picker/brn_tags_common_picker.dart index d6cb4a5e..9a45f503 100644 --- a/lib/src/components/picker/brn_tags_common_picker.dart +++ b/lib/src/components/picker/brn_tags_common_picker.dart @@ -36,9 +36,10 @@ class CommonTagsPicker extends StatefulWidget { this.themeData}) : super(key: key) { this.themeData ??= BrnPickerConfig(); - this.themeData = this - .themeData! - .merge(BrnThemeConfigurator.instance.getConfig().pickerConfig); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .pickerConfig + .merge(this.themeData); } void show() { diff --git a/lib/src/components/picker/brn_tags_picker_config.dart b/lib/src/components/picker/brn_tags_picker_config.dart index 1303df3c..ab8ffa20 100644 --- a/lib/src/components/picker/brn_tags_picker_config.dart +++ b/lib/src/components/picker/brn_tags_picker_config.dart @@ -49,10 +49,7 @@ class BrnTagsPickerConfig { this.tagBackgroudColor, this.selectedTagBackgroudColor, this.chipPadding, - this.tagItemSource = const []}) { - this.tagTitleColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - } + this.tagItemSource = const []}); ///tag 文字大小 double tagTitleFontSize; diff --git a/lib/src/components/tabbar/normal/brn_tab_bar.dart b/lib/src/components/tabbar/normal/brn_tab_bar.dart index 3b4f5090..619ef439 100644 --- a/lib/src/components/tabbar/normal/brn_tab_bar.dart +++ b/lib/src/components/tabbar/normal/brn_tab_bar.dart @@ -134,23 +134,23 @@ class BrnTabBar extends StatefulWidget { this.tagSpacing, this.preLineTagCount, this.tagHeight, - }) : assert(tabs == null) { + }) : assert(tabs != null) { this.themeData ??= BrnTabBarConfig(); - this.themeData = this.themeData!.merge(BrnTabBarConfig( - backgroundColor: backgroundcolor, - tabHeight: tabHeight, - indicatorHeight: indicatorWeight, - indicatorWidth: indicatorWidth, - labelStyle: BrnTextStyle.withStyle(labelStyle), - unselectedLabelStyle: BrnTextStyle.withStyle(unselectedLabelStyle), - tagSpacing: tagSpacing, - preLineTagCount: preLineTagCount, - tagHeight: tagHeight, - )); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData!.configId) .tabBarConfig .merge(this.themeData); + this.themeData = this.themeData!.merge(BrnTabBarConfig( + backgroundColor: backgroundcolor, + tabHeight: tabHeight, + indicatorHeight: indicatorWeight, + indicatorWidth: indicatorWidth, + labelStyle: BrnTextStyle.withStyle(labelStyle), + unselectedLabelStyle: BrnTextStyle.withStyle(unselectedLabelStyle), + tagSpacing: tagSpacing, + preLineTagCount: preLineTagCount, + tagHeight: tagHeight, + )); } @override diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index 1ae47149..a3185e7c 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -69,13 +69,13 @@ class BrnDeleteTag extends StatefulWidget { this.themeData}) : super(key: key) { themeData ??= BrnTagConfig(); - themeData = themeData!.merge(BrnTagConfig( - tagBackgroundColor: this.backgroundColor, - tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); themeData = BrnThemeConfigurator.instance .getConfig(configId: themeData!.configId) .tagConfig .merge(this.themeData); + themeData = themeData!.merge(BrnTagConfig( + tagBackgroundColor: this.backgroundColor, + tagTextStyle: BrnTextStyle.withStyle(tagTextStyle))); } @override diff --git a/lib/src/components/tag/tagview/brn_select_tag.dart b/lib/src/components/tag/tagview/brn_select_tag.dart index f2aed619..e1aba607 100644 --- a/lib/src/components/tag/tagview/brn_select_tag.dart +++ b/lib/src/components/tag/tagview/brn_select_tag.dart @@ -82,6 +82,10 @@ class BrnSelectTag extends StatefulWidget { assert(initTagState == null || (initTagState!.length <= 1)); } this.themeData ??= BrnTagConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .tagConfig + .merge(this.themeData); this.themeData = this.themeData!.merge(BrnTagConfig( tagBackgroundColor: this.tagBackgroundColor, tagTextStyle: BrnTextStyle.withStyle(this.tagTextStyle), @@ -89,10 +93,6 @@ class BrnSelectTag extends StatefulWidget { tagWidth: this.tagWidth, tagHeight: this.tagHeight, selectedTagBackgroundColor: this.selectedTagBackgroundColor)); - this.themeData = BrnThemeConfigurator.instance - .getConfig(configId: this.themeData!.configId) - .tagConfig - .merge(this.themeData); } @override From af45282b9f500d1f50997310b499e423cf7675ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E8=84=B8=E5=84=BF?= Date: Tue, 26 Apr 2022 14:16:32 +0800 Subject: [PATCH 11/19] fix core rules analyze problems (#193) * fix core rules analyze problems * fix core rules analyze comments * fix core rules analyze Function naming rule --- analysis_options.yaml | 8 +++++ .../actionsheet/brn_common_action_sheet.dart | 4 +-- .../brn_selected_list_action_sheet.dart | 2 +- .../actionsheet/brn_share_action_sheet.dart | 8 ++--- .../brn_appraise_emoji_list_view.dart | 2 +- .../brn_multiple_bottom_button.dart | 3 +- .../collection/brn_text_button_panel.dart | 2 +- .../content_card/brn_enhance_number_card.dart | 2 +- .../brn_doughnut_chart.dart | 3 +- .../brn_progress_bar_chart.dart | 3 +- .../brn_progress_bar_chart_painter.dart | 25 +++++++------ .../charts/broken_line/brn_line_painter.dart | 6 ++-- lib/src/components/charts/funnel_chart.dart | 3 +- lib/src/components/charts/radar_chart.dart | 3 +- lib/src/components/dialog/brn_dialog.dart | 6 ++-- .../dialog/brn_middle_input_diaolg.dart | 2 +- .../dialog/brn_multi_select_dialog.dart | 3 +- .../components/dialog/brn_share_dialog.dart | 6 ++-- .../components/dialog/brn_single_select.dart | 3 +- .../items/group/brn_expandable_group.dart | 3 +- .../items/group/brn_portrait_radio_group.dart | 2 +- .../items/group/element_expand_widget.dart | 3 +- .../gallery/page/brn_gallery_detail_page.dart | 7 ++-- .../page/brn_gallery_summary_page.dart | 11 +++--- lib/src/components/guide/brn_tip_widget.dart | 12 ++++--- lib/src/components/navbar/brn_appbar.dart | 18 +++++----- .../components/picker/base/brn_picker.dart | 8 +++-- .../components/picker/brn_bottom_picker.dart | 2 +- .../picker/brn_bottom_write_picker.dart | 2 +- .../components/picker/brn_multi_picker.dart | 9 ++--- .../brn_select_tags_with_input_picker.dart | 4 +-- .../bean/brn_multi_column_picker_entity.dart | 28 +++++++-------- .../brn_multi_column_list.dart | 22 ++++++------ .../brn_multi_column_picker.dart | 6 ++-- .../brn_multi_column_picker_util.dart | 8 ++--- .../btn_multi_column_picker_item.dart | 10 ++---- .../brn_date_picker_constants.dart | 8 ++--- .../time_picker/brn_date_time_formatter.dart | 10 +++--- .../date_picker/brn_datetime_widget.dart | 10 +++--- .../brn_date_range_side_widget.dart | 2 +- .../brn_date_range_widget.dart | 4 +-- .../brn_time_range_side_widget.dart | 2 +- .../brn_time_range_widget.dart | 14 ++++---- .../components/popup/brn_measure_size.dart | 2 +- .../scroll_anchor/brn_scroll_anchor_tab.dart | 36 +++++++++---------- .../selectcity/brn_az_listview.dart | 6 ++-- .../components/selectcity/brn_index_bar.dart | 2 +- .../brn_single_select_city_page.dart | 2 +- .../selectcity/brn_suspension_view.dart | 4 +-- .../bean/brn_selection_common_entity.dart | 34 +++++++++--------- .../selection/brn_flat_selection.dart | 10 +++--- .../selection/brn_selection_util.dart | 8 ++--- .../selection/brn_selection_view.dart | 11 +++--- .../widget/brn_flat_selection_item.dart | 4 +-- .../widget/brn_selection_animate_widget.dart | 2 -- .../brn_selection_common_item_widget.dart | 12 +++---- .../brn_selection_date_range_item_widget.dart | 10 ++---- ...n_selection_datepicker_animate_widget.dart | 2 -- .../widget/brn_selection_list_widget.dart | 12 +++---- .../brn_selection_menu_item_widget.dart | 4 +-- .../widget/brn_selection_menu_widget.dart | 22 ++++++------ .../brn_selection_more_item_widget.dart | 4 +-- ...brn_selection_range_input_item_widget.dart | 7 ++-- .../widget/brn_selection_range_widget.dart | 16 ++++----- .../brn_selection_single_list_widget.dart | 4 +-- .../components/sugsearch/brn_search_text.dart | 1 - .../bottom/brn_bottom_tab_bar_main.dart | 24 +++++++++---- .../indicator/brn_triangle_decoration.dart | 5 --- .../tag/tagview/brn_delete_tag.dart | 3 +- .../tag/tagview/brn_select_tag.dart | 3 +- lib/src/utils/brn_tools.dart | 2 +- pubspec.yaml | 1 + 72 files changed, 279 insertions(+), 273 deletions(-) create mode 100644 analysis_options.yaml diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..7ee5ce4d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,8 @@ +include: package:lints/core.yaml +# include: package:lints/recommended.yaml + +analyzer: + exclude: + - doc/** + - example/** + - test/** \ No newline at end of file diff --git a/lib/src/components/actionsheet/brn_common_action_sheet.dart b/lib/src/components/actionsheet/brn_common_action_sheet.dart index d0e297f8..e0158a45 100644 --- a/lib/src/components/actionsheet/brn_common_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_common_action_sheet.dart @@ -4,9 +4,9 @@ import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/theme/configs/brn_action_sheet_config.dart'; import 'package:flutter/material.dart'; -typedef void BrnCommonActionSheetItemClickCallBack( +typedef BrnCommonActionSheetItemClickCallBack = void Function( int index, BrnCommonActionSheetItem actionItem); -typedef bool BrnCommonActionSheetItemClickInterceptor( +typedef BrnCommonActionSheetItemClickInterceptor = bool Function( int index, BrnCommonActionSheetItem actionItem); /// 每行样式 diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index e50906ff..1d186a2c 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -360,7 +360,7 @@ class _BrnActionSheetSelectedItemListState Widget build(BuildContext context) { // 顶部标题处理 String title = - (widget.itemWidget.title != null && widget.itemWidget.title!.length > 0) + (widget.itemWidget.title != null && widget.itemWidget.title!.isNotEmpty) ? widget.itemWidget.title! : '已选列表'; TextStyle titleStyle = const TextStyle( diff --git a/lib/src/components/actionsheet/brn_share_action_sheet.dart b/lib/src/components/actionsheet/brn_share_action_sheet.dart index 6cfc6e62..d681a7f4 100644 --- a/lib/src/components/actionsheet/brn_share_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_share_action_sheet.dart @@ -5,12 +5,12 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; /// section为所在行数(0或1),index是在第几位(从0开始记), shareItem为渠道相关信息 -typedef void BrnShareActionSheetItemClickCallBack( +typedef BrnShareActionSheetItemClickCallBack = void Function( int section, int index, BrnShareItem shareItem); /// 点击事件拦截回调(如果配置了此项,返回值为是否拦截,如果为true,则进行拦截,不进行默认回调) /// section为所在行数(0或1),index是在第几位(从0开始记),shareItem为渠道相关信息 -typedef bool BrnShareActionSheetOnItemClickInterceptor( +typedef BrnShareActionSheetOnItemClickInterceptor = bool Function( int section, int index, BrnShareItem shareItem); /// 分享元素 @@ -222,7 +222,7 @@ class BrnShareActionSheet extends StatelessWidget { )); // 添加“预设分享”容器 - if (firstSectionItems.length > 0) { + if (firstSectionItems.isNotEmpty) { tiles.add(Container( padding: EdgeInsets.only(left: leftGap, top: topGap, bottom: bottomGap), alignment: Alignment.centerLeft, @@ -243,7 +243,7 @@ class BrnShareActionSheet extends StatelessWidget { )); // 添加“自定义分享”容器 - if (secondSectionItems.length > 0) { + if (secondSectionItems.isNotEmpty) { tiles.add(Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: leftGap, top: topGap, bottom: bottomGap), diff --git a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart index 93ef8d1d..80cd04e1 100644 --- a/lib/src/components/appraise/brn_appraise_emoji_list_view.dart +++ b/lib/src/components/appraise/brn_appraise_emoji_list_view.dart @@ -24,7 +24,7 @@ class BrnAppraiseEmojiListView extends StatefulWidget { this.indexes = const [0, 1, 2, 3, 4], this.titles = _defaultTitles, this.onTap}) - : assert(indexes.length > 0), + : assert(indexes.isNotEmpty), assert(titles.length == 5), super(key: key); diff --git a/lib/src/components/button/collection/brn_multiple_bottom_button.dart b/lib/src/components/button/collection/brn_multiple_bottom_button.dart index 393f8eee..5cb5dcbc 100644 --- a/lib/src/components/button/collection/brn_multiple_bottom_button.dart +++ b/lib/src/components/button/collection/brn_multiple_bottom_button.dart @@ -118,8 +118,9 @@ class _BrnMultipleBottomButtonState extends State { onValueChangedAtIndex: (index, value) { //同步到外界的当前的全选状态 _controller.setState(selectAllState: value); - if (widget.onSelectAll != null) + if (widget.onSelectAll != null) { widget.onSelectAll!(value); + } }, key: Key(DateTime.now().toString()), ); diff --git a/lib/src/components/button/collection/brn_text_button_panel.dart b/lib/src/components/button/collection/brn_text_button_panel.dart index 74b3d6a6..7fb6ccfc 100644 --- a/lib/src/components/button/collection/brn_text_button_panel.dart +++ b/lib/src/components/button/collection/brn_text_button_panel.dart @@ -46,7 +46,7 @@ class _BrnTextButtonPanelState extends State { @override Widget build(BuildContext context) { - if (widget.nameList.length > 0) { + if (widget.nameList.isNotEmpty) { Row row = Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceAround, diff --git a/lib/src/components/card/content_card/brn_enhance_number_card.dart b/lib/src/components/card/content_card/brn_enhance_number_card.dart index 9fae5469..86bcf5e4 100644 --- a/lib/src/components/card/content_card/brn_enhance_number_card.dart +++ b/lib/src/components/card/content_card/brn_enhance_number_card.dart @@ -101,7 +101,7 @@ class BrnEnhanceNumberCard extends StatelessWidget { .enhanceNumberCardConfig .merge(defaultConfig); - if (itemChildren == null || itemChildren!.length == 0) { + if (itemChildren == null || itemChildren!.isEmpty) { return Container( height: 0, width: 0, diff --git a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart index 30ea9fb9..ce8a10ce 100644 --- a/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart +++ b/lib/src/components/charts/brn_doughunt_chart/brn_doughnut_chart.dart @@ -234,9 +234,10 @@ class BrnDoughnut extends CustomPainter { double radain = pointRadianInSector(position); if (item.startRadius < radain && radain < (item.startRadius + item.radius)) { - if (null != brnDoughnutSelectCallback) + if (null != brnDoughnutSelectCallback) { brnDoughnutSelectCallback!( item.startRadius == selectedItem?.startRadius ? null : item); + } break; } } diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart index fb12f8de..4381b053 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart @@ -199,8 +199,9 @@ class BrnProgressBarChartState extends State { widget.selectedHintTextBackgroundColor, brnProgressBarChartSelectCallback: (BrnProgressBarItem? item) { - if (null != widget.barChartSelectCallback) + if (null != widget.barChartSelectCallback) { widget.barChartSelectCallback!(item); + } setState(() { _selectedBarItem = item; }); diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart index e5d0e673..28845bec 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart @@ -13,7 +13,7 @@ typedef BrnProgressBarChartSelectCallback = void Function( BrnProgressBarItem? barItem); /// 点击柱状数据的拦截器 -typedef bool OnBarItemClickInterceptor( +typedef OnBarItemClickInterceptor = bool Function( int barBundleIndex, BrnProgressBarBundle barBundle, int barGroupIndex, @@ -231,27 +231,29 @@ class BrnProgressBarChartPainter extends CustomPainter { return Size(textWidth, textHeight); } - if (yAxis.axisItemList.length > 0) { + if (yAxis.axisItemList.isNotEmpty) { //确定y轴文本最大宽度,以及每个文本大小 yAxis.axisItemList.forEach((AxisItem item) { Size textSize = getTextAreaSize(item.showText, yAxis.textStyle); item.textSize = textSize; - if (textSize.width > yAxis.maxTextWidth) + if (textSize.width > yAxis.maxTextWidth) { yAxis.maxTextWidth = textSize.width; + } }); } return yAxis.maxTextWidth + 10; } void _prepareData(Canvas canvas, Size size) { - if (this.yAxis.axisItemList.length > 0) { + if (this.yAxis.axisItemList.isNotEmpty) { //确定y轴文本最大宽度,以及每个文本大小 this.yAxis.axisItemList.forEach((AxisItem item) { Size textSize = this.getTextAreaSize(item.showText, this.yAxis.textStyle); item.textSize = textSize; - if (textSize.width > this.yAxis.maxTextWidth) + if (textSize.width > this.yAxis.maxTextWidth) { this.yAxis.maxTextWidth = textSize.width; + } }); this.yAxisRect = Rect.fromLTWH( @@ -259,21 +261,22 @@ class BrnProgressBarChartPainter extends CustomPainter { 0, this.yAxis.maxTextWidth + _yTextAxisSpace, size.height - - (0 == this.xAxis.axisItemList.length ? 0 : this._xAxisHeight)); + (this.xAxis.axisItemList.isEmpty ? 0 : this._xAxisHeight)); } - if (!this.drawY) + if (!this.drawY) { this.yAxisRect = Rect.fromLTWH( 0, 0, 0, size.height - - (0 == this.xAxis.axisItemList.length ? 0 : this._xAxisHeight)); + (this.xAxis.axisItemList.isEmpty ? 0 : this._xAxisHeight)); + } this.xAxisRect = Rect.fromPoints( this.yAxisRect.bottomRight, Offset(size.width, size.height)); - if (this.barBundleList.length > 0) { + if (this.barBundleList.isNotEmpty) { this.contentRect = Rect.fromPoints(this.yAxisRect.topRight, this.xAxisRect.topRight); } @@ -377,7 +380,7 @@ class BrnProgressBarChartPainter extends CustomPainter { } void _drawXAxisIn(Canvas canvas, Rect xAxisRect) { - if (0 == this.xAxis.axisItemList.length) return; + if (this.xAxis.axisItemList.isEmpty) return; if (AxisStyle.axisStyleSolid == this.xAxis.axisStyle) { Offset xLineStart = xAxisRect.topLeft; Offset xLineEnd = xAxisRect.topRight; @@ -457,7 +460,7 @@ class BrnProgressBarChartPainter extends CustomPainter { } void _drawYAxisIn(Canvas canvas, Rect yAxisRect) { - if (0 == this.yAxis.axisItemList.length) return; + if (this.yAxis.axisItemList.isEmpty) return; if (AxisStyle.axisStyleSolid == this.yAxis.axisStyle) { Offset yLineStart = yAxisRect.bottomRight; Offset yLineEnd = yAxisRect.topRight; diff --git a/lib/src/components/charts/broken_line/brn_line_painter.dart b/lib/src/components/charts/broken_line/brn_line_painter.dart index 5b0f850f..cc1fc89a 100644 --- a/lib/src/components/charts/broken_line/brn_line_painter.dart +++ b/lib/src/components/charts/broken_line/brn_line_painter.dart @@ -270,7 +270,7 @@ class BrnLinePainter extends BrnBasePainter { double? x0, y0, x1, y1, t0; var path = Path(); for (int i = 0; i < targetPoints.length; i++) { - var t1; + double? t1; var x = targetPoints[i].x; var y = targetPoints[i].y; if (x == x1 && y == y1) break; @@ -512,7 +512,7 @@ class BrnLinePainter extends BrnBasePainter { var length = item.points.length; for (var i = 0; i < length; i++) { if (item.points[i].pointText == null || - item.points[i].pointText!.length == 0) { + item.points[i].pointText!.isEmpty) { continue; } var tpX = TextPainter( @@ -545,7 +545,7 @@ class BrnLinePainter extends BrnBasePainter { bool isAdjustPosition( int lineIndex, Point currentPoint, List>> lines) { List> sameXPoints = getSameXValuePoints(currentPoint, lines); - if (sameXPoints.length > 0) { + if (sameXPoints.isNotEmpty) { if (currentPoint.distanceTo(sameXPoints[0]) == 0) { return lineIndex > 0; } else if (currentPoint.distanceTo(sameXPoints[0]) < 40) { diff --git a/lib/src/components/charts/funnel_chart.dart b/lib/src/components/charts/funnel_chart.dart index a2ac4c7d..b0a4a61b 100644 --- a/lib/src/components/charts/funnel_chart.dart +++ b/lib/src/components/charts/funnel_chart.dart @@ -267,8 +267,9 @@ abstract class RenderFunnelChart extends RenderBox @override void setupParentData(RenderBox child) { - if (child.parentData is! BrnFunnelChartParentData) + if (child.parentData is! BrnFunnelChartParentData) { child.parentData = BrnFunnelChartParentData(); + } } @override diff --git a/lib/src/components/charts/radar_chart.dart b/lib/src/components/charts/radar_chart.dart index 4e7e2804..6a74b948 100644 --- a/lib/src/components/charts/radar_chart.dart +++ b/lib/src/components/charts/radar_chart.dart @@ -339,8 +339,9 @@ class RenderRadarChart extends RenderBox @override void setupParentData(RenderBox child) { - if (child.parentData is! BrnRadarChartParentData) + if (child.parentData is! BrnRadarChartParentData) { child.parentData = BrnRadarChartParentData(); + } } double _getIntrinsicDimensionHorizontal( diff --git a/lib/src/components/dialog/brn_dialog.dart b/lib/src/components/dialog/brn_dialog.dart index 09c3e106..dd0049ec 100644 --- a/lib/src/components/dialog/brn_dialog.dart +++ b/lib/src/components/dialog/brn_dialog.dart @@ -311,13 +311,14 @@ class BrnDialog extends AlertDialog { /// 内容widget:以contentWidget为准,辅以message生成的Text Widget _generateContentWidget( BuildContext context, BrnDialogConfig dialogConfig) { - if (contentWidget != null) + if (contentWidget != null) { return Flexible( child: DefaultTextStyle( style: dialogConfig.contentTextStyle.generateTextStyle(), child: contentWidget!, ), ); + } return Padding( padding: _configContentPadding(dialogConfig), @@ -334,13 +335,14 @@ class BrnDialog extends AlertDialog { /// 警示widget:以warningWidget为准,辅以warning生成的Text Widget _generateWarningWidget( BuildContext context, BrnDialogConfig dialogConfig) { - if (warningWidget != null) + if (warningWidget != null) { return Flexible( child: DefaultTextStyle( style: dialogConfig.warningTextStyle.generateTextStyle(), child: warningWidget!, ), ); + } return Padding( padding: _configWarningPadding(dialogConfig), diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index 6092c097..9954bb76 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -82,7 +82,7 @@ class BrnMiddleInputDialog { void _doShow(BuildContext context) { String _value = inputEditingController?.text ?? ""; var dialogMessageWidgets = []; - if (message != null && message!.length > 0) { + if (message != null && message!.isNotEmpty) { dialogMessageWidgets.add(Text( message!, style: cContentTextStyle, diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index 40e979e8..e30654df 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -235,11 +235,12 @@ class MultiSelectPickerWidgetState extends State { /// 若无则以 messageText 生成widget 填充, /// 都没设置则为空 Container Widget _generateContentWidget() { - if (widget.messageWidget != null) + if (widget.messageWidget != null) { return Padding( padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), child: widget.messageWidget, ); + } if (!BrunoTools.isEmpty(widget.messageText)) { return Padding( diff --git a/lib/src/components/dialog/brn_share_dialog.dart b/lib/src/components/dialog/brn_share_dialog.dart index 8e282877..a45f761c 100644 --- a/lib/src/components/dialog/brn_share_dialog.dart +++ b/lib/src/components/dialog/brn_share_dialog.dart @@ -9,15 +9,15 @@ import 'package:flutter/material.dart'; /// 点击item回调 /// shareChannel 是分享渠道一般传入 [BrnShareItemConstants] 下的值 -typedef BrnShareDialogItemClickCallBack(int shareChannel, int customIndex); +typedef BrnShareDialogItemClickCallBack = void Function(int shareChannel, int customIndex); /// 获取自定义分享item标题 /// index为自定义分享item索引 -typedef String? BrnShareDialogGetCustomShareItemTitle(int index); +typedef BrnShareDialogGetCustomShareItemTitle = String? Function(int index); /// 获取自定义分享item图标 /// index为自定义分享item索引 -typedef Widget? BrnShareDialogGetCustomShareItemIcon(int index); +typedef BrnShareDialogGetCustomShareItemIcon = Widget? Function(int index); // ignore: must_be_immutable class BrnShareDialog extends StatelessWidget { diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index 1f3554e5..97e2c3a1 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -271,11 +271,12 @@ class BrnSingleSelectDialogWidgetState /// 若无则以 messageText 生成widget 填充, /// 都没设置则为空 Container Widget _generateContentWidget() { - if (widget.messageWidget != null) + if (widget.messageWidget != null) { return Padding( padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), child: widget.messageWidget, ); + } if (!BrunoTools.isEmpty(widget.messageText)) { return Padding( diff --git a/lib/src/components/form/items/group/brn_expandable_group.dart b/lib/src/components/form/items/group/brn_expandable_group.dart index debd5420..d9321482 100644 --- a/lib/src/components/form/items/group/brn_expandable_group.dart +++ b/lib/src/components/form/items/group/brn_expandable_group.dart @@ -149,8 +149,9 @@ class _BrnExpansionElementState extends State } PageStorage.of(context)?.writeState(context, _isExpanded); }); - if (widget.onExpansionChanged != null) + if (widget.onExpansionChanged != null) { widget.onExpansionChanged!(_isExpanded); + } } Widget _buildHeader(BuildContext context, Widget? child) { diff --git a/lib/src/components/form/items/group/brn_portrait_radio_group.dart b/lib/src/components/form/items/group/brn_portrait_radio_group.dart index f66df326..e48430b0 100644 --- a/lib/src/components/form/items/group/brn_portrait_radio_group.dart +++ b/lib/src/components/form/items/group/brn_portrait_radio_group.dart @@ -157,7 +157,7 @@ class BrnPortraitRadioGroupState extends State { }, ), Visibility( - visible: option.subTitle != null && option.subTitle!.length > 0, + visible: option.subTitle != null && option.subTitle!.isNotEmpty, child: Padding( padding: EdgeInsets.only(top: 4, right: 20), child: Text( diff --git a/lib/src/components/form/items/group/element_expand_widget.dart b/lib/src/components/form/items/group/element_expand_widget.dart index 6cb1f8e6..af4f56ae 100644 --- a/lib/src/components/form/items/group/element_expand_widget.dart +++ b/lib/src/components/form/items/group/element_expand_widget.dart @@ -162,8 +162,9 @@ class _ExpansionElementState extends State } PageStorage.of(context)?.writeState(context, _isExpanded); }); - if (widget.onExpansionChanged != null) + if (widget.onExpansionChanged != null) { widget.onExpansionChanged!(_isExpanded); + } } Widget _buildHeader(BuildContext context, Widget? child) { diff --git a/lib/src/components/gallery/page/brn_gallery_detail_page.dart b/lib/src/components/gallery/page/brn_gallery_detail_page.dart index 829bb00f..fa1573a5 100644 --- a/lib/src/components/gallery/page/brn_gallery_detail_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_detail_page.dart @@ -22,10 +22,10 @@ class BrnGalleryDetailPage extends StatefulWidget { final List allConfig; /// 初始位于第几组,默认 0 - final initGroupId; + final int initGroupId; /// 初始位于组内的第几个,默认 0 - final initIndexId; + final int initIndexId; /// 是否来自于列表页,一般情况不要使用,默认 false final bool fromSummary; @@ -188,7 +188,7 @@ class _BrnGalleryDetailPageState extends State _allConfig.forEach((item) => _tabs.add( BadgeTab(text: '${item.title ?? ""}(${item.configList!.length})'))); - if (_allConfig.length > 1) + if (_allConfig.length > 1) { _columnViews.add(BrnTabBar( backgroundcolor: _tabBarConfig.backgroundColor, unselectedLabelStyle: @@ -204,6 +204,7 @@ class _BrnGalleryDetailPageState extends State duration: Duration(microseconds: 100), curve: Curves.linear); }, )); + } for (int i = 0; i < _allConfig.length; i++) { for (int j = 0; j < _allConfig[i].configList!.length; j++) { diff --git a/lib/src/components/gallery/page/brn_gallery_summary_page.dart b/lib/src/components/gallery/page/brn_gallery_summary_page.dart index 2e7d7c93..30e07e9e 100644 --- a/lib/src/components/gallery/page/brn_gallery_summary_page.dart +++ b/lib/src/components/gallery/page/brn_gallery_summary_page.dart @@ -99,7 +99,7 @@ class _BrnGallerySummaryPageState extends State { Widget _buildItem(BrnBasicGroupConfig? groupConfig, int groupId) { if (groupConfig == null) return Row(); List columnViews = []; - if (groupConfig.title != null) + if (groupConfig.title != null) { columnViews.add(Container( height: 53, child: Padding( @@ -113,15 +113,16 @@ class _BrnGallerySummaryPageState extends State { ), ), )); + } if (groupConfig.configList != null) { List gridViews = []; - for (int i = 0; i < groupConfig.configList!.length; i++) + for (int i = 0; i < groupConfig.configList!.length; i++) { gridViews.add(GestureDetector( onTap: () { //页面的跳转不应该交个子Widget处理 - if (widget.fromDetail) + if (widget.fromDetail) { Navigator.of(context).pop([groupId, i]); - else + } else { Navigator.of(context).push(CupertinoPageRoute(builder: (context) { return BrnGalleryDetailPage( allConfig: widget.allConfig, @@ -132,10 +133,12 @@ class _BrnGallerySummaryPageState extends State { controller: widget.controller, ); })); + } }, child: groupConfig.configList![i] .buildSummaryWidget(context, widget.allConfig, groupId, i), )); + } columnViews.add(GridView.count( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, diff --git a/lib/src/components/guide/brn_tip_widget.dart b/lib/src/components/guide/brn_tip_widget.dart index d8e1f094..d1cefe3b 100644 --- a/lib/src/components/guide/brn_tip_widget.dart +++ b/lib/src/components/guide/brn_tip_widget.dart @@ -48,7 +48,7 @@ class BrnTipInfoWidget extends StatelessWidget { Color borderColor = mode == GuideMode.force ? Colors.transparent : Color(0xFFCCCCCC); if (direction == GuideDirection.bottomLeft || - direction == GuideDirection.bottomRight) + direction == GuideDirection.bottomRight) { return Column( verticalDirection: VerticalDirection.up, children: [ @@ -70,8 +70,9 @@ class BrnTipInfoWidget extends StatelessWidget { ), ], ); + } if (direction == GuideDirection.topLeft || - direction == GuideDirection.topRight) + direction == GuideDirection.topRight) { return Column( children: [ buildContent(), @@ -90,7 +91,8 @@ class BrnTipInfoWidget extends StatelessWidget { ), ], ); - if (direction == GuideDirection.left) + } + if (direction == GuideDirection.left) { return Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, @@ -107,7 +109,8 @@ class BrnTipInfoWidget extends StatelessWidget { ), ], ); - if (direction == GuideDirection.right) + } + if (direction == GuideDirection.right) { return Row( crossAxisAlignment: CrossAxisAlignment.end, textDirection: TextDirection.rtl, @@ -127,6 +130,7 @@ class BrnTipInfoWidget extends StatelessWidget { ), ], ); + } return Row(); } diff --git a/lib/src/components/navbar/brn_appbar.dart b/lib/src/components/navbar/brn_appbar.dart index 93ee65b5..233f7ccb 100644 --- a/lib/src/components/navbar/brn_appbar.dart +++ b/lib/src/components/navbar/brn_appbar.dart @@ -592,13 +592,13 @@ class BrnBarBottomDivider extends PreferredSize { class _BrnSearchResultAppBar extends StatelessWidget { final BrnAppBarConfig? appBarConfig; final String? title; - final backgroundColor; - final bottom; - final brightness; - final showLeadingDivider; - final flexibleSpace; - final backLeadCallback; - final showDefaultBottom; + final Color? backgroundColor; + final PreferredSizeWidget? bottom; + final Brightness? brightness; + final bool showLeadingDivider; + final Widget? flexibleSpace; + final VoidCallback? backLeadCallback; + final bool showDefaultBottom; _BrnSearchResultAppBar( {this.appBarConfig, @@ -639,7 +639,7 @@ class _BrnSearchResultAppBar extends StatelessWidget { /// divider Visibility( - visible: showLeadingDivider ?? true, + visible: showLeadingDivider, child: Container( margin: EdgeInsets.only(left: 12, right: 12), height: 16, @@ -650,7 +650,7 @@ class _BrnSearchResultAppBar extends StatelessWidget { /// padding Visibility( - visible: !(showLeadingDivider ?? true), + visible: !(showLeadingDivider), child: Padding( padding: EdgeInsets.only(left: 12), ), diff --git a/lib/src/components/picker/base/brn_picker.dart b/lib/src/components/picker/base/brn_picker.dart index 2b08b40f..3776a810 100644 --- a/lib/src/components/picker/base/brn_picker.dart +++ b/lib/src/components/picker/base/brn_picker.dart @@ -424,10 +424,11 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { set controller(FixedExtentScrollController? value) { if (value == _controller) return; - if (_controller != null) + if (_controller != null) { _controller!.removeListener(_handleScrollUpdate); - else + } else { _currentIndex = value!.initialItem; + } value?.addListener(_handleScrollUpdate); _controller = value; } @@ -468,8 +469,9 @@ class _RenderCupertinoPickerSemantics extends RenderProxyBox { @override void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable children) { - if (children.isEmpty) + if (children.isEmpty) { return super.assembleSemanticsNode(node, config, children); + } final SemanticsNode scrollable = children.first; final Map indexedChildren = {}; scrollable.visitChildren((SemanticsNode child) { diff --git a/lib/src/components/picker/brn_bottom_picker.dart b/lib/src/components/picker/brn_bottom_picker.dart index 2d6ba65e..65c7e9da 100644 --- a/lib/src/components/picker/brn_bottom_picker.dart +++ b/lib/src/components/picker/brn_bottom_picker.dart @@ -76,7 +76,7 @@ class BrnBottomPickerWidget extends StatefulWidget { final dynamic cancel; final Function()? onConfirmPressed; final Function()? onCancelPressed; - final barrierDismissible; + final bool barrierDismissible; final BrnPickerTitleConfig pickerTitleConfig; const BrnBottomPickerWidget({ diff --git a/lib/src/components/picker/brn_bottom_write_picker.dart b/lib/src/components/picker/brn_bottom_write_picker.dart index c5a5cbaf..e2027c7a 100644 --- a/lib/src/components/picker/brn_bottom_write_picker.dart +++ b/lib/src/components/picker/brn_bottom_write_picker.dart @@ -117,7 +117,7 @@ class _BottomWritePickerState extends State { void initState() { super.initState(); if (_controller == null) { - if (widget.defaultText != null && widget.defaultText!.length > 0) { + if (widget.defaultText != null && widget.defaultText!.isNotEmpty) { _controller = TextEditingController.fromValue(TextEditingValue( text: widget.defaultText!, selection: TextSelection.fromPosition(TextPosition( diff --git a/lib/src/components/picker/brn_multi_picker.dart b/lib/src/components/picker/brn_multi_picker.dart index 3c4aa26f..46b4c7af 100644 --- a/lib/src/components/picker/brn_multi_picker.dart +++ b/lib/src/components/picker/brn_multi_picker.dart @@ -18,10 +18,10 @@ typedef BrnMultiDataPickerCreateWidgetCallback = Widget Function( bool isSelect, int column, int row, List selectedItems); /// 创建一级数据widget列表 -typedef List CreateWidgetList(); +typedef CreateWidgetList = List Function(); /// 确定筛选内容事件回调 -typedef void ConfirmButtonClick(List selectedIndexList); +typedef ConfirmButtonClick = void Function(List selectedIndexList); /// 数据适配 Delegate abstract class BrnMultiDataPickerDelegate { @@ -197,8 +197,9 @@ class _BrnMultiDataPickerState extends State { }, onConfirm: () { Navigator.of(context).pop(_selectedIndexList); - if (widget.confirmClick != null) + if (widget.confirmClick != null) { widget.confirmClick!(_selectedIndexList); + } }, ); } @@ -383,7 +384,7 @@ class _MyPickerState extends State { widget.changed!(index); } }, - children: children.length > 0 + children: children.isNotEmpty ? children : [ Center(child: Text('')), diff --git a/lib/src/components/picker/brn_select_tags_with_input_picker.dart b/lib/src/components/picker/brn_select_tags_with_input_picker.dart index ec480659..9988365d 100644 --- a/lib/src/components/picker/brn_select_tags_with_input_picker.dart +++ b/lib/src/components/picker/brn_select_tags_with_input_picker.dart @@ -461,8 +461,8 @@ class _BrnSelectTagsWithInputPickerWidgetState break; } } - return this._selectedTags.length > 0 && - (needExpend ? _textEditingController!.text.length > 0 : true); + return this._selectedTags.isNotEmpty && + (needExpend ? _textEditingController!.text.isNotEmpty : true); } bool isShowTextInput() { diff --git a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart index ab22d14a..162fe8a6 100644 --- a/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart +++ b/lib/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart @@ -74,7 +74,7 @@ class BrnPickerEntity { } void configDefaultValue() { - if (this.children.length > 0) { + if (this.children.isNotEmpty) { for (BrnPickerEntity entity in this.children) { if (!BrunoTools.isEmpty(defaultValue)) { List values = defaultValue!.split(','); @@ -83,12 +83,12 @@ class BrnPickerEntity { entity.configDefaultValue(); } - isSelected = isSelected || children.where((_) => _.isSelected).length > 0; + isSelected = isSelected || children.where((_) => _.isSelected).isNotEmpty; } } void configRelationship() { - if (this.children.length > 0) { + if (this.children.isNotEmpty) { for (BrnPickerEntity entity in this.children) { entity.parent = this; entity.configRelationship(); @@ -117,7 +117,7 @@ class BrnPickerEntity { } void clearChildSelection() { - if (this.children.length > 0) { + if (this.children.isNotEmpty) { for (BrnPickerEntity entity in this.children) { entity.isSelected = false; entity.clearChildSelection(); @@ -127,16 +127,16 @@ class BrnPickerEntity { List selectedLastColumnList() { List list = []; - if (this.children.length > 0) { + if (this.children.isNotEmpty) { List firstList = []; for (BrnPickerEntity firstEntity in this.children) { - if (firstEntity.children.length > 0) { + if (firstEntity.children.isNotEmpty) { List secondList = []; for (BrnPickerEntity secondEntity in firstEntity.children) { - if (secondEntity.children.length > 0) { + if (secondEntity.children.isNotEmpty) { List thirds = this.currentSelectListForEntity(secondEntity); - if (thirds.length > 0) { + if (thirds.isNotEmpty) { list.addAll(thirds); } else if (secondEntity.isSelected) { secondList.add(secondEntity); @@ -164,12 +164,12 @@ class BrnPickerEntity { List results = []; List firstColumn = this.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn.length > 0) { + if (firstColumn.isNotEmpty) { for (BrnPickerEntity firstEntity in firstColumn) { List secondColumn = this.currentSelectListForEntity(firstEntity); results.addAll(secondColumn); - if (secondColumn.length > 0) { + if (secondColumn.isNotEmpty) { for (BrnPickerEntity secondEntity in secondColumn) { List thirdColumn = this.currentSelectListForEntity(secondEntity); @@ -184,7 +184,7 @@ class BrnPickerEntity { /// 返回状态为选中的子节点 List currentSelectListForEntity(BrnPickerEntity entity) { List list = []; - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { for (BrnPickerEntity entity in entity.children) { if (entity.isSelected) { list.add(entity); @@ -210,7 +210,7 @@ class BrnPickerEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || parent!.children.length == 0) return -1; + if (parent == null || parent!.children.isEmpty) return -1; for (BrnPickerEntity entity in parent!.children) { if (entity == this) { @@ -221,10 +221,10 @@ class BrnPickerEntity { } bool isInLastLevel() { - if (parent == null || parent!.children.length == 0) return true; + if (parent == null || parent!.children.isEmpty) return true; for (BrnPickerEntity entity in parent!.children) { - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { return false; } } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart index 6297610c..fd0212f9 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_list.dart @@ -11,7 +11,7 @@ import 'package:flutter/material.dart'; /// [listIndex] 点击位置处于第几列 /// [index] 点击位置处于当前列的位置 /// [entity] 被点击位置的数据 -typedef bool BrnOnSelectEntityInterceptor( +typedef BrnOnSelectEntityInterceptor = bool Function( int? listIndex, int index, BrnPickerEntity entity); // ignore: must_be_immutable @@ -49,7 +49,7 @@ class BrnMultiColumnListWidget extends StatefulWidget { }); currentListIndex = BrnMultiColumnPickerUtil.getCurrentColumnIndex( - items!.length > 0 ? items![0] : null); + items!.isNotEmpty ? items![0] : null); _selectedItems = items?.where((f) => f.isSelected).toList(); if (_selectedItems == null) { @@ -160,12 +160,10 @@ class _BrnMultiColumnListWidgetState extends State { /// (两列、三列时)第一列节点是否被选中取决于它的子节点是否被选中, /// 只有当它子节点被选中时才会认为第一列的节点相应被选中。 if (widget.items != null && - widget.items!.length > 0 && + widget.items!.isNotEmpty && widget.items![0].parent != null) { widget.items![0].parent?.isSelected = widget.items![0].parent!.children - .where((BrnPickerEntity f) => f.isSelected) - .length > - 0; + .where((BrnPickerEntity f) => f.isSelected).isNotEmpty; } for (BrnPickerEntity item in widget.items!) { @@ -193,9 +191,9 @@ class _BrnMultiColumnListWidgetState extends State { selectedEntity.isSelected = true; } else { ///清除【不限】类型。 - var brotherItems; + List brotherItems; if (selectedEntity.parent == null) { - brotherItems = widget.items; + brotherItems = widget.items ?? []; } else { brotherItems = selectedEntity.parent!.children; } @@ -227,9 +225,9 @@ class _BrnMultiColumnListWidgetState extends State { selectedEntity.isSelected = true; } else { ///清除【不限】类型。 - var brotherItems; + List brotherItems; if (selectedEntity.parent == null) { - brotherItems = widget.items; + brotherItems = widget.items ?? []; } else { brotherItems = selectedEntity.parent!.children; } @@ -261,9 +259,9 @@ class _BrnMultiColumnListWidgetState extends State { selectedEntity.isSelected = true; } else { ///清除【不限】类型。 - var brotherItems; + List brotherItems; if (selectedEntity.parent == null) { - brotherItems = widget.items; + brotherItems = widget.items ?? []; } else { brotherItems = selectedEntity.parent!.children; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart index e070c441..2e0b11a6 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker.dart @@ -16,7 +16,7 @@ import 'package:flutter/material.dart'; /// [columnIndex] 数据项所在列 /// [rowIndex] 数据项所在列中的位置 /// [entity] 被点击的数据项 -typedef void BrnOnEntityTap( +typedef BrnOnEntityTap = void Function( int columnIndex, int rowIndex, BrnPickerEntity entity); /// 单个数据项被点击的回调, @@ -24,7 +24,7 @@ typedef void BrnOnEntityTap( /// [firstIndex] 第一列被选中数据的位置 /// [secondIndex] 第二列被选中数据的位置 /// [thirdIndex] 第三列被选中数据的位置 -typedef void BrnOnPickerConfirm(Map> results, +typedef BrnOnPickerConfirm = void Function(Map> results, int? firstIndex, int? secondIndex, int? thirdIndex); /// 从屏幕下方弹起的多级筛选选择器 @@ -455,7 +455,7 @@ class _BrnSelectionGroupViewState extends State { int _getInitialSelectIndex(List? levelList) { int index = -1; - if (levelList == null || levelList.length == 0) { + if (levelList == null || levelList.isEmpty) { return index; } diff --git a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart index 27017e2e..14fb5ff0 100644 --- a/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart +++ b/lib/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; /// BrnMultiColumnPicker相关工具类 @@ -12,13 +10,13 @@ class BrnMultiColumnPickerUtil { rootEntity = rootEntity?.parent!; } - if (rootEntity != null && rootEntity.children.length > 0) { + if (rootEntity != null && rootEntity.children.isNotEmpty) { count = count > 1 ? count : 1; for (BrnPickerEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children.isNotEmpty) { count = count > 2 ? count : 2; for (BrnPickerEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children.length > 0) { + if (secondLevelEntity.children.isNotEmpty) { count = 3; break; } diff --git a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart index 521a3652..47821ad8 100644 --- a/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart +++ b/lib/src/components/picker/multi_range_picker/btn_multi_column_picker_item.dart @@ -1,13 +1,9 @@ - - import 'package:bruno/src/components/picker/multi_range_picker/bean/brn_multi_column_picker_entity.dart'; import 'package:bruno/src/components/picker/multi_range_picker/brn_multi_column_picker_util.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef void ItemSelectFunction(BrnPickerEntity entity); - class BrnMultiRangePickerCommonItem extends StatelessWidget { final BrnPickerEntity item; final Color normalColor; @@ -19,7 +15,7 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { final bool isMoreSelectionListType; - final ItemSelectFunction? itemSelectFunction; + final ValueChanged? itemSelectFunction; BrnMultiRangePickerCommonItem({ required this.item, @@ -35,8 +31,8 @@ class BrnMultiRangePickerCommonItem extends StatelessWidget { @override Widget build(BuildContext context) { - var checkbox; - if (!item.isUnLimit() && (item.children.length == 0)) { + Container checkbox; + if (!item.isUnLimit() && (item.children.isEmpty)) { if (item.isInLastLevel() && _hasCheckBoxBrother(item)) { checkbox = Container( padding: EdgeInsets.only(left: 6), diff --git a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart index f8c04c82..cdb7f280 100755 --- a/lib/src/components/picker/time_picker/brn_date_picker_constants.dart +++ b/lib/src/components/picker/time_picker/brn_date_picker_constants.dart @@ -1,15 +1,15 @@ /// Selected value of DatePicker. -typedef DateValueCallback(DateTime dateTime, List selectedIndex); +typedef DateValueCallback = Function(DateTime dateTime, List selectedIndex); -typedef DateRangeValueCallback(DateTime startDateTime, DateTime endDateTime, +typedef DateRangeValueCallback = Function(DateTime startDateTime, DateTime endDateTime, List startSelectedIndex, List endSelectedIndex); -typedef DateRangeSideValueCallback( +typedef DateRangeSideValueCallback = Function( DateTime selectDateTime, List selectedIndex); /// Pressed cancel callback. -typedef DateVoidCallback(); +typedef DateVoidCallback = Function(); /// Default value of minimum datetime. const String datePickerMinDatetime = "1900-01-01 00:00:00"; diff --git a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart index 0994b820..e89c1f16 100755 --- a/lib/src/components/picker/time_picker/brn_date_time_formatter.dart +++ b/lib/src/components/picker/time_picker/brn_date_time_formatter.dart @@ -29,7 +29,7 @@ class DateTimeFormatter { /// Get default value of date format. static String generateDateFormat( String? dateFormat, BrnDateTimePickerMode pickerMode) { - if (dateFormat != null && dateFormat.length > 0) { + if (dateFormat != null && dateFormat.isNotEmpty) { return dateFormat; } switch (pickerMode) { @@ -44,7 +44,7 @@ class DateTimeFormatter { static String generateDateRangePickerFormat( String? dateFormat, BrnDateTimeRangePickerMode pickerMode) { - if (dateFormat != null && dateFormat.length > 0) { + if (dateFormat != null && dateFormat.isNotEmpty) { return dateFormat; } switch (pickerMode) { @@ -68,7 +68,7 @@ class DateTimeFormatter { /// Split date format to array. static List splitDateFormat(String? dateFormat, {BrnDateTimePickerMode? mode}) { - if (dateFormat == null || dateFormat.length == 0) { + if (dateFormat == null || dateFormat.isEmpty) { return []; } List result = dateFormat.split(RegExp(DATE_FORMAT_SEPARATOR)); @@ -107,7 +107,7 @@ class DateTimeFormatter { /// Format datetime string static String formatDateTime( int value, String format, DateTimePickerLocale locale) { - if (format.length == 0) { + if (format.isEmpty) { return value.toString(); } @@ -148,7 +148,7 @@ class DateTimeFormatter { /// Format day display static String formatDate( DateTime dateTime, String format, DateTimePickerLocale locale) { - if (format.length == 0) { + if (format.isEmpty) { return dateTime.toString(); } diff --git a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart index 18a6e077..6f842698 100755 --- a/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart +++ b/lib/src/components/picker/time_picker/date_picker/brn_datetime_widget.dart @@ -216,19 +216,19 @@ class _BrnDateTimeWidgetState extends State { /// 如果传入的时间格式不包含 月、天、小时、分钟、秒。则相对应的时间置为 1,1,0,0,0; DateTime dateTime = DateTime( _currYear, - (formatArr.where((format) => format.contains('M')).toList()).length > 0 + (formatArr.where((format) => format.contains('M')).toList()).isNotEmpty ? _currMonth : 1, - (formatArr.where((format) => format.contains('d')).toList()).length > 0 + (formatArr.where((format) => format.contains('d')).toList()).isNotEmpty ? _currDay : 1, - (formatArr.where((format) => format.contains('H')).toList()).length > 0 + (formatArr.where((format) => format.contains('H')).toList()).isNotEmpty ? _currHour : 0, - (formatArr.where((format) => format.contains('m')).toList()).length > 0 + (formatArr.where((format) => format.contains('m')).toList()).isNotEmpty ? _currMinute : 0, - (formatArr.where((format) => format.contains('s')).toList()).length > 0 + (formatArr.where((format) => format.contains('s')).toList()).isNotEmpty ? _currSecond : 0, ); diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart index fb3a4afb..b975afac 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_side_widget.dart @@ -212,7 +212,7 @@ class _DatePickerWidgetState extends State { required String format, required ValueChanged valueChanged, }) { - var globalKey; + GlobalKey? globalKey; if (_scrolledNotDay && format.contains("d")) { globalKey = GlobalKey(); _scrolledNotDay = false; diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart index e5f311b1..ff43ddb6 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_date_range_widget.dart @@ -191,8 +191,8 @@ class _DatePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { /// 用于强制刷新 Widget - var firstGlobalKey; - var secondGlobalKey; + GlobalKey? firstGlobalKey; + GlobalKey? secondGlobalKey; if (_isFirstScroll) { secondGlobalKey = GlobalKey(); diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart index d1841e8e..1a0573e0 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_side_widget.dart @@ -232,7 +232,7 @@ class _TimePickerWidgetState extends State { required String format, required ValueChanged valueChanged, }) { - var globalKey; + GlobalKey? globalKey; if (_scrolledNotMinute && format.contains("m")) { globalKey = GlobalKey(); _scrolledNotMinute = false; diff --git a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart index ef48138d..07fe2d61 100755 --- a/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart +++ b/lib/src/components/picker/time_picker/date_range_picker/brn_time_range_widget.dart @@ -27,7 +27,7 @@ class BrnTimeRangeWidget extends StatefulWidget { final DateTime? initialEndDateTime; /// 是否限制 Picker 选择的时间范围(开始时间≤结束时间) - final isLimitTimeRange; + final bool isLimitTimeRange; /// 时间格式 final String? dateFormat; @@ -212,8 +212,8 @@ class _TimePickerWidgetState extends State { /// render the picker widget of year、month and day Widget _renderDatePickerWidget() { /// 用于强制刷新 Widget - var firstGlobalKey; - var secondGlobalKey; + GlobalKey? firstGlobalKey; + GlobalKey? secondGlobalKey; if (widget._isFirstScroll) { secondGlobalKey = GlobalKey(); @@ -237,7 +237,7 @@ class _TimePickerWidgetState extends State { maxDateTime: _maxTime, initialStartDateTime: _startSelectedDateTime, minuteDivider: _minuteDivider, - onInitSelectChange: (widget.isLimitTimeRange ?? true) + onInitSelectChange: (widget.isLimitTimeRange) ? (DateTime selectedDateTime, List selected) { _startSelectedDateTime = selectedDateTime; _startSelectedIndex = selected; @@ -260,17 +260,17 @@ class _TimePickerWidgetState extends State { child: BrnTimeRangeSideWidget( key: secondGlobalKey, dateFormat: widget.dateFormat, - minDateTime: (widget.isLimitTimeRange ?? true) + minDateTime: (widget.isLimitTimeRange) ? _startSelectedDateTime : _minTime, maxDateTime: _maxTime, - initialStartDateTime: (widget.isLimitTimeRange ?? true) + initialStartDateTime: (widget.isLimitTimeRange) ? _endSelectedDateTime.compareTo(_startSelectedDateTime) > 0 ? _endSelectedDateTime : _startSelectedDateTime : _endSelectedDateTime, minuteDivider: _minuteDivider, - onInitSelectChange: (widget.isLimitTimeRange ?? true) + onInitSelectChange: (widget.isLimitTimeRange) ? (DateTime selectedDateTime, List selected) { _endSelectedDateTime = selectedDateTime; _endSelectedIndex = selected; diff --git a/lib/src/components/popup/brn_measure_size.dart b/lib/src/components/popup/brn_measure_size.dart index d2e08eaf..199f3e89 100644 --- a/lib/src/components/popup/brn_measure_size.dart +++ b/lib/src/components/popup/brn_measure_size.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -typedef void OnWidgetSizeChange(Size size); +typedef OnWidgetSizeChange = void Function(Size size); /// 描述: 计算 Widget 宽高的工具类。 class MeasureSizeRenderObject extends RenderProxyBox { diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 9a096a21..35b96e3a 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -1,5 +1,3 @@ - - import 'dart:async'; import 'package:bruno/src/components/tabbar/normal/brn_tab_bar.dart'; @@ -180,14 +178,15 @@ class _BrnScrollAnchorTabWidgetState extends State listDy = globalToLocal.dy; for (int i = 0, n = widget.itemCount; i < n; i++) { - if (_cardOffsetList[i] == -1.0) if (_bodyKeyList[i].currentContext != - null) { - double cardOffset = - (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 - - _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; + if (_cardOffsetList[i] == -1.0) { + if (_bodyKeyList[i].currentContext != null) { + double cardOffset = + (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 + + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; + } } } } @@ -200,14 +199,15 @@ class _BrnScrollAnchorTabWidgetState extends State void updateOffset() { for (int i = 0, n = widget.itemCount; i < n; i++) { - if (_cardOffsetList[i] == -1.0) if (_bodyKeyList[i].currentContext != - null) { - double cardOffset = - (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 - - _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; + if (_cardOffsetList[i] == -1.0) { + if (_bodyKeyList[i].currentContext != null) { + double cardOffset = + (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 + + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; + } } } } diff --git a/lib/src/components/selectcity/brn_az_listview.dart b/lib/src/components/selectcity/brn_az_listview.dart index 5243f172..c3d306a9 100644 --- a/lib/src/components/selectcity/brn_az_listview.dart +++ b/lib/src/components/selectcity/brn_az_listview.dart @@ -5,16 +5,16 @@ import 'package:flutter/material.dart'; /// Called to build children for the listView. /// 列表的Item -typedef Widget ItemWidgetBuilder(BuildContext context, ISuspensionBean model); +typedef ItemWidgetBuilder = Widget Function(BuildContext context, ISuspensionBean model); /// Called to build IndexBar. /// 右侧索引区域 -typedef Widget IndexBarBuilder( +typedef IndexBarBuilder = Widget Function( BuildContext context, List tags, IndexBarTouchCallback onTouch); /// Called to build index hint. /// 右侧索引项滑动或点击 页面显示的Widget -typedef Widget IndexHintBuilder(BuildContext context, String hint); +typedef IndexHintBuilder = Widget Function(BuildContext context, String hint); /// _Header. class _Header extends ISuspensionBean { diff --git a/lib/src/components/selectcity/brn_index_bar.dart b/lib/src/components/selectcity/brn_index_bar.dart index 3db2109e..e71d23ad 100644 --- a/lib/src/components/selectcity/brn_index_bar.dart +++ b/lib/src/components/selectcity/brn_index_bar.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; /// IndexBar touch callback IndexModel. -typedef void IndexBarTouchCallback(IndexBarDetails model); +typedef IndexBarTouchCallback = void Function(IndexBarDetails model); /// IndexModel. class IndexBarDetails { diff --git a/lib/src/components/selectcity/brn_single_select_city_page.dart b/lib/src/components/selectcity/brn_single_select_city_page.dart index b8b7c961..7d5d54a3 100644 --- a/lib/src/components/selectcity/brn_single_select_city_page.dart +++ b/lib/src/components/selectcity/brn_single_select_city_page.dart @@ -342,7 +342,7 @@ class _BrnSingleSelectCityPageState extends State { ///城市搜索结果页 Widget _buildSearchResultList(String searchText) { List cList = _searchCityList(searchText); - return (cList.length == 0) + return (cList.isEmpty) ? _noDataWidget() : Expanded( flex: 1, diff --git a/lib/src/components/selectcity/brn_suspension_view.dart b/lib/src/components/selectcity/brn_suspension_view.dart index 34f0bcbc..b7c8f82c 100644 --- a/lib/src/components/selectcity/brn_suspension_view.dart +++ b/lib/src/components/selectcity/brn_suspension_view.dart @@ -2,7 +2,7 @@ import 'package:bruno/src/components/selectcity/brn_az_common.dart'; import 'package:flutter/material.dart'; /// on all sus section callback(map: Used to scroll the list to the specified tag location). -typedef void OnSusSectionCallBack(Map map); +typedef SusSectionTapCallback = void Function(Map map); ///Suspension Widget.Currently only supports fixed height items! class SuspensionView extends StatefulWidget { @@ -28,7 +28,7 @@ class SuspensionView extends StatefulWidget { final ValueChanged? onSusTagChanged; /// on sus section callback. - final OnSusSectionCallBack? onSusSectionInited; + final SusSectionTapCallback? onSusSectionInited; final AzListViewHeader? header; diff --git a/lib/src/components/selection/bean/brn_selection_common_entity.dart b/lib/src/components/selection/bean/brn_selection_common_entity.dart index 1bc70af5..48e6ab4c 100644 --- a/lib/src/components/selection/bean/brn_selection_common_entity.dart +++ b/lib/src/components/selection/bean/brn_selection_common_entity.dart @@ -204,7 +204,7 @@ class BrnSelectionEntity { } void configRelationship() { - if (children.length > 0) { + if (children.isNotEmpty) { for (BrnSelectionEntity entity in children) { entity.parent = this; } @@ -215,7 +215,7 @@ class BrnSelectionEntity { } void configDefaultValue() { - if (children.length > 0) { + if (children.isNotEmpty) { for (BrnSelectionEntity entity in children) { if (!BrunoTools.isEmpty(defaultValue)) { List values = defaultValue!.split(','); @@ -224,7 +224,7 @@ class BrnSelectionEntity { } /// 当 default 不在普通 Item 类型中时,尝试填充 同级别 Range Item. - if (children.where((_) => _.isSelected).toList().length == 0) { + if (children.where((_) => _.isSelected).toList().isEmpty) { List rangeItems = this.children.where((_) { return (_.filterType == BrnSelectionFilterType.range || _.filterType == BrnSelectionFilterType.dateRange || @@ -250,10 +250,10 @@ class BrnSelectionEntity { entity.configDefaultValue(); } if (hasCheckBoxBrother()) { - isSelected = children.where((_) => _.isSelected).length > 0; + isSelected = children.where((_) => _.isSelected).isNotEmpty; } else { isSelected = - isSelected || children.where((_) => _.isSelected).length > 0; + isSelected || children.where((_) => _.isSelected).isNotEmpty; } } } @@ -295,7 +295,7 @@ class BrnSelectionEntity { } void clearChildSelection() { - if (children.length > 0) { + if (children.isNotEmpty) { for (BrnSelectionEntity entity in children) { entity.isSelected = false; if (entity.filterType == BrnSelectionFilterType.date) { @@ -313,16 +313,16 @@ class BrnSelectionEntity { List selectedLastColumnList() { List list = []; - if (this.children.length > 0) { + if (this.children.isNotEmpty) { List firstList = []; for (BrnSelectionEntity firstEntity in this.children) { - if (firstEntity.children.length > 0) { + if (firstEntity.children.isNotEmpty) { List secondList = []; for (BrnSelectionEntity secondEntity in firstEntity.children) { - if (secondEntity.children.length > 0) { + if (secondEntity.children.isNotEmpty) { List thirds = BrnSelectionUtil.currentSelectListForEntity(secondEntity); - if (thirds.length > 0) { + if (thirds.isNotEmpty) { list.addAll(thirds); } else if (secondEntity.isSelected) { secondList.add(secondEntity); @@ -368,12 +368,12 @@ class BrnSelectionEntity { List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn.length > 0) { + if (firstColumn.isNotEmpty) { for (BrnSelectionEntity firstEntity in firstColumn) { List secondColumn = BrnSelectionUtil.currentSelectListForEntity(firstEntity); results.addAll(secondColumn); - if (secondColumn.length > 0) { + if (secondColumn.isNotEmpty) { for (BrnSelectionEntity secondEntity in secondColumn) { List thirdColumn = BrnSelectionUtil.currentSelectListForEntity(secondEntity); @@ -391,12 +391,12 @@ class BrnSelectionEntity { List firstColumn = BrnSelectionUtil.currentSelectListForEntity(this); results.addAll(firstColumn); - if (firstColumn.length > 0) { + if (firstColumn.isNotEmpty) { for (BrnSelectionEntity firstEntity in firstColumn) { List secondColumn = BrnSelectionUtil.currentSelectListForEntity(firstEntity); results.addAll(secondColumn); - if (secondColumn.length > 0) { + if (secondColumn.isNotEmpty) { for (BrnSelectionEntity secondEntity in secondColumn) { List thirdColumn = BrnSelectionUtil.currentSelectListForEntity(secondEntity); @@ -442,7 +442,7 @@ class BrnSelectionEntity { /// 判断当前的筛选 Item 是否为当前层次中第一个被选中的 Item。 /// 用于展开筛选弹窗时显示选中效果。 int getIndexInCurrentLevel() { - if (parent == null || parent!.children.length == 0) return -1; + if (parent == null || parent!.children.isEmpty) return -1; for (BrnSelectionEntity entity in parent!.children) { if (entity == this) { @@ -454,10 +454,10 @@ class BrnSelectionEntity { /// 是否在筛选数据的最后一层。 如果最大层次为 3;某个筛选数据层次为 2,但其无子节点。此时认为不在最后一层。 bool isInLastLevel() { - if (parent == null || parent!.children.length == 0) return true; + if (parent == null || parent!.children.isEmpty) return true; for (BrnSelectionEntity entity in parent!.children) { - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { return false; } } diff --git a/lib/src/components/selection/brn_flat_selection.dart b/lib/src/components/selection/brn_flat_selection.dart index 8fd19c9a..7d8b03d0 100644 --- a/lib/src/components/selection/brn_flat_selection.dart +++ b/lib/src/components/selection/brn_flat_selection.dart @@ -82,7 +82,7 @@ class _BrnFlatSelectionState extends State widget.controller?.addListener(_handleFlatControllerTick); List firstColumn = []; - if (widget.entityDataList.length > 0) { + if (widget.entityDataList.isNotEmpty) { for (BrnSelectionEntity entity in widget.entityDataList) { if (entity.isSelected) { firstColumn.add(entity); @@ -90,12 +90,12 @@ class _BrnFlatSelectionState extends State } } _originalSelectedItemsList.addAll(firstColumn); - if (firstColumn.length > 0) { + if (firstColumn.isNotEmpty) { for (BrnSelectionEntity firstEntity in firstColumn) { List secondColumn = BrnSelectionUtil.currentSelectListForEntity(firstEntity); _originalSelectedItemsList.addAll(secondColumn); - if (secondColumn.length > 0) { + if (secondColumn.isNotEmpty) { for (BrnSelectionEntity secondEntity in secondColumn) { List thirdColumn = BrnSelectionUtil.currentSelectListForEntity(secondEntity); @@ -151,7 +151,7 @@ class _BrnFlatSelectionState extends State /// 取消 _cancelSelectedOptions() { - if (widget.entityDataList.length <= 0) { + if (widget.entityDataList.isEmpty) { return; } for (BrnSelectionEntity entity in widget.entityDataList) { @@ -173,7 +173,7 @@ class _BrnFlatSelectionState extends State /// 重置 _resetSelectedOptions() { clearController.add(FlatClearEvent()); - if (widget.entityDataList.length > 0) { + if (widget.entityDataList.isNotEmpty) { for (BrnSelectionEntity entity in widget.entityDataList) { _clearUIData(entity); } diff --git a/lib/src/components/selection/brn_selection_util.dart b/lib/src/components/selection/brn_selection_util.dart index 69b488d8..ae759f18 100644 --- a/lib/src/components/selection/brn_selection_util.dart +++ b/lib/src/components/selection/brn_selection_util.dart @@ -48,14 +48,14 @@ class BrnSelectionUtil { rootEntity = rootEntity.parent!; } - if (rootEntity.children.length > 0) { + if (rootEntity.children.isNotEmpty) { level = level > 1 ? level : 1; for (BrnSelectionEntity firstLevelEntity in rootEntity.children) { - if (firstLevelEntity.children.length > 0) { + if (firstLevelEntity.children.isNotEmpty) { level = level > 2 ? level : 2; for (BrnSelectionEntity secondLevelEntity in firstLevelEntity.children) { - if (secondLevelEntity.children.length > 0) { + if (secondLevelEntity.children.isNotEmpty) { level = 3; break; } @@ -104,7 +104,7 @@ class BrnSelectionUtil { filledCustomInputItem = entity; break; } - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { filledCustomInputItem = getFilledCustomInputItem(entity.children); } if (filledCustomInputItem != null) { diff --git a/lib/src/components/selection/brn_selection_view.dart b/lib/src/components/selection/brn_selection_view.dart index 1843df76..905e71f0 100644 --- a/lib/src/components/selection/brn_selection_view.dart +++ b/lib/src/components/selection/brn_selection_view.dart @@ -11,7 +11,7 @@ import 'package:flutter/material.dart'; /// 配置 类型为 Range 展示时,每行 tag 的数量 /// [index] 第几个 menu /// [entity] index 对应的 筛选对象 -typedef BrnConfigTagCountPerRow(int index, BrnSelectionEntity entity); +typedef BrnConfigTagCountPerRow = Function(int index, BrnSelectionEntity entity); /// [menuTitle] 设置自定义 menu 的Title文案 /// [isMenuTitleHighLight] 设置自定义 menu 的 title 是否高亮 @@ -132,10 +132,7 @@ class BrnSelectionView extends StatefulWidget { } @override - State createState() { - // TODO: implement createState - return BrnSelectionViewState(); - } + State createState() => BrnSelectionViewState(); } class BrnSelectionViewState extends State { @@ -158,7 +155,7 @@ class BrnSelectionViewState extends State { @override Widget build(BuildContext context) { - if (widget.originalSelectionData.length > 0) { + if (widget.originalSelectionData.isNotEmpty) { widget.originalSelectionData.forEach((f) => f.configRelationship()); return BrnSelectionMenuWidget( context: context, @@ -254,7 +251,7 @@ class BrnSelectionViewState extends State { void _openMore(BrnSelectionEntity entity, {BrnOnCustomFloatingLayerClick? onCustomFloatingLayerClick}) { - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { Navigator.of(context).push(PageRouteBuilder( opaque: false, pageBuilder: (context, animation, second) { diff --git a/lib/src/components/selection/widget/brn_flat_selection_item.dart b/lib/src/components/selection/widget/brn_flat_selection_item.dart index fd8c4de2..12b781e2 100644 --- a/lib/src/components/selection/widget/brn_flat_selection_item.dart +++ b/lib/src/components/selection/widget/brn_flat_selection_item.dart @@ -178,9 +178,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { ), Visibility( visible: widget.selectionEntity - .currentShowTagByExpanded(isExpanded) - .length > - 0, + .currentShowTagByExpanded(isExpanded).isNotEmpty, child: Container( padding: EdgeInsets.only(top: 12), child: _buildOptionWidgets(), diff --git a/lib/src/components/selection/widget/brn_selection_animate_widget.dart b/lib/src/components/selection/widget/brn_selection_animate_widget.dart index 7cd9c1cd..c83821de 100644 --- a/lib/src/components/selection/widget/brn_selection_animate_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_animate_widget.dart @@ -1,8 +1,6 @@ import 'package:bruno/src/components/selection/controller/brn_selection_view_controller.dart'; import 'package:flutter/material.dart'; -typedef void MaskClickFunction(int index); - class BrnSelectionAnimationWidget extends StatefulWidget { final BrnSelectionListViewController controller; final Widget view; diff --git a/lib/src/components/selection/widget/brn_selection_common_item_widget.dart b/lib/src/components/selection/widget/brn_selection_common_item_widget.dart index 7cae62f9..b512dfc5 100644 --- a/lib/src/components/selection/widget/brn_selection_common_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_common_item_widget.dart @@ -6,8 +6,6 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/utils/css/brn_css_2_text.dart'; import 'package:flutter/material.dart'; -typedef void ItemSelectFunction(BrnSelectionEntity entity); - class BrnSelectionCommonItemWidget extends StatelessWidget { final BrnSelectionEntity item; final Color? backgroundColor; @@ -16,7 +14,7 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { final bool isFirstLevel; final bool isMoreSelectionListType; - final ItemSelectFunction? itemSelectFunction; + final ValueChanged? itemSelectFunction; final BrnSelectionConfig? themeData; @@ -34,8 +32,8 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { - var checkbox; - if (!item.isUnLimit() && (item.children.length == 0)) { + Container checkbox; + if (!item.isUnLimit() && (item.children.isEmpty)) { if (item.isInLastLevel() && item.hasCheckBoxBrother()) { checkbox = Container( padding: EdgeInsets.only(left: 6), @@ -129,7 +127,7 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { if (isHighLight(item)) { return true; } else { - return item.hasCheckBoxBrother() && item.selectedList().length > 0; + return item.hasCheckBoxBrother() && item.selectedList().isNotEmpty; } } @@ -155,7 +153,7 @@ class BrnSelectionCommonItemWidget extends StatelessWidget { } else { var unLimited = item.children.where((f) => f.isSelected && f.isUnLimit()).toList(); - if (unLimited.length > 0) { + if (unLimited.isNotEmpty) { return '(全部)'; } } diff --git a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart index f789193c..b1079422 100644 --- a/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_date_range_item_widget.dart @@ -10,9 +10,6 @@ import 'package:bruno/src/utils/i18n/brn_date_picker_i18n.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -typedef void OnRangeChangedFunction(String minInput, String maxInput); -typedef void OnTappedFunction(); - const String _defaultDateFormat = 'yyyy年MM月dd日'; // ignore: must_be_immutable @@ -31,7 +28,7 @@ class BrnSelectionDateRangeItemWidget extends StatefulWidget { final TextEditingController minTextEditingController; final TextEditingController maxTextEditingController; - final OnTappedFunction? onTapped; + final VoidCallback? onTapped; BrnSelectionConfig themeData; @@ -58,13 +55,13 @@ class _BrnSelectionDateRangeItemWidgetState @override void initState() { - var minDateTime; + DateTime? minDateTime; if (widget.item.customMap != null && widget.item.customMap!['min'] != null) { minDateTime = DateTimeFormatter.convertIntValueToDateTime( widget.item.customMap!['min']); } - var maxDateTime; + DateTime? maxDateTime; if (widget.item.customMap != null && widget.item.customMap!['max'] != null) { maxDateTime = DateTimeFormatter.convertIntValueToDateTime( @@ -256,7 +253,6 @@ class _BrnSelectionDateRangeItemWidgetState @override void dispose() { - // TODO: implement dispose _datePickerController.hide(); super.dispose(); } diff --git a/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart b/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart index ebc4ec00..7143ccc0 100644 --- a/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_datepicker_animate_widget.dart @@ -1,8 +1,6 @@ import 'package:bruno/src/components/selection/controller/brn_selection_view_date_picker_controller.dart'; import 'package:flutter/material.dart'; -typedef void MaskClickFunction(int index); - class BrnSelectionDatePickerAnimationWidget extends StatefulWidget { final BrnSelectionDatePickerController controller; final Widget view; diff --git a/lib/src/components/selection/widget/brn_selection_list_widget.dart b/lib/src/components/selection/widget/brn_selection_list_widget.dart index c0d32144..52a9d1f2 100644 --- a/lib/src/components/selection/widget/brn_selection_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_list_widget.dart @@ -10,17 +10,15 @@ import 'package:bruno/src/theme/configs/brn_selection_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef void SingleListItemSelect( +typedef SingleListItemSelect = void Function( int listIndex, int index, BrnSelectionEntity entity); -typedef void ListBgClickFunction(); - // ignore: must_be_immutable class BrnListSelectionGroupWidget extends StatefulWidget { final BrnSelectionEntity entity; final double maxContentHeight; final bool showSelectedCount; - final ListBgClickFunction? bgClickFunction; + final VoidCallback? bgClickFunction; final BrnOnRangeSelectionConfirm? onSelectionConfirm; BrnSelectionConfig themeData; @@ -434,7 +432,7 @@ class _BrnSelectionGroupViewState extends State { int _getInitialSelectIndex(List levelList) { int index = -1; - if (levelList.length == 0) { + if (levelList.isEmpty) { return index; } @@ -555,11 +553,11 @@ class _BrnSelectionGroupViewState extends State { } _processSelectedStatus(BrnSelectionEntity entity) { - if (entity.children.length > 0) { + if (entity.children.isNotEmpty) { entity.children.forEach((f) => _processSelectedStatus(f)); if (entity.hasCheckBoxBrother()) { entity.isSelected = - entity.children.where((_) => _.isSelected).length > 0; + entity.children.where((_) => _.isSelected).isNotEmpty; } } } diff --git a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart index cf74bb03..bae2214f 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_item_widget.dart @@ -3,14 +3,12 @@ import 'package:bruno/src/theme/configs/brn_selection_config.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef void ItemClickFunction(); - // ignore: must_be_immutable class BrnSelectionMenuItemWidget extends StatelessWidget { final String title; final bool isHighLight; final bool active; - final ItemClickFunction? itemClickFunction; + final VoidCallback? itemClickFunction; BrnSelectionConfig themeData; diff --git a/lib/src/components/selection/widget/brn_selection_menu_widget.dart b/lib/src/components/selection/widget/brn_selection_menu_widget.dart index 18a0a187..0deddc5b 100644 --- a/lib/src/components/selection/widget/brn_selection_menu_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_menu_widget.dart @@ -15,9 +15,9 @@ import 'package:bruno/src/utils/brn_tools.dart'; import 'package:bruno/src/utils/i18n/brn_date_picker_i18n.dart'; import 'package:flutter/material.dart'; -typedef bool BrnOnMenuItemClick(int index); +typedef BrnOnMenuItemClick = bool Function(int index); -typedef void BrnOnRangeSelectionConfirm(BrnSelectionEntity results, +typedef BrnOnRangeSelectionConfirm = void Function(BrnSelectionEntity results, int firstIndex, int secondIndex, int thirdIndex); class BrnSelectionMenuWidget extends StatefulWidget { @@ -302,7 +302,7 @@ class _BrnSelectionMenuWidgetState extends State { bgClickFunction: () { setState(() { menuItemActiveState[listViewController.menuIndex] = false; - if (entity.selectedListWithoutUnlimit().length > 0) { + if (entity.selectedListWithoutUnlimit().isNotEmpty) { menuItemHighlightState[listViewController.menuIndex] = true; } listViewController.hide(); @@ -329,7 +329,7 @@ class _BrnSelectionMenuWidgetState extends State { bgClickFunction: () { setState(() { menuItemActiveState[listViewController.menuIndex] = false; - if (entity.selectedListWithoutUnlimit().length > 0) { + if (entity.selectedListWithoutUnlimit().isNotEmpty) { menuItemHighlightState[listViewController.menuIndex] = true; } listViewController.hide(); @@ -375,11 +375,11 @@ class _BrnSelectionMenuWidgetState extends State { BrnSelectionUtil.currentSelectListForEntity(entity); List secondColumn = []; List thirdColumn = []; - if (firstColumn.length > 0) { + if (firstColumn.isNotEmpty) { for (BrnSelectionEntity firstEntity in firstColumn) { secondColumn .addAll(BrnSelectionUtil.currentSelectListForEntity(firstEntity)); - if (secondColumn.length > 0) { + if (secondColumn.isNotEmpty) { for (BrnSelectionEntity secondEntity in secondColumn) { thirdColumn.addAll( BrnSelectionUtil.currentSelectListForEntity(secondEntity)); @@ -388,7 +388,7 @@ class _BrnSelectionMenuWidgetState extends State { } } - if (firstColumn.length == 0 || firstColumn.length > 1) { + if (firstColumn.isEmpty || firstColumn.length > 1) { title = entity.title; } else { /// 第一列选中了一个,为【不限】类型,使用上一级别的名字展示。 @@ -401,7 +401,7 @@ class _BrnSelectionMenuWidgetState extends State { BrnSelectionFilterType.dateRangeCalendar) { title = _getDateAndRangeTitle(firstColumn, entity); } else { - if (secondColumn.length == 0 || secondColumn.length > 1) { + if (secondColumn.isEmpty || secondColumn.length > 1) { title = firstColumn[0].title; } else { /// 第二列选中了一个,为【不限】类型,使用上一级别的名字展示。 @@ -415,7 +415,7 @@ class _BrnSelectionMenuWidgetState extends State { BrnSelectionFilterType.dateRangeCalendar) { title = _getDateAndRangeTitle(secondColumn, firstColumn[0]); } else { - if (thirdColumn.length == 0 || thirdColumn.length > 1) { + if (thirdColumn.isEmpty || thirdColumn.length > 1) { title = secondColumn[0].title; } else { /// 第三列选中了一个,为【不限】类型,使用上一级别的名字展示。 @@ -525,7 +525,7 @@ class _BrnSelectionMenuWidgetState extends State { void _refreshSelectionMenuTitle(int index, BrnSelectionEntity entity) { if (entity.filterType == BrnSelectionFilterType.more) { - if (entity.allSelectedList().length > 0) { + if (entity.allSelectedList().isNotEmpty) { menuItemHighlightState[index] = true; } else { menuItemHighlightState[index] = false; @@ -536,7 +536,7 @@ class _BrnSelectionMenuWidgetState extends State { if (title != null) { titles[index] = title; } - if (entity.selectedListWithoutUnlimit().length > 0) { + if (entity.selectedListWithoutUnlimit().isNotEmpty) { menuItemHighlightState[index] = true; } else if (!BrunoTools.isEmpty(entity.customTitle)) { menuItemHighlightState[index] = entity.isCustomTitleHighLight; diff --git a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart index dddc1aa1..e2ac2a89 100644 --- a/lib/src/components/selection/widget/brn_selection_more_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_more_item_widget.dart @@ -143,9 +143,7 @@ class __FilterCommonTypeWidgetState extends State<_FilterCommonTypeWidget> { //标签的筛选条件 Visibility( visible: widget.selectionEntity - .currentShowTagByExpanded(isExpanded) - .length > - 0, + .currentShowTagByExpanded(isExpanded).isNotEmpty, child: Padding( padding: EdgeInsets.only(top: 12), child: _buildSelectionTag(), diff --git a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart index 0372558d..ae412365 100644 --- a/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_input_item_widget.dart @@ -4,8 +4,7 @@ import 'package:bruno/src/utils/brn_event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -typedef void OnRangeChangedFunction(String minInput, String maxInput); -typedef void OnFocusChangedFunction(bool focus); +typedef RangeChangedCallback = void Function(String minInput, String maxInput); /// 清空自定义范围输入框焦点的事件类 class ClearSelectionFocusEvent {} @@ -13,8 +12,8 @@ class ClearSelectionFocusEvent {} class BrnSelectionRangeItemWidget extends StatefulWidget { final BrnSelectionEntity item; - final OnRangeChangedFunction? onRangeChanged; - final OnFocusChangedFunction? onFocusChanged; + final RangeChangedCallback? onRangeChanged; + final ValueChanged? onFocusChanged; final bool isShouldClearText; diff --git a/lib/src/components/selection/widget/brn_selection_range_widget.dart b/lib/src/components/selection/widget/brn_selection_range_widget.dart index 22c1b0dc..3b7ec3c5 100644 --- a/lib/src/components/selection/widget/brn_selection_range_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_range_widget.dart @@ -19,8 +19,6 @@ import 'package:bruno/src/utils/brn_text_util.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef void BrnOnRangeSelectionBgClick(); - class BrnRangeSelectionGroupWidget extends StatefulWidget { static final double screenWidth = window.physicalSize.width / window.devicePixelRatio; @@ -28,7 +26,7 @@ class BrnRangeSelectionGroupWidget extends StatefulWidget { final BrnSelectionEntity entity; final double maxContentHeight; final bool showSelectedCount; - final BrnOnRangeSelectionBgClick? bgClickFunction; + final VoidCallback? bgClickFunction; final BrnOnRangeSelectionConfirm? onSelectionConfirm; final int? rowCount; @@ -253,7 +251,7 @@ class _BrnRangeSelectionGroupWidgetState widget.rowCount!; } - var tagContainer = (tagFilterList.length) > 0 + var tagContainer = tagFilterList.isNotEmpty ? Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 20), @@ -275,7 +273,7 @@ class _BrnRangeSelectionGroupWidgetState ) : Container(); - var content; + Widget? content; for (BrnSelectionEntity item in subFilterList) { if (item.filterType == BrnSelectionFilterType.range) { content = BrnSelectionRangeItemWidget( @@ -407,7 +405,7 @@ class _BrnRangeSelectionGroupWidgetState widget.entity.children[_tabController.index].children; List selectItems = subFilterList.where((f) => f.isSelected).toList(); - if (selectItems.length > 0) { + if (selectItems.isNotEmpty) { _firstList[_tabController.index].isSelected = true; } else { _firstList[_tabController.index].isSelected = false; @@ -595,7 +593,7 @@ class _BrnRangeSelectionGroupWidgetState f.isSelected) .toList(); - if (ranges.length > 0) { + if (ranges.isNotEmpty) { return ranges[0]; } return null; @@ -657,9 +655,7 @@ class _BrnRangeSelectionGroupWidgetState .where((_) => _.filterType == BrnSelectionFilterType.date || _.filterType == BrnSelectionFilterType.dateRangeCalendar) - .toList() - .length > - 0; + .toList().isNotEmpty; /// 查找第二层级 if (!hasCalendarItem) { diff --git a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart index 246900ac..8db3012a 100644 --- a/lib/src/components/selection/widget/brn_selection_single_list_widget.dart +++ b/lib/src/components/selection/widget/brn_selection_single_list_widget.dart @@ -43,7 +43,7 @@ class BrnSelectionSingleListWidget extends StatefulWidget { /// 当前 Items 所在的层级 currentListIndex = BrnSelectionUtil.getCurrentListIndex( - items.length > 0 ? items[0] : null); + items.isNotEmpty ? items[0] : null); _selectedItems = items.where((f) => f.isSelected).toList(); } @@ -153,7 +153,7 @@ class _BrnSelectionSingleListWidgetState /// Warning !!! /// (两列、三列时)第一列节点是否被选中取决于它的子节点是否被选中, /// 只有当它子节点被选中时才会认为第一列的节点相应被选中。 - if (widget.items.length > 0) { + if (widget.items.isNotEmpty) { widget.items[0].parent?.isSelected = (widget.items[0].parent?.children .where((BrnSelectionEntity f) => f.isSelected) .length ?? diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index 51b85212..1efe3253 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -149,7 +149,6 @@ class _SearchTextState extends State { @override void dispose() { - // TODO: implement dispose super.dispose(); tmpController?.dispose(); focusNode!.removeListener(_handleFocusNodeChangeListenerTick); diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index 810a2ce7..ad706fe6 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -37,7 +37,7 @@ class BrnBottomTabBar extends StatefulWidget { this.isAnimation = false, this.badgeColor, this.isInkResponse = false, - }) : assert(items.length >= 1), + }) : assert(items.isNotEmpty), assert( items.every((BrnBottomTabBarItem item) => item.title != null) == true, 'Every item must have a non-null title', @@ -92,8 +92,12 @@ class _BottomTabBarState extends State with TickerProviderState Tween(begin: 1.0, end: 1.5); void _resetState() { - for (AnimationController controller in _controllers) controller.dispose(); - for (_Circle circle in _circles) circle.dispose(); + for (AnimationController controller in _controllers) { + controller.dispose(); + } + for (_Circle circle in _circles) { + circle.dispose(); + } _circles.clear(); _controllers = @@ -129,8 +133,12 @@ class _BottomTabBarState extends State with TickerProviderState @override void dispose() { - for (AnimationController controller in _controllers) controller.dispose(); - for (_Circle circle in _circles) circle.dispose(); + for (AnimationController controller in _controllers) { + controller.dispose(); + } + for (_Circle circle in _circles) { + circle.dispose(); + } super.dispose(); } @@ -188,8 +196,9 @@ class _BottomTabBarState extends State with TickerProviderState _controllers[oldWidget.currentIndex].reverse(); _controllers[widget.currentIndex].forward(); } else { - if (_backgroundColor != widget.items[widget.currentIndex].backgroundColor) + if (_backgroundColor != widget.items[widget.currentIndex].backgroundColor) { _backgroundColor = widget.items[widget.currentIndex].backgroundColor; + } } } @@ -655,8 +664,9 @@ class _RadialPainter extends CustomPainter { if (textDirection != oldPainter.textDirection) return true; if (circles == oldPainter.circles) return false; if (circles.length != oldPainter.circles.length) return true; - for (int i = 0; i < circles.length; i += 1) + for (int i = 0; i < circles.length; i += 1) { if (circles[i] != oldPainter.circles[i]) return true; + } return false; } diff --git a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart index ed6219cf..af005ef2 100644 --- a/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart +++ b/lib/src/components/tabbar/indicator/brn_triangle_decoration.dart @@ -201,11 +201,6 @@ class _TriangleDecorationPainter extends BoxPainter { _path.reset(); } - @override - void dispose() { - super.dispose(); - } - @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(configuration.size != null); diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index a3185e7c..37a72a20 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -264,8 +264,9 @@ class BrnDeleteTagController { String result = _tags.removeAt(index); _asyncData(); return result; - } else + } else { return null; + } } /// 删除某个具体内容的标签,成功返回 true,失败返回 false diff --git a/lib/src/components/tag/tagview/brn_select_tag.dart b/lib/src/components/tag/tagview/brn_select_tag.dart index e1aba607..c55ee652 100644 --- a/lib/src/components/tag/tagview/brn_select_tag.dart +++ b/lib/src/components/tag/tagview/brn_select_tag.dart @@ -223,8 +223,9 @@ class _BrnSelectTagState extends State { void didUpdateWidget(BrnSelectTag oldWidget) { super.didUpdateWidget(oldWidget); // 如果两个数组不相等,重置选中状态 - if (!sameList(oldWidget.tags, widget.tags)) + if (!sameList(oldWidget.tags, widget.tags)) { _tagState = List.filled(widget.tags.length, false); + } } /// 比较两个数组内容是否一致,如果一致,返回 true,否则 false diff --git a/lib/src/utils/brn_tools.dart b/lib/src/utils/brn_tools.dart index a5d90958..332d318c 100644 --- a/lib/src/utils/brn_tools.dart +++ b/lib/src/utils/brn_tools.dart @@ -124,7 +124,7 @@ class BrunoTools { return obj.isEmpty; } if (obj is Map) { - return obj.length == 0; + return obj.isEmpty; } return obj == null; } diff --git a/pubspec.yaml b/pubspec.yaml index 6ed0939a..0553c37a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + lints: ^1.0.1 From e02257a8cd7ed612fb4889d9433eb96f686192f3 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Wed, 27 Apr 2022 16:39:22 +0800 Subject: [PATCH 12/19] sync documents (#197) --- .../BrnCommonActionSheet.md | 26 ++++---- .../BrnShareActionSheet.md | 4 +- .../appraise/BrnAppraise/BrnAppraise.md | 66 +++++++++---------- .../BrnBottomTabBar/BrnBottomTabBar.md | 3 - .../BrnProgressBarChart.md | 4 +- .../dialog/BrnShareDialog/BrnShareDialog.md | 2 +- .../BrnTextBlockInputFormItem.md | 4 +- .../BrnMultiSelectTagsPicker.md | 5 +- .../brn_selected_list_action_sheet.dart | 11 +++- 9 files changed, 62 insertions(+), 63 deletions(-) diff --git a/doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md b/doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md index 22d190f7..912ae432 100644 --- a/doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md +++ b/doc/components/actionsheet/BrnCommonActionSheet/BrnCommonActionSheet.md @@ -53,19 +53,19 @@ BrnCommonActionSheet({ ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | ------------------------- | -| actions | `List` | 用于存储每个选项的相关配置信息的列表(BrnActionItem 含有参数 title---选项标题文案(**必填**),desc----辅助信息文案,actionEleStyle----普通项或警示项,titleStyle---自定义主标题文本样式(覆盖 actionEleStyle)descStyle---自定义辅助信息文本样式(覆盖 actionEleStyle)) | 是 | 空 | -| title | String? | 列表标题的文案 | 否 | 空 | -| titleWidget | Widget? | 列表标题区域自定义 Widget | 否 | 空 | -| cancelTitle | String? | 取消按钮的文案 | 否 | ''取消'' | -| maxTitleLines | Int | 列表标题文案最大行数 | 否 | 2 | -| onItemClickInterceptor | BrnCommonActionSheetItemClickInterceptor? =void( int index, BrnCommonActionSheetItem actionItem)? | **返回值为 bool**,返回值用于判断是否拦截点击事件,如果为**true**将拦截,用户点击将**不会触发 clickCallBack**,当前 actionSheet 也**不会消失**。如果为**false**,则不会造成任何影响,只是提前拦截了一下点击事件。 | 否 | 空 | -| clickCallBack(默认回调后会执行 pop 操作,如过不想 pop,请使用 onItemClickInterceptor) | BrnCommonActionSheetItemClickCallBack?=void ( int index, BrnCommonActionSheetItem actionItem)? | **返回值为 void**,点击后回调方法(方法传参为被点击的按钮的**index**及相关配置信息**BrnActionItem**),使用者**根据参数自行配置响应动作**。 | 是 | 空 | -| spaceColor | Color | “取消”按钮上方间隔颜色 | 否 | **Color(0xfff8f8f8)**浅灰 | -| separatorLineColor | Color? | 分割线颜色 | 否 | **Color(0xfff0f0f0)**浅灰 | -| maxSheetHeight | double | 列表最大高度限制 | 否 | 默认为0 | -| themeData | BrnActionSheetConfig? | ActionSheet 主题配置类,支持配置字段详见 BrnActionSheetConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------------------------------------------------ | ----------------------------------------- | ------------------------------------------------------------ | ------------ | ------------------------- | +| actions | `List` | 用于存储每个选项的相关配置信息的列表(BrnActionItem 含有参数 title---选项标题文案(**必填**),desc----辅助信息文案,actionEleStyle----普通项或警示项,titleStyle---自定义主标题文本样式(覆盖 actionEleStyle)descStyle---自定义辅助信息文本样式(覆盖 actionEleStyle)) | 是 | 空 | +| title | String? | 列表标题的文案 | 否 | 空 | +| titleWidget | Widget? | 列表标题区域自定义 Widget | 否 | 空 | +| cancelTitle | String? | 取消按钮的文案 | 否 | ''取消'' | +| maxTitleLines | Int | 列表标题文案最大行数 | 否 | 2 | +| onItemClickInterceptor | BrnCommonActionSheetItemClickInterceptor? | **返回值为 bool**,返回值用于判断是否拦截点击事件,如果为**true**将拦截,用户点击将**不会触发 clickCallBack**,当前 actionSheet 也**不会消失**。如果为**false**,则不会造成任何影响,只是提前拦截了一下点击事件。 | 否 | 空 | +| clickCallBack(默认回调后会执行 pop 操作,如过不想 pop,请使用 onItemClickInterceptor) | BrnCommonActionSheetItemClickCallBack? | **返回值为 void**,点击后回调方法(方法传参为被点击的按钮的**index**及相关配置信息**BrnActionItem**),使用者**根据参数自行配置响应动作**。 | 是 | 空 | +| spaceColor | Color | “取消”按钮上方间隔颜色 | 否 | **Color(0xfff8f8f8)**浅灰 | +| separatorLineColor | Color? | 分割线颜色 | 否 | **Color(0xfff0f0f0)**浅灰 | +| maxSheetHeight | double | 列表最大高度限制 | 否 | 默认为0 | +| themeData | BrnActionSheetConfig? | ActionSheet 主题配置类,支持配置字段详见 BrnActionSheetConfig | 否 | | ## 四、代码演示 diff --git a/doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md b/doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md index f37fef55..bf925199 100644 --- a/doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md +++ b/doc/components/actionsheet/BrnShareActionSheet/BrnShareActionSheet.md @@ -72,12 +72,12 @@ BrnShareActionSheet({ | firstShareChannels | `List?` | 第一行渠道列表 | 否 | 空 | | secondShareChannels | `List?` | 第二行渠道列表 | 否 | | | mainTitle | String? | 列表标题 | 否 | | -| clickCallBack | BrnShareActionSheetItemClickCallBack=void ( int section, int index, BrnShareItem shareItem)? | 点击分享渠道图标后回调方法 | 否 | 空 | +| clickCallBack | BrnShareActionSheetItemClickCallBack? | 点击分享渠道图标后回调方法 | 否 | 空 | | cancelTitle | String? | 取消按钮的文案 | 否 | ''取消'' | | context | BuildContext | BuidContext | 是 | 空 | | shareTextColor | Color | 分享渠道文案颜色 | 否 | Color(0xff999999)灰色 | | textColor | Color | 选项标题颜色 | 否 | Color(0xff222222)黑色 | -| clickInterceptor | BrnShareActionSheetOnItemClickInterceptor? = void (int section, int index, BrnShareItem shareItem)? | 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true | 否 | | +| clickInterceptor | BrnShareActionSheetOnItemClickInterceptor? | 是否可点击(如果为预设类型,设置为不可点击后会变为相应的置灰图标)默认为true | 否 | | ### 其他数据 diff --git a/doc/components/appraise/BrnAppraise/BrnAppraise.md b/doc/components/appraise/BrnAppraise/BrnAppraise.md index c0ad9aa4..68381da8 100644 --- a/doc/components/appraise/BrnAppraise/BrnAppraise.md +++ b/doc/components/appraise/BrnAppraise/BrnAppraise.md @@ -92,44 +92,44 @@ BrnAppraise( ### 参数说明 -| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | -| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | -------------------------------------- | -| title | String | 标题 | 否 | '' | -| headerType | BrnAppraiseHeaderType | 标题类型,居中还是两侧 | 否 | BrnAppraiseHeaderType.spaceBetween | -| type | BrnAppraiseType | 评价组件类型,表情包还是五角星 | 否 | BrnAppraiseType.Star | -| iconDescriptions | `List` | 点击表情时对应等级的提示文案。若 `type=BrnAppraiseType.Emoji`,则 list 长度为 5,不足 5 个时请在对应位置补空字符串。若 `type=BrnAppraiseType.Star`,list 长度不能比传入的 BrnAppraiseConfig 中的 count 小。 | 否 | ['不好','还行','满意','很棒','超惊喜'] | -| tags | `List?` | 供选择的标签数据 | 否 | 无 | -| inputHintText | String | 输入框的提示文字 | 否 | '' | -| onConfirm | `void Function(int index, List selectedTags, String input)?` | 点击提交时的回调,其中 index 是选中的表情或者五角星的 index,selectedTags 是选中的标签,input 是输入框的内容 | 否 | 无 | -| config | BrnAppraiseConfig | 配置类,具体见下边其他参数说明 | 否 | BrnAppraiseConfig() | +| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | +| ---------------- | ------------------------ | ------------------------------------------------------------ | ------------ | -------------------------------------- | +| title | String | 标题 | 否 | '' | +| headerType | BrnAppraiseHeaderType | 标题类型,居中还是两侧 | 否 | BrnAppraiseHeaderType.spaceBetween | +| type | BrnAppraiseType | 评价组件类型,表情包还是五角星 | 否 | BrnAppraiseType.Star | +| iconDescriptions | `List` | 点击表情时对应等级的提示文案。若 `type=BrnAppraiseType.Emoji`,则 list 长度为 5,不足 5 个时请在对应位置补空字符串。若 `type=BrnAppraiseType.Star`,list 长度不能比传入的 BrnAppraiseConfig 中的 count 小。 | 否 | ['不好','还行','满意','很棒','超惊喜'] | +| tags | `List?` | 供选择的标签数据 | 否 | 无 | +| inputHintText | String | 输入框的提示文字 | 否 | '' | +| onConfirm | BrnAppraiseConfirmClick? | 点击提交时的回调,其中 index 是选中的表情或者五角星的 index,selectedTags 是选中的标签,input 是输入框的内容 | 否 | 无 | +| config | BrnAppraiseConfig | 配置类,具体见下边其他参数说明 | 否 | BrnAppraiseConfig() | ### 其他参数说明 #### BrnAppraiseConfig -| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | -| ----------------------- | ------------------------------------------- | ------------------------------------------------------------ | ------------ | ------------------------------------------------------------ | -| showHeader | bool | 是否显示顶部标题和关闭按钮的 header 视图 | 否 | true | -| headerPadding | EdgeInsets? | header 部分的 padding,只有居中样式支持设置 | 否 | `headerType=BrnAppraiseHeader.center`时,为 `EdgeInsets.only(top: 20, bottom: 20)`,其余为 `EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20)` | -| titleMaxLines | int | 标题的最大行数 | 否 | 1 | -| onCancel | `void Function(BuildContext context)?` | 点击关闭按钮时的回调 | 否 | 无 | -| count | int | `type=BrnAppraiseType.Star`时所需五角星的个数 | 否 | 5 | -| iconDescriptions | `List` | 点击表情时的文案。`type=BrnAppraiseType.Star`时,该列表的数据个数不能比 count 少。`type=BrnAppraiseType.Emoji`时,list 长度应为 5,不足 5 个时请在对应位置补空字符串 | 否 | ['不好', '还行', '满意', '很棒', '超惊喜'] | -| indexes | `List` | 表情包打分组件所需表情的 index | 否 | [0,1,2,3,4] | -| starAppraiseHint | String | 五角星未打分时的提示文案 | 否 | '' | -| multiSelect | bool | 标签是否支持多选 | 否 | true | -| tagCountEachRow | int | 每行显示的标签数 | 否 | 2 | -| showTextInput | bool | 是否显示输入框 | 否 | true | -| maxLength | int | 输入框能输入文字的最大长度 | 否 | 100 | -| maxHintLines | int | 提示文案的最大行数 | 否 | 1 | -| inputDefaultText | String? | 输入框默认文案 | 否 | 无 | -| inputMaxHeight | double | 输入框的最大高度 | 否 | 120 | -| showConfirmButton | bool | 是否显示提交按钮 | 否 | true | -| confirmButtonText | String | 提交按钮自定义文案 | 否 | '提交' | -| isConfirmButtonEnabled | bool | 提交按钮的可用状态 | 否 | 默认 null,在打分之后 enable | -| iconClickCallback | `void Function(int index)?` | 点击打分时的回调 | 否 | 无 | -| inputTextChangeCallback | `void Function(String input)?` | 输入框内容改变的回调 | 否 | 无 | -| tagSelectCallback | `void Function(List selectedTags)?` | 选择标签时的回调 | 否 | 无 | +| **参数名** | **参数类型** | **作用** | **是否必填** | **默认值** | +| ----------------------- | ------------------------------ | ------------------------------------------------------------ | ------------ | ------------------------------------------------------------ | +| showHeader | bool | 是否显示顶部标题和关闭按钮的 header 视图 | 否 | true | +| headerPadding | EdgeInsets? | header 部分的 padding,只有居中样式支持设置 | 否 | `headerType=BrnAppraiseHeader.center`时,为 `EdgeInsets.only(top: 20, bottom: 20)`,其余为 `EdgeInsets.only(left: 20, top: 16, right: 16, bottom: 20)` | +| titleMaxLines | int | 标题的最大行数 | 否 | 1 | +| onCancel | BrnAppraiseCloseClickCallBack? | 点击关闭按钮时的回调 | 否 | 无 | +| count | int | `type=BrnAppraiseType.Star`时所需五角星的个数 | 否 | 5 | +| iconDescriptions | `List` | 点击表情时的文案。`type=BrnAppraiseType.Star`时,该列表的数据个数不能比 count 少。`type=BrnAppraiseType.Emoji`时,list 长度应为 5,不足 5 个时请在对应位置补空字符串 | 否 | ['不好', '还行', '满意', '很棒', '超惊喜'] | +| indexes | `List` | 表情包打分组件所需表情的 index | 否 | [0,1,2,3,4] | +| starAppraiseHint | String | 五角星未打分时的提示文案 | 否 | '' | +| multiSelect | bool | 标签是否支持多选 | 否 | true | +| tagCountEachRow | int | 每行显示的标签数 | 否 | 2 | +| showTextInput | bool | 是否显示输入框 | 否 | true | +| maxLength | int | 输入框能输入文字的最大长度 | 否 | 100 | +| maxHintLines | int | 提示文案的最大行数 | 否 | 1 | +| inputDefaultText | String? | 输入框默认文案 | 否 | 无 | +| inputMaxHeight | double | 输入框的最大高度 | 否 | 120 | +| showConfirmButton | bool | 是否显示提交按钮 | 否 | true | +| confirmButtonText | String | 提交按钮自定义文案 | 否 | '提交' | +| isConfirmButtonEnabled | bool | 提交按钮的可用状态 | 否 | 默认 null,在打分之后 enable | +| iconClickCallback | BrnAppraiseIconClick? | 点击打分时的回调 | 否 | 无 | +| inputTextChangeCallback | BrnInputTextChangeCallback? | 输入框内容改变的回调 | 否 | 无 | +| tagSelectCallback | BrnAppraiseTagClick? | 选择标签时的回调 | 否 | 无 | ```dart const BrnAppraiseConfig({ diff --git a/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md b/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md index 3e8deced..6171d737 100644 --- a/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md +++ b/doc/components/bottomTabBar/BrnBottomTabBar/BrnBottomTabBar.md @@ -41,9 +41,6 @@ BrnBottomTabBar({ 'Every item must have a non-null title', ), assert(0 <= currentIndex && currentIndex < items.length), - type = items.length <= 3 - ? BrnBottomTabBarDisplayType.fixed - : BrnBottomTabBarDisplayType.shifting, super(key: key); ``` diff --git a/doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md b/doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md index ac64e1c4..ff8c9880 100644 --- a/doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md +++ b/doc/components/charts/BrnProgressBarChart/BrnProgressBarChart.md @@ -73,8 +73,8 @@ BrnProgressBarChart( | barMaxValue | double | 柱状图最大值 | 否 | 0 | | selectedHintTextColor | Color | 选中柱状图提示文案文本颜色 | 否 | Colors.white | | selectedHintTextBackgroundColor | Color | 选中柱状图提示文案文本背景颜色 | 否 | Colors.black | -| barChartSelectCallback | void Function(BarItem barItem) | 选中柱状图时候的回调 | 否 | | -| onBarItemClickInterceptor | bool OnBarItemClickInterceptor(int barBundleIndex, BarBundle barBundle, int barGroupIndex, BarItem barItem) | 柱状图是否可点击回调 | 否 | | +| barChartSelectCallback | BrnProgressBarChartSelectCallback | 选中柱状图时候的回调 | 否 | | +| onBarItemClickInterceptor | OnBarItemClickInterceptor | 柱状图是否可点击回调 | 否 | | ## 四、代码演示 diff --git a/doc/components/dialog/BrnShareDialog/BrnShareDialog.md b/doc/components/dialog/BrnShareDialog/BrnShareDialog.md index 59109a4d..92d831f2 100644 --- a/doc/components/dialog/BrnShareDialog/BrnShareDialog.md +++ b/doc/components/dialog/BrnShareDialog/BrnShareDialog.md @@ -69,7 +69,7 @@ BrnShareDialog({ | descText | String? | 弹框辅助信息文案(为空则**不显示**辅助信息) | 否 | 无 | | separatorText | String? | 文案与分享渠道图标间的分割线内嵌文案 | 否 | 你可以通过以下方式分享给客户 | | shareChannels | `List` | 用于表示所展示的分享渠道图标的索引(列表内容可直接填写渠道对应的**int**值,或使用**BrnShareItemConstants**的静态变量,例如**BrnShareItemConstants.SHARE\_WEIXIN**)。自定义为100或**BrnShareItemConstants.SHARE\_CUSTOM**。 | 是 | 空 | -| clickCallBack | BrnShareDialogItemClickCallBack(int shareChannel, int customIndex) | 点击分享渠道图标后回调方法(方法传参为被点击的分享渠道图标在**BrnShareItemConstants**中的索引值shareChannel, 及改列表在使用者自定义的*shareChannels*中的索引值customIndex),使用者**根据参数自行配置响应动作**。 | 否 | 空 | +| clickCallBack | BrnShareDialogItemClickCallBack? | 点击分享渠道图标后回调方法(方法传参为被点击的分享渠道图标在**BrnShareItemConstants**中的索引值shareChannel, 及改列表在使用者自定义的*shareChannels*中的索引值customIndex),使用者**根据参数自行配置响应动作**。 | 否 | 空 | | getCustomChannelTitle | BrnShareDialogGetCustomShareItemTitle? | 获取自定义分享渠道对应的显示**文案**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**String**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | | getCustomChannelWidget | BrnShareDialogGetCustomShareItemIcon? | 获取自定义分享渠道对应的显示**图标**(方法传参为该自定义分享渠道在*shareChannels*中的索引值index)。回调返回值为**Widget**,如果返回值为空,则**不显示**该自定义分享渠道。 | 否 | 空 | | context | BuildContext | BuildContext | 是 | 空 | diff --git a/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md b/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md index 82dc179d..76c4cc95 100644 --- a/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md +++ b/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md @@ -95,8 +95,8 @@ BrnTextBlockInputFormItem( | inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | | onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | | controller | TextEditingController? | 文本输入controller | 否 | 无 | | -| minLines | int | 最小行数 | 否 | 4 | | -| maxLines | int | 最大行数 | 否 | 20 | | +| minLines | int? | 最小行数 | 否 | 4 | | +| maxLines | int? | 最大行数 | 否 | 20 | | | themeData | BrnFormItemConfig? | 表单主题配置 | 否 | 无 | | ### 其他数据说明 diff --git a/doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md b/doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md index fc7b58ef..096109b7 100644 --- a/doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md +++ b/doc/components/picker/BrnMultiSelectTagsPicker/BrnMultiSelectTagsPicker.md @@ -90,10 +90,7 @@ class BrnTagsPickerConfig { this.tagBackgroudColor, this.selectedTagBackgroudColor, this.chipPadding, - this.tagItemSource = const []}) { - this.tagTitleColor = - BrnThemeConfigurator.instance.getConfig().commonConfig.colorTextBase; - } + this.tagItemSource = const []}); ///tag 文字大小 double tagTitleFontSize; diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index 1d186a2c..62a877e8 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -6,6 +6,11 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; +typedef BrnItemTitleBuilder = dynamic Function(int index, T entity); +typedef BrnItemDeleteCallback = bool Function(int deleteIdx, T deleteEntity); +typedef BrnListDismissCallback = void Function(bool isClosedByClearButton); + + /// 监听数据刷新和列表关闭操作 class BrnSelectedListActionSheetController extends ChangeNotifier { /// 是否刷新数据 @@ -50,7 +55,7 @@ class BrnSelectedListActionSheet { final List items; /// 获取对应 index 行内容的回调。类型必须为 String 或者自定义的 widget.自定义 widget 时,左边的 icon 会自动隐藏,自定义widget填充整行。 - final dynamic Function(int index, T entity) itemTitleBuilder; + final BrnItemTitleBuilder itemTitleBuilder; /// 控制视图隐藏/刷新列表等方法 final BrnSelectedListActionSheetController? controller; @@ -95,13 +100,13 @@ class BrnSelectedListActionSheet { final VoidCallback? onClearCanceled; /// 每一行删除按钮的点击回调。返回值:是否要删除该 entity,如果该 handler 没有实现或者返回 true,则删除 - final bool Function(int deleteIdx, T deleteEntity)? onItemDelete; + final BrnItemDeleteCallback? onItemDelete; /// 视图显示时的回调 final VoidCallback? onListShowed; /// 视图隐藏时的回调,会把是否是清空按钮触发的销毁视图回传 - final void Function(bool isClosedByClearButton)? onListDismissed; + final BrnListDismissCallback? onListDismissed; OverlayEntry? _overlayEntry; double? _leftOffset; From 45753cd5695865d1b1f95b1defd714ad96e0a28c Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 29 Apr 2022 10:27:57 +0800 Subject: [PATCH 13/19] sync the optimization of components. (#196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: radio and checkbox, add `crossAxisAlignment` param. * perf: `BrnMiddleInputDialog` support `themeData`. * perf: `BrnMiddleInputDialog` support `themeData`. * perf: `BrnTextButtonPanel` 优化 button 展示,修复某些情况下无法充满空间的问题。 * perf: `BrnCommonCardTitle`,增加 `titleMaxLines`、`titleOverflow` 参数 * perf: `BrnCommonCardTitle`,增加 `titleMaxLines`、`titleOverflow` 参数 * perf: `BrnMultiSelectDialog` 使用 BrnDialogConfig 默认配置。 * perf: `BrnScrollableTextDialog` 优化ScrollBar 展示位置。 * perf: `BrnScrollableTextDialog` 增加 `close` Icon 点击回调。 * perf: `BrnSelectionView` 优化【更多】筛选页的数据展示,最大支持展示 2 行。 * perf: 优化表单项啊,支持 自动 `autoFocus`参数。 * perf: `BrnAppBar` 主题定制支持 `showDefaultBottom` 参数,用于控制 AppBar 底部分割线。 * perf: `BrnAppBar` 主题定制支持 `showDefaultBottom` 参数,用于控制 AppBar 底部分割线。 * perf: `BrnMultiDataPicker` 支持默认 Delegate 构造数据,更易使用。 * perf: `BrnStepInputFormItem` 递增、减组件支持手动输入。 * perf: `BrnPairInfoTable` 增加 展开收起状态变化的回调。 * perf: `BrnSearchText` 搜索增加部分控制参数。 * perf: `BrnAnchorTab` 支持内容动态变化的情况。 * perf: `BrnProgressBarChart` 支持 `barChartStyle = BarChartStyle.vertical` chart 水平展示时,x 轴刻度文字倾斜展示、item 的点击回调。 * perf: `BrnStepInputFormItem` 递增、减组件支持手动输入。 * perf: 对 example test 目录 lint 检查,优化 Demo 首页卡顿问题。 * perf: `BrnPairInfoTable` 增加 展开收起状态变化的回调。 * perf: const SizedBox.shrink() * perf: `BrnScrollableTextDialog` 优化ScrollBar 展示位置。 --- analysis_options.yaml | 2 - .../checkbox/BrnCheckbox/BrnCheckbox.md | 2 + .../BrnMiddleInputDialog.md | 5 +- .../BrnSingleSelectDialog.md | 32 +-- .../BrnStepInputFormItem.md | 4 + .../BrnTextBlockInputFormItem.md | 2 + .../BrnTextInputFormItem.md | 2 + .../BrnTitleSelectInputFormItem.md | 2 + .../radio/BrnRadioButton/BrnRadioButton.md | 2 + .../search/BrnSearchText/BrnSearchText.md | 4 + .../text/BrnPairInfoTable/BrnPairInfoTable.md | 4 +- .../BrnCommonCardTitle/BrnCommonCardTitle.md | 28 ++- .../charts/progress_bar_chart_example.dart | 202 ++++++++--------- .../form/all_item_style_example.dart | 2 +- .../items_example/step_input_example.dart | 40 +++- .../picker/multi_picker_example.dart | 31 +++ .../scroll_actor_tab_example.dart | 20 +- example/lib/sample/home/group_card.dart | 7 +- example/lib/sample/home/list_item.dart | 5 +- .../appraise/brn_appraise_header.dart | 2 +- .../collection/brn_bottom_button_panel.dart | 4 +- .../collection/brn_text_button_panel.dart | 23 +- .../calendar/brn_calendar_view.dart | 2 +- .../content_card/brn_pair_info_table.dart | 20 +- .../card_title/brn_action_card_title.dart | 2 +- .../card_title/brn_common_card_title.dart | 13 +- .../brn_progress_bar_chart.dart | 63 +++++- .../brn_progress_bar_chart_painter.dart | 140 ++++++++++-- .../dialog/brn_middle_input_diaolg.dart | 45 +++- .../dialog/brn_multi_select_dialog.dart | 9 +- .../dialog/brn_scrollable_text_dialog.dart | 26 ++- .../components/dialog/brn_single_select.dart | 19 +- .../general/brn_quick_select_input_item.dart | 2 +- .../items/general/brn_step_input_item.dart | 206 ++++++++++++------ .../general/brn_text_block_input_item.dart | 5 + .../items/general/brn_text_input_item.dart | 5 + .../general/brn_title_select_input_item.dart | 5 + lib/src/components/navbar/brn_appbar.dart | 20 +- .../components/picker/brn_multi_picker.dart | 169 +++++++++++--- lib/src/components/radio/brn_checkbox.dart | 6 + .../components/radio/brn_radio_button.dart | 6 + lib/src/components/radio/brn_radio_core.dart | 6 + .../scroll_anchor/brn_scroll_anchor_tab.dart | 183 ++++++++-------- .../bean/brn_selection_common_entity.dart | 6 +- .../selection/brn_more_selection.dart | 6 +- .../widget/brn_layer_more_selection_page.dart | 7 +- .../components/sugsearch/brn_search_text.dart | 20 +- .../tag/tagview/brn_delete_tag.dart | 2 +- .../theme/base/brn_default_config_utils.dart | 1 + lib/src/theme/configs/brn_appbar_config.dart | 14 ++ 50 files changed, 1002 insertions(+), 431 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 7ee5ce4d..80f2c75c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,5 +4,3 @@ include: package:lints/core.yaml analyzer: exclude: - doc/** - - example/** - - test/** \ No newline at end of file diff --git a/doc/components/checkbox/BrnCheckbox/BrnCheckbox.md b/doc/components/checkbox/BrnCheckbox/BrnCheckbox.md index e9699d85..5162b770 100644 --- a/doc/components/checkbox/BrnCheckbox/BrnCheckbox.md +++ b/doc/components/checkbox/BrnCheckbox/BrnCheckbox.md @@ -39,6 +39,7 @@ const BrnCheckbox({ this.child, this.childOnRight = true, this.mainAxisAlignment = MainAxisAlignment.start, + this.crossAxisAlignment = CrossAxisAlignment.center, this.mainAxisSize = MainAxisSize.min, }); ``` @@ -54,6 +55,7 @@ const BrnCheckbox({ | iconPadding | EdgeInsets | 选择图标的padding | 否 | EdgeInsets.all(5) | | childOnRight | bool | widget在是否在选择 icon 的右边,false 就在左边 | 否 | true | | mainAxisAlignment | MainAxisAlignment | child 视图和 icon 在row布局里面的alignment | 否 | MainAxisAlignment.start | +| crossAxisAlignment | CrossAxisAlignment | child 视图和 icon 在row布局里面的CrossAlignment | 否 | CrossAxisAlignment.center | | mainAxisSize | MainAxisSize | child 视图和 icon 在row布局里面的mainAxisSize | 否 | MainAxisSize.min | ## 四、代码演示 diff --git a/doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md b/doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md index 9dd40a66..3d8cabca 100644 --- a/doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md +++ b/doc/components/dialog/BrnMiddleInputDialog/BrnMiddleInputDialog.md @@ -41,7 +41,8 @@ const BrnMiddleInputDialog( this.onCancel, this.dismissOnActionsTap = true, this.barrierDismissible = true, - this.autoFocus = false}); + this.autoFocus = false, + this.themeData,}); ``` ### 参数说明 @@ -64,7 +65,7 @@ const BrnMiddleInputDialog( | dismissOnActionsTap | bool | 点击取消/确认按钮之后,是否自动关闭弹窗 | 否 | true | | barrierDismissible | bool | 点击蒙层背景,弹窗是否可关闭。 | 否 | true | | autoFocus | bool | 是否自动获取焦点,弹出键盘 | 否 | false | - +| themeData | BrnDialogConfig | 主题定制配置 | 否 | defaultDialogConfig | ## 四、效果及代码展示 diff --git a/doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md b/doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md index f5212325..5b6bfcca 100644 --- a/doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md +++ b/doc/components/dialog/BrnSingleSelectDialog/BrnSingleSelectDialog.md @@ -36,27 +36,29 @@ const BrnSingleSelectDialog( this.onItemClick, this.checkedItem, this.customWidget, + this.onCloseClick, this.canDismissOnConfirmClick = true, this.isCustomFollowScroll = true}); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ------------------------ | ----------------------------------- | --------------------------------------------------------- | ------------ | ---------- | -| isClose | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | -| title | String | 弹窗标题名称 | 否 | "" | -| messageText | String? | 描述文案,优先级较 messageWidget 低,优先使用 messageWidget | 否 | | -| messageWidget | Widget? | 描述 Widget | 否 | | -| conditions | List | 备选项数组 | 否 | | -| checkedItem | String | 选中的选项名称 | 否 | | -| submitText | String | 确定/提交 按钮文案 | 否 | | -| submitBgColor | Color | 提交按钮背景颜色 | 否 | | -| customWidget | Widget | 在单选列表底部自定义 Widget | 否 | null | -| isCustomFollowScroll | bool | 内容是否可滑动 | 否 | true | -| canDismissOnConfirmClick | bool | 是否在点击时让 Diallog 消失 | 否 | true | -| onSubmitClick | BrnSingleSelectOnSubmitCallback? | 提交按钮点击的回调 | 否 | | -| onItemClick | BrnSingleSelectOnItemClickCallback? | item 的点击回调 | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ------------------------ | ----------------------------------- | ----------------------------------------------------------- | ------------ | ---------- | +| isClose | bool | 用于控制弹窗是否相应电机外部关闭,true 关闭,false 不关闭 | 否 | true | +| title | String | 弹窗标题名称 | 否 | "" | +| messageText | String? | 描述文案,优先级较 messageWidget 低,优先使用 messageWidget | 否 | | +| messageWidget | Widget? | 描述 Widget | 否 | | +| conditions | List | 备选项数组 | 否 | | +| checkedItem | String | 选中的选项名称 | 否 | | +| submitText | String | 确定/提交 按钮文案 | 否 | | +| submitBgColor | Color | 提交按钮背景颜色 | 否 | | +| customWidget | Widget | 在单选列表底部自定义 Widget | 否 | null | +| onCloseClick | VoidCallback | 点击关闭 icon 的回调 | 否 | null | +| isCustomFollowScroll | bool | 内容是否可滑动 | 否 | true | +| canDismissOnConfirmClick | bool | 是否在点击时让 Diallog 消失 | 否 | true | +| onSubmitClick | BrnSingleSelectOnSubmitCallback? | 提交按钮点击的回调 | 否 | | +| onItemClick | BrnSingleSelectOnItemClickCallback? | item 的点击回调 | 否 | | ## 三、代码演示 diff --git a/doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md b/doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md index 8391b38b..7c577163 100644 --- a/doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md +++ b/doc/components/form/BrnStepInputFormItem/BrnStepInputFormItem.md @@ -53,6 +53,8 @@ BrnStepInputFormItem({ this.maxLimit = 10, this.minLimit = 0, this.onChanged, + this.canManualInput = false, + this.controller, this.themeData, }) : assert(value == null || value >= minLimit && value <= maxLimit), super(key: key) { @@ -84,6 +86,8 @@ BrnStepInputFormItem({ | maxLimit | int | 单步上限值 | 否 | 10 | | | minLimit | int | 单步下限值 | 否 | 0 | | | onChanged | OnBrnFormValueChanged? | 递增值变化回调 | 否 | 无 | | +| canManualInput | bool | 是否可手动输入 | 否 | false | | +| controller | TextEditingController? | 输入框控制器 | 否 | 无 | | | themeData | BrnFormItemConfig? | form配置 | 否 | 无 | | ### 其他数据说明: diff --git a/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md b/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md index 76c4cc95..9433bbb8 100644 --- a/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md +++ b/doc/components/form/BrnTextBlockInputFormItem/BrnTextBlockInputFormItem.md @@ -58,6 +58,7 @@ BrnTextBlockInputFormItem( this.onChanged, this.hint = "请输入", this.maxCharCount, + this.autofocus: false, this.inputType, this.inputFormatters, this.controller, @@ -91,6 +92,7 @@ BrnTextBlockInputFormItem( | onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | | hint | String | 录入项 hint 提示 | 否 | "请输入" | | | maxCharCount | int? | 最大输入字符数 | 否 | 无 | | +| autofocus | bool | 是否自动获取焦点 | 否 | false | | | inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | | inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | | onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | diff --git a/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md b/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md index 348eba16..0bee0186 100644 --- a/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md +++ b/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md @@ -59,6 +59,7 @@ BrnTextInputFormItem({ this.hint = "请输入", this.unit, this.maxCharCount, + this.autofocus: false, this.inputType, this.inputFormatters, this.onChanged, @@ -93,6 +94,7 @@ BrnTextInputFormItem({ | hint | String | 录入项 hint 提示 | 否 | "请输入" | | | unit | String? | 单位 | 否 | 无 | | | maxCharCount | int? | 最大输入字符数 | 否 | 无 | | +| autofocus | bool | 是否自动获取焦点 | 否 | false | | | inputType | String? | 输入内容类型,指定键盘类型,参见 `BrnInputType` | 否 | 无 | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | | inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | | onChanged | `ValueChanged?` | 输入文案回调 | 否 | 无 | | diff --git a/doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md b/doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md index b798f568..cfd9ceff 100644 --- a/doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md +++ b/doc/components/form/BrnTitleSelectInputFormItem/BrnTitleSelectInputFormItem.md @@ -58,6 +58,7 @@ BrnTitleSelectInputFormItem( this.inputType = BrnInputType.TEXT, this.selectedIndex = -1, this.inputFormatters, + this.autofocus: false, this.onChanged, this.onTitleSelected, this.controller, @@ -92,6 +93,7 @@ this.themeData = BrnThemeConfigurator.instance | maxCount | int? | 最大输入字符数 | 否 | 无 | | | inputType | String | 指定键盘类型 | 否 | BrnInputType.TEXT | 详见**BrnInputType**类,注意:无法通过指定键盘类型确保输入。比如不能通过指定数字键盘确保用户只输入数字。如果有要求用户只输入特定字符的需求请使用**inputFormatters**参数 | | inputFormatters | `List?` | 指定对输入数据的格式化要求 | 否 | 无 | | +| autofocus | bool | 是否自动获取焦点 | 否 | false | | | onChanged | `ValueChanged?` | 输入文本变化回调 | 否 | 无 | | | controller | TextEditingController? | 文本输入controller | 否 | 无 | | | selectedIndex | int | 当前Title选中索引 | 否 | -1 | | diff --git a/doc/components/radio/BrnRadioButton/BrnRadioButton.md b/doc/components/radio/BrnRadioButton/BrnRadioButton.md index 545cb373..624c4243 100644 --- a/doc/components/radio/BrnRadioButton/BrnRadioButton.md +++ b/doc/components/radio/BrnRadioButton/BrnRadioButton.md @@ -39,6 +39,7 @@ const BrnRadioButton( this.child, this.childOnRight = true, this.mainAxisAlignment = MainAxisAlignment.start, + this.crossAxisAlignment = CrossAxisAlignment.center, this.mainAxisSize = MainAxisSize.min, this.behavior = HitTestBehavior.translucent}); ``` @@ -54,6 +55,7 @@ const BrnRadioButton( | iconPadding | EdgeInsets? | 选择图标的padding | 否 | EdgeInsets.all(5) | | childOnRight | bool | widget在是否在选择 icon 的右边,false 就在左边 | 否 | true | | mainAxisAlignment | MainAxisAlignment | child 视图和 icon 在row布局里面的alignment | 否 | MainAxisAlignment.start | +| crossAxisAlignment | CrossAxisAlignment | child 视图和 icon 在row布局里面的CrossAlignment | 否 | CrossAxisAlignment.center | | mainAxisSize | MainAxisSize | child 视图和 icon 在row布局里面的mainAxisSize | 否 | MainAxisSize.min | | behavior | HitTestBehavior | 默认值HitTestBehavior.translucent,控制widget.onRadioItemClick触发的点击范围 | 否 | HitTestBehavior.translucent | diff --git a/doc/components/search/BrnSearchText/BrnSearchText.md b/doc/components/search/BrnSearchText/BrnSearchText.md index ad21dc85..2f703706 100644 --- a/doc/components/search/BrnSearchText/BrnSearchText.md +++ b/doc/components/search/BrnSearchText/BrnSearchText.md @@ -62,6 +62,8 @@ const BrnSearchText({ this.focusNode, this.autoFocus = false, this.textInputAction, + this.inputFormatters, + this.textInputType, }) : super(key: key); ``` @@ -93,6 +95,8 @@ const BrnSearchText({ | focusNode | FocusNode? | 管理焦点 | 否 | 无 | | autofocus | bool | 是否自动获取焦点 | 否 | false | | textInputAction | TextInputAction? | 用于控制键盘动作 | 否 | 无 | +| inputFormatters | List\? | 过滤输入内容 | 否 | 无 | +| textInputType | TextInputType? | 输入类型 | 否 | 无 | diff --git a/doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md b/doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md index c0dbbc63..9fbb6c43 100644 --- a/doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md +++ b/doc/components/text/BrnPairInfoTable/BrnPairInfoTable.md @@ -31,8 +31,9 @@ BrnPairInfoTable({ this.rowDistance, this.itemSpacing, this.isFolded = true, - this.themeData, + this.onExpanded, this.customKeyWidth, + this.themeData }); ``` @@ -47,6 +48,7 @@ BrnPairInfoTable({ | rowDistance | double? | 行与行之间的间距 | 否 | 4 | | itemSpacing | double? | key-value 之间的间距 | 否 | 2 | | isFolded | true | 初始的展开收起状态 | 否 | bool | +| onExpanded | ValueChanged\? | 展开手气状态变化的回调 | 否 | 无 | | customKeyWidth | TableColumnWidth? | 对齐情况下,自定义的key展示规则,默认是最大的Key展示长度是107,可以参考[_MaxWrapTableWidth]实现自定义的展示规则,指定长度等 | 否 | key 最大宽度 94 | | themeData | BrnPairInfoTableConfig? | 主题定制属性 | 否 | | diff --git a/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md b/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md index 3b4f7453..b733f463 100644 --- a/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md +++ b/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md @@ -35,24 +35,28 @@ BrnCommonCardTitle( this.detailColor, this.alignment, this.padding, + this.titleMaxLines, + this.titleOverflow = TextOverflow.clip, this.themeData}) : super(key: key); ``` ### 参数说明 -| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | -| ---------------- | --------------------- | ----------------------------------- | ------------ | ----------------- | -| title | String | 标题文本 | 是 | | -| subTitleWidget | Widget? | 标题右侧的显示 widget | 否 | | -| accessoryText | String? | 最右侧的文字 | 否 | | -| accessoryWidget | Widget? | 最右侧的 widget | 否 | | -| onTap | VoidCallback? | 整个标题点击的事件 | 否 | | -| detailTextString | String? | 标题下面的文字 | 否 | | -| detailColor | Color? | 标题下方文字颜色 | 否 | Color(0xFF222222) | -| alignment | PlaceholderAlignment? | title 的流式文本的对齐方式 | 否 | | -| padding | EdgeInsetsGeometry? | 内容的间距 | 否 | | -| themeData | BrnCardTitleConfig? | 标题配置,详情见 BrnCardTitleConfig | 否 | | +| **参数名** | **参数类型** | **描述** | **是否必填** | **默认值** | +| ---------------- | --------------------- | ------------------------------------------------------------ | ------------ | ----------------- | +| title | String | 标题文本 | 是 | | +| subTitleWidget | Widget? | 标题右侧的显示 widget | 否 | | +| accessoryText | String? | 最右侧的文字 | 否 | | +| accessoryWidget | Widget? | 最右侧的 widget | 否 | | +| onTap | VoidCallback? | 整个标题点击的事件 | 否 | | +| detailTextString | String? | 标题下面的文字 | 否 | | +| detailColor | Color? | 标题下方文字颜色 | 否 | Color(0xFF222222) | +| alignment | PlaceholderAlignment? | title 的流式文本的对齐方式 | 否 | | +| padding | EdgeInsetsGeometry? | 内容的间距 | 否 | | +| titleMaxLines | int? | 标题最大行数 | 否 | 无 | +| titleOverflow | TextOverflow | 标题 Overflow 展示方式,
注意,由于 subTitleWidget 与 title 是流式布局,所以 subTitleWidget 会折叠 | 否 | TextOverflow.clip | +| themeData | BrnCardTitleConfig? | 标题配置,详情见 BrnCardTitleConfig | 否 | | ## 四、代码演示 diff --git a/example/lib/sample/components/charts/progress_bar_chart_example.dart b/example/lib/sample/components/charts/progress_bar_chart_example.dart index 0baa6afb..72ac818f 100644 --- a/example/lib/sample/components/charts/progress_bar_chart_example.dart +++ b/example/lib/sample/components/charts/progress_bar_chart_example.dart @@ -1,5 +1,3 @@ - - import 'dart:math'; import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; @@ -25,104 +23,114 @@ class ProgressBarChartExampleState extends State { appBar: BrnAppBar( title: '柱状图', ), - body: Column( - children: [ - BrnProgressBarChart( - barChartStyle: BarChartStyle.horizontal, - xAxis: ChartAxis(axisItemList: [ - AxisItem(showText: '10'), - AxisItem(showText: '20'), - AxisItem(showText: '30') - ]), - yAxis: ChartAxis(axisItemList: [ - AxisItem(showText: '示例1'), - AxisItem(showText: '示例2') - ]), - singleBarWidth: 30, - barBundleList: [ - BrnProgressBarBundle(barList: [ - BrnProgressBarItem(text: '示例', value: 10, hintValue: 15), - BrnProgressBarItem(text: '示例', value: 20) - ], colors: [ - Color(0xff1545FD), - Color(0xff0984F9) + body: SingleChildScrollView( + child: Column( + children: [ + BrnProgressBarChart( + barChartStyle: BarChartStyle.horizontal, + xAxis: ChartAxis(axisItemList: [ + AxisItem(showText: '1010'), + AxisItem(showText: '20'), + AxisItem(showText: '30'), + AxisItem(showText: '40'), + AxisItem(showText: '50'), + AxisItem(showText: '60'), + AxisItem(showText: '70'), + ]), + yAxis: ChartAxis(axisItemList: [ + AxisItem(showText: '示例1'), + AxisItem(showText: '示例2'), + AxisItem(showText: '示例3'), + AxisItem(showText: '示例4'), + AxisItem(showText: '示例5'), ]), - ], - ), - BrnProgressBarChart( - barChartStyle: BarChartStyle.vertical, - xAxis: ChartAxis(axisItemList: [ - AxisItem(showText: '示例1'), - AxisItem(showText: '示例2'), - AxisItem(showText: '示例3'), - AxisItem(showText: '示例4'), - AxisItem(showText: '示例5'), - AxisItem(showText: '示例6'), - AxisItem(showText: '示例7'), - AxisItem(showText: '示例8'), - AxisItem(showText: '示例9'), - AxisItem(showText: '示例10'), - ]), - barBundleList: [ - BrnProgressBarBundle(barList: [ - BrnProgressBarItem( - text: '示例11', - value: 5, - hintValue: 15, - showBarValueText: "1122334"), - BrnProgressBarItem( - text: '示例12', value: 20, selectedHintText: '示例12:20'), - BrnProgressBarItem( - text: '示例13', - value: 30, - selectedHintText: - '示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30'), - BrnProgressBarItem(text: '示例14', value: 25), - BrnProgressBarItem(text: '示例15', value: 21), - BrnProgressBarItem(text: '示例16', value: 28), - BrnProgressBarItem(text: '示例17', value: 15), - BrnProgressBarItem(text: '示例18', value: 11), - BrnProgressBarItem(text: '示例19', value: 30), - BrnProgressBarItem(text: '示例110', value: 24), - ], colors: [ - Color(0xff1545FD), - Color(0xff0984F9) + singleBarWidth: 30, + barBundleList: [ + BrnProgressBarBundle(barList: [ + BrnProgressBarItem(text: '示例', value: 10, hintValue: 15), + BrnProgressBarItem(text: '示例', value: 20), + BrnProgressBarItem(text: '示例', value: 30, hintValue: 15), + BrnProgressBarItem(text: '示例', value: 20, hintValue: 15), + BrnProgressBarItem(text: '示例', value: 0, hintValue: 15), + ], colors: [ + Color(0xff1545FD), + Color(0xff0984F9) + ]), + ], + barChartSelectCallback: (BrnProgressBarItem? barItem) { + BrnToast.show(barItem?.text ?? '', context); + }, + ), + BrnProgressBarChart( + barChartStyle: BarChartStyle.vertical, + xAxis: ChartAxis(axisItemList: [ + AxisItem(showText: '示例1'), + AxisItem(showText: '示例2'), + AxisItem(showText: '示例3'), + AxisItem(showText: '示例4'), + AxisItem(showText: '示例5'), + AxisItem(showText: '示例6'), + AxisItem(showText: '示例7'), + AxisItem(showText: '示例8'), + AxisItem(showText: '示例9'), + AxisItem(showText: '示例10'), ]), - BrnProgressBarBundle(barList: [ - BrnProgressBarItem(text: '示例21', value: 20, hintValue: 15), - BrnProgressBarItem( - text: '示例22', value: 15, selectedHintText: '示例12:20'), - BrnProgressBarItem( - text: '示例23', - value: 30, - selectedHintText: - '示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30'), - BrnProgressBarItem(text: '示例24', value: 20), - BrnProgressBarItem(text: '示例25', value: 28), - BrnProgressBarItem(text: '示例26', value: 25), - BrnProgressBarItem(text: '示例27', value: 17), - BrnProgressBarItem(text: '示例28', value: 14), - BrnProgressBarItem(text: '示例29', value: 36), - BrnProgressBarItem(text: '示例210', value: 29), - ], colors: [ - Color(0xff01D57D), - Color(0xff01D57D) + barBundleList: [ + BrnProgressBarBundle(barList: [ + BrnProgressBarItem( + text: '示例11', value: 5, hintValue: 15, showBarValueText: "1122334"), + BrnProgressBarItem(text: '示例12', value: 20, selectedHintText: '示例12:20'), + BrnProgressBarItem( + text: '示例13', + value: 30, + selectedHintText: '示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30'), + BrnProgressBarItem(text: '示例14', value: 25), + BrnProgressBarItem(text: '示例15', value: 21), + BrnProgressBarItem(text: '示例16', value: 28), + BrnProgressBarItem(text: '示例17', value: 15), + BrnProgressBarItem(text: '示例18', value: 11), + BrnProgressBarItem(text: '示例19', value: 30), + BrnProgressBarItem(text: '示例110', value: 24), + ], colors: [ + Color(0xff1545FD), + Color(0xff0984F9) + ]), + BrnProgressBarBundle(barList: [ + BrnProgressBarItem(text: '示例21', value: 20, hintValue: 15), + BrnProgressBarItem(text: '示例22', value: 15, selectedHintText: '示例12:20'), + BrnProgressBarItem( + text: '示例23', + value: 30, + selectedHintText: '示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30\n示例13:30'), + BrnProgressBarItem(text: '示例24', value: 20), + BrnProgressBarItem(text: '示例25', value: 28), + BrnProgressBarItem(text: '示例26', value: 25), + BrnProgressBarItem(text: '示例27', value: 17), + BrnProgressBarItem(text: '示例28', value: 14), + BrnProgressBarItem(text: '示例29', value: 36), + BrnProgressBarItem(text: '示例210', value: 29), + ], colors: [ + Color(0xff01D57D), + Color(0xff01D57D) + ]), + ], + yAxis: ChartAxis(axisItemList: [ + AxisItem(showText: '10'), + AxisItem(showText: '20'), + AxisItem(showText: '30') ]), - ], - yAxis: ChartAxis(axisItemList: [ - AxisItem(showText: '10'), - AxisItem(showText: '20'), - AxisItem(showText: '30') - ]), - singleBarWidth: 30, - barGroupSpace: 30, - barMaxValue: 60, - onBarItemClickInterceptor: - (barBundleIndex, barBundle, barGroupIndex, barItem) { - return true; - }, - ) - ], + singleBarWidth: 30, + barGroupSpace: 30, + barMaxValue: 60, + onBarItemClickInterceptor: (barBundleIndex, barBundle, barGroupIndex, barItem) { + return true; + }, + barChartSelectCallback: (BrnProgressBarItem? barItem) { + BrnToast.show(barItem?.text ?? '', context); + }, + ) + ], + ), ), ); } diff --git a/example/lib/sample/components/form/all_item_style_example.dart b/example/lib/sample/components/form/all_item_style_example.dart index 07630cad..0322b638 100644 --- a/example/lib/sample/components/form/all_item_style_example.dart +++ b/example/lib/sample/components/form/all_item_style_example.dart @@ -252,7 +252,7 @@ class AllFormItemStyleExamplePage extends StatelessWidget { onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return StepInputExamplePage("递增表单项f`ormItemConfig"); + return StepInputExamplePage(title: "递增表单项"); }, )); }, diff --git a/example/lib/sample/components/form/items_example/step_input_example.dart b/example/lib/sample/components/form/items_example/step_input_example.dart index 3b828923..001c0d29 100644 --- a/example/lib/sample/components/form/items_example/step_input_example.dart +++ b/example/lib/sample/components/form/items_example/step_input_example.dart @@ -3,16 +3,24 @@ import 'package:bruno/bruno.dart'; import 'package:flutter/material.dart'; -class StepInputExamplePage extends StatelessWidget { - final String _title; +class StepInputExamplePage extends StatefulWidget { - StepInputExamplePage(this._title); + final String title; + const StepInputExamplePage({Key? key, this.title = '示例'}) : super(key: key); + + @override + State createState() => _StepInputExamplePageState(); +} + +class _StepInputExamplePageState extends State { + + TextEditingController _manualInputController = TextEditingController()..text = '23'; @override Widget build(BuildContext context) { return Scaffold( appBar: BrnAppBar( - title: _title, + title: widget.title, ), body: ListView( children: [ @@ -113,6 +121,30 @@ class StepInputExamplePage extends StatelessWidget { "点击触发回调${oldValue}_${newValue}_onChanged", context); }, ), + BrnStepInputFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + canManualInput: true, + controller: _manualInputController, + title: "可手动输入", + subTitle: "可传入 controller设置初始值 ", + maxLimit: 99, + minLimit: 0, + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + onChanged: (oldValue, newValue) { + BrnToast.show( + "点击触发回调_${oldValue}_${newValue}_onChanged", context); + }, + ), ], )); } diff --git a/example/lib/sample/components/picker/multi_picker_example.dart b/example/lib/sample/components/picker/multi_picker_example.dart index ad50ea05..e311a1b4 100644 --- a/example/lib/sample/components/picker/multi_picker_example.dart +++ b/example/lib/sample/components/picker/multi_picker_example.dart @@ -140,9 +140,40 @@ class MultiPickerExamplePage extends StatelessWidget { ).show(); }, ), + ListItem( + title: "默认 Delegate", + describe: '使用默认 Delegate 构造数据展示', + onPressed: () { + BrnMultiDataPicker( + context: context, + title: '来源', + delegate: BrnDefaultMultiDataPickerDelegate( + firstSelectedIndex: 2, + secondSelectedIndex: 1, + thirdSelectedIndex: 1, + data: _getDefaultDelegateData()), + confirmClick: (list) { + BrnToast.show(list.toString(), context); + }, + ).show(); + }, + ), ], )); } + + List _getDefaultDelegateData() { + BrnMultiDataPickerEntity data = BrnMultiDataPickerEntity( + text: '测试1', value: 5095791542795657, children: []); + + BrnMultiDataPickerEntity data2 = BrnMultiDataPickerEntity( + text: '测试2', value: 5029051542795656, children: []); + + BrnMultiDataPickerEntity data3 = BrnMultiDataPickerEntity( + text: '测试3', value: 5090501542795658, children: []); + + return [data, data2, data3]; + } } class Brn1RowDelegate implements BrnMultiDataPickerDelegate { diff --git a/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart b/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart index 5ac76358..c72810fb 100644 --- a/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart +++ b/example/lib/sample/components/scroll_anchor/scroll_actor_tab_example.dart @@ -13,14 +13,20 @@ class ScrollActorTabExample extends StatelessWidget { title: '锚点', ), body: BrnAnchorTab( - itemCount: 10, + itemCount: 20, widgetIndexedBuilder: (context, index) { - return Container( - child: Center(child: Text('$index')), - height: Random().nextInt(400).toDouble(), - color: Color.fromARGB(Random().nextInt(255), Random().nextInt(255), - Random().nextInt(255), Random().nextInt(255)), - ); + return StatefulBuilder(builder: (_, state) { + double height = Random().nextInt(400).toDouble(); + return GestureDetector(child: Container( + child: Center(child: Text('$index')), + height: height, + color: Color.fromARGB(Random().nextInt(255), Random().nextInt(255), + Random().nextInt(255), Random().nextInt(255)), + ), + onTap: (){ + state(() {}); + },); + }); }, tabIndexedBuilder: (context, index) { return BadgeTab(text: 'index $index'); diff --git a/example/lib/sample/home/group_card.dart b/example/lib/sample/home/group_card.dart index 0296a77d..e63a2def 100644 --- a/example/lib/sample/home/group_card.dart +++ b/example/lib/sample/home/group_card.dart @@ -21,7 +21,7 @@ class GroupCard extends StatefulWidget { } class GroupCardState extends State - with SingleTickerProviderStateMixin { + with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin { static final Animatable _easeInTween = CurveTween(curve: Curves.easeIn); static final Animatable _halfTween = @@ -32,6 +32,9 @@ class GroupCardState extends State late bool _initExpand; AnimationController? _animationController; + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); @@ -101,7 +104,7 @@ class GroupCardState extends State Widget _getContentWidget() { if (widget.groupInfo == null || widget.groupInfo!.children == null) { - return SizedBox.shrink(); + return const SizedBox.shrink(); } return ListView.builder( physics: new NeverScrollableScrollPhysics(), diff --git a/example/lib/sample/home/list_item.dart b/example/lib/sample/home/list_item.dart index e37c9332..0d5cdedb 100644 --- a/example/lib/sample/home/list_item.dart +++ b/example/lib/sample/home/list_item.dart @@ -42,7 +42,10 @@ class ListItem extends StatefulWidget { _ListItemState createState() => _ListItemState(); } -class _ListItemState extends State { +class _ListItemState extends State with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + @override Widget build(BuildContext context) { return TextButton( diff --git a/lib/src/components/appraise/brn_appraise_header.dart b/lib/src/components/appraise/brn_appraise_header.dart index 6ba5a3b8..43d985cf 100644 --- a/lib/src/components/appraise/brn_appraise_header.dart +++ b/lib/src/components/appraise/brn_appraise_header.dart @@ -45,7 +45,7 @@ class BrnAppraiseHeader extends StatelessWidget { return _centerHeader(); } } - return SizedBox.shrink(); + return const SizedBox.shrink(); } Widget _centerHeader() { diff --git a/lib/src/components/button/collection/brn_bottom_button_panel.dart b/lib/src/components/button/collection/brn_bottom_button_panel.dart index 403835ec..5ee6c6f7 100644 --- a/lib/src/components/button/collection/brn_bottom_button_panel.dart +++ b/lib/src/components/button/collection/brn_bottom_button_panel.dart @@ -109,7 +109,7 @@ class BrnBottomButtonPanel extends StatelessWidget { bool enableMainButton = true, List? iconButtonList}) { if ((buttonTitleList.isEmpty) && iconButtonList == null) { - return SizedBox.shrink(); + return const SizedBox.shrink(); } if (buttonTitleList.length >= 2) { return BrnBottomButtonPanel( @@ -142,7 +142,7 @@ class BrnBottomButtonPanel extends StatelessWidget { iconButtonList: iconButtonList, ); } - return SizedBox.shrink(); + return const SizedBox.shrink(); } @override diff --git a/lib/src/components/button/collection/brn_text_button_panel.dart b/lib/src/components/button/collection/brn_text_button_panel.dart index 7fb6ccfc..63e20acb 100644 --- a/lib/src/components/button/collection/brn_text_button_panel.dart +++ b/lib/src/components/button/collection/brn_text_button_panel.dart @@ -74,17 +74,17 @@ class _BrnTextButtonPanelState extends State { List showWidget = []; for (int i = 0, n = widgetList.length; i < n; ++i) { showWidget.add(Expanded( - child: Center( - child: widgetList[i], - ), + child: widgetList[i], )); if (i != n - 1) { - showWidget.add(Container( - alignment: Alignment.center, - height: 26, - width: 1, - color: Color(0xFFf8f8f8), - )); + showWidget.add( + Container( + alignment: Alignment.center, + height: 26, + width: 1, + color: Color(0xFFf8f8f8), + ), + ); } } return showWidget; @@ -103,7 +103,9 @@ class _BrnTextButtonPanelState extends State { ); return GestureDetector( + behavior: HitTestBehavior.opaque, child: Container( + alignment: Alignment.center, padding: EdgeInsets.fromLTRB(4, 0, 4, 0), child: tx, ), @@ -140,6 +142,7 @@ class _BrnTextButtonPanelState extends State { : BrunoTools.getAssetImage(BrnAsset.iconDownArrow); return GestureDetector( + behavior:HitTestBehavior.opaque, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -171,7 +174,7 @@ class _BrnTextButtonPanelState extends State { }); }); } else { - return SizedBox.shrink(); + return const SizedBox.shrink(); } } } diff --git a/lib/src/components/calendar/brn_calendar_view.dart b/lib/src/components/calendar/brn_calendar_view.dart index 119bdb62..57a029b9 100644 --- a/lib/src/components/calendar/brn_calendar_view.dart +++ b/lib/src/components/calendar/brn_calendar_view.dart @@ -267,7 +267,7 @@ class _CustomCalendarViewState extends State { ), ); } - return SizedBox.shrink(); + return const SizedBox.shrink(); } bool _isIconEnable(bool isPre) { diff --git a/lib/src/components/card/content_card/brn_pair_info_table.dart b/lib/src/components/card/content_card/brn_pair_info_table.dart index 463beac3..3dd6835b 100644 --- a/lib/src/components/card/content_card/brn_pair_info_table.dart +++ b/lib/src/components/card/content_card/brn_pair_info_table.dart @@ -103,6 +103,9 @@ class BrnPairInfoTable extends StatefulWidget { ///可以参考[_MaxWrapTableWidth]实现自定义的展示规则,指定长度等 final TableColumnWidth? customKeyWidth; + /// Table 展开收起状态变化的回调 + final ValueChanged? onFolded; + BrnPairInfoTable({ Key? key, required this.children, @@ -112,8 +115,9 @@ class BrnPairInfoTable extends StatefulWidget { this.rowDistance, this.itemSpacing, this.isFolded = true, - this.themeData, + this.onFolded, this.customKeyWidth, + this.themeData }); @override @@ -140,7 +144,7 @@ class _BrnPairInfoTableState extends State { BrnInfoModal? indexModal; // 是否具备展开收起功能 如果不展示则显示全部 - bool canExpanded = false; + bool _canFold = false; late BrnPairInfoTableConfig themeData; @@ -161,12 +165,12 @@ class _BrnPairInfoTableState extends State { widget.expandAtIndex >= (widget.children.length - 1)) { _expandAtIndex = -1; showList = widget.children; - canExpanded = false; + _canFold = false; } else { indexModal = widget.children[_expandAtIndex]; foldList = _generateFoldList(); expandedList = _generateExpandedList(); - canExpanded = true; + _canFold = true; } super.initState(); } @@ -186,7 +190,7 @@ class _BrnPairInfoTableState extends State { Widget build(BuildContext context) { Widget showWidget; - if (canExpanded) { + if (_canFold) { if (_isFolded) { showList = foldList; } else { @@ -296,6 +300,7 @@ class _BrnPairInfoTableState extends State { GestureDetector gdt = GestureDetector( child: row, onTap: () { + widget.onFolded?.call(!_isFolded); setState(() { _isFolded = !_isFolded; }); @@ -355,6 +360,7 @@ class _BrnPairInfoTableState extends State { GestureDetector gdt = GestureDetector( child: row, onTap: () { + widget.onFolded?.call(!_isFolded); setState(() { _isFolded = !_isFolded; }); @@ -578,9 +584,7 @@ class BrnFollowPairInfo extends StatelessWidget with PairInfoPart { if (infoModal.valueClickCallback != null) { value = GestureDetector( onTap: () { - if (infoModal.valueClickCallback != null) { - infoModal.valueClickCallback!(); - } + infoModal.valueClickCallback?.call(); }, child: value, ); diff --git a/lib/src/components/card_title/brn_action_card_title.dart b/lib/src/components/card_title/brn_action_card_title.dart index 4cb00a2c..4cadc255 100644 --- a/lib/src/components/card_title/brn_action_card_title.dart +++ b/lib/src/components/card_title/brn_action_card_title.dart @@ -134,7 +134,7 @@ class BrnActionCardTitle extends StatelessWidget { ); } - return SizedBox.shrink(); + return const SizedBox.shrink(); } Widget _arrowWidget() { diff --git a/lib/src/components/card_title/brn_common_card_title.dart b/lib/src/components/card_title/brn_common_card_title.dart index cea76fdf..2bcb46a0 100644 --- a/lib/src/components/card_title/brn_common_card_title.dart +++ b/lib/src/components/card_title/brn_common_card_title.dart @@ -73,6 +73,13 @@ class BrnCommonCardTitle extends StatelessWidget { /// 内容的padding 默认上下16 左右0 final EdgeInsetsGeometry? padding; + /// 标题最大行数 + final int? titleMaxLines; + + /// 标题 Overflow 展示方式,默认 TextOverflow.clip + /// 注意,由于 subTitleWidget 与 title 是流式布局,所以 subTitleWidget 会折叠 + final TextOverflow titleOverflow; + final BrnCardTitleConfig? themeData; BrnCommonCardTitle( @@ -86,7 +93,9 @@ class BrnCommonCardTitle extends StatelessWidget { this.detailColor, this.alignment, this.padding, - this.themeData}) + this.titleMaxLines, + this.titleOverflow = TextOverflow.clip, + this.themeData}) : super(key: key); @override @@ -174,6 +183,8 @@ class BrnCommonCardTitle extends StatelessWidget { } var titleWidget = RichText( textScaleFactor: MediaQuery.of(context).textScaleFactor, + maxLines: this.titleMaxLines, + overflow: this.titleOverflow, text: TextSpan( text: title, style: defaultConfig.titleWithHeightTextStyle.generateTextStyle(), diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart index 4381b053..16d142d3 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart.dart @@ -213,19 +213,60 @@ class BrnProgressBarChartState extends State { ), ); } else if (BarChartStyle.horizontal == widget.barChartStyle) { + double yAxisWidth = + BrnProgressBarChartPainter.maxYAxisWidth(widget.yAxis); return Padding( padding: widget.padding, - child: CustomPaint( - size: chartSize, - painter: BrnProgressBarChartPainter( - xAxis: widget.xAxis, - yAxis: widget.yAxis, - barChartStyle: widget.barChartStyle, - singleBarWidth: widget.singleBarWidth, - barMaxValue: widget.barMaxValue, - barGroupSpace: widget.barGroupSpace, - barBundleList: widget.barBundleList, - ), + child: Stack( + children: [ + Padding( + padding: EdgeInsets.only(left: yAxisWidth), + child: CustomPaint( + size: chartSize, + painter: BrnProgressBarChartPainter( + drawBar: false, + drawY: false, + xAxis: widget.xAxis, + yAxis: widget.yAxis, + barChartStyle: widget.barChartStyle, + singleBarWidth: widget.singleBarWidth, + barMaxValue: widget.barMaxValue, + barGroupSpace: widget.barGroupSpace, + barBundleList: widget.barBundleList, + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 22), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: CustomPaint( + size: chartSize, + painter: BrnProgressBarChartPainter( + drawX: false, + xAxis: widget.xAxis, + yAxis: widget.yAxis, + barChartStyle: widget.barChartStyle, + singleBarWidth: widget.singleBarWidth, + barMaxValue: widget.barMaxValue, + barGroupSpace: widget.barGroupSpace, + barBundleList: widget.barBundleList, + onBarItemClickInterceptor: + widget.onBarItemClickInterceptor, + selectedBarItem: _selectedBarItem, + selectedHintTextColor: widget.selectedHintTextColor, + selectedHintTextBackgroundColor: + widget.selectedHintTextBackgroundColor, + brnProgressBarChartSelectCallback: (BrnProgressBarItem? item) { + widget.barChartSelectCallback?.call(item); + setState(() { + _selectedBarItem = item; + }); + }), + ), + ), + ), + ], ), ); } else { diff --git a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart index 28845bec..1e24733b 100644 --- a/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart +++ b/lib/src/components/charts/brn_progress_bar_chart/brn_progress_bar_chart_painter.dart @@ -69,12 +69,17 @@ class ChartAxis { /// 0/刻度偏移量 double leadingSpace = 30; + TextStyle textStyle = TextStyle(color: Color(0x999999), fontSize: 12); + /// 倾斜坐标轴文本,避免文本距离过近,目前仅针对X轴文本有效 + final bool inclineText; + ChartAxis({ required this.axisItemList, this.hasMark = true, this.axisStyle = AxisStyle.axisStyleSolid, + this.inclineText = false, }); } @@ -276,6 +281,16 @@ class BrnProgressBarChartPainter extends CustomPainter { this.xAxisRect = Rect.fromPoints( this.yAxisRect.bottomRight, Offset(size.width, size.height)); + if (this.barChartStyle == BarChartStyle.horizontal) { + if (!this.drawX) { + // 仅画x + this.xAxisRect = Rect.fromLTWH(this.yAxisRect.bottomRight.dx, + size.height, size.width - this.yAxisRect.width, 0); + this.yAxisRect = Rect.fromLTWH( + 0, 0, this.yAxis.maxTextWidth + _yTextAxisSpace, size.height - (this.xAxis.axisItemList.isEmpty ? 0 : this._xAxisHeight)); + } + } + if (this.barBundleList.isNotEmpty) { this.contentRect = Rect.fromPoints(this.yAxisRect.topRight, this.xAxisRect.topRight); @@ -424,8 +439,16 @@ class BrnProgressBarChartPainter extends CustomPainter { double textWidth = textPainter.size.width; - textPainter.paint(canvas, - Offset(currentOffset.dx - textWidth / 2, currentOffset.dy + 5)); + if (this.xAxis.inclineText == true) { + canvas.save(); + canvas.translate(currentOffset.dx, currentOffset.dy + 3); + canvas.rotate(-0.3); + textPainter.paint(canvas, Offset(-textWidth, 0)); + canvas.restore(); + } else { + textPainter.paint(canvas, + Offset(currentOffset.dx - textWidth / 2, currentOffset.dy + 5)); + } } } else if (BarChartStyle.vertical == this.barChartStyle) { Paint markLinkePaint = Paint()..color = Color(0xff222222); @@ -722,21 +745,57 @@ class BrnProgressBarChartPainter extends CustomPainter { RRect barRRect = RRect.fromRectAndCorners(barItem.barRect!, topRight: Radius.circular(4), bottomRight: Radius.circular(4)); - Shader shader = LinearGradient( + if (this.selectedBarItem != null) { + // 有选中的柱形,选中柱形保持原样,未选中的置灰 + Shader shader; + if (this.selectedBarItem!.barRect == barItem.barRect) { + // 选中的柱形 + shader = LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, tileMode: TileMode.clamp, colors: barBundle.colors) - .createShader(barItem.barRect!); - Paint barPaint = Paint() - ..shader = shader - ..isAntiAlias = true - ..strokeCap = StrokeCap.round - ..strokeWidth = 1.5 - ..style = PaintingStyle.fill; - - canvas.drawRRect(barRRect, barPaint); + .createShader(barItem.barRect!); + } else { + // 未选中需要置灰的柱形 + shader = LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + tileMode: TileMode.clamp, + colors: [this.unselectedColor, this.unselectedColor]) + .createShader(barItem.barRect!); + } + Paint barPaint = Paint() + ..shader = shader + ..isAntiAlias = true + ..strokeCap = StrokeCap.round + ..strokeWidth = 1.5 + ..style = PaintingStyle.fill; + canvas.drawRRect(barRRect, barPaint); + if (this.selectedBarItem!.barRect == barItem.barRect) { + // 选中柱形的虚线以及 HintText + this._drawDashLineOn( + canvas, + barItem.barRect!.centerLeft, + Offset(this.xAxisRect.right, barItem.barRect!.centerLeft.dy), + Color(0xff222222)); + } + } else { + Shader shader = LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + tileMode: TileMode.clamp, + colors: barBundle.colors) + .createShader(barItem.barRect!); + Paint barPaint = Paint() + ..shader = shader + ..isAntiAlias = true + ..strokeCap = StrokeCap.round + ..strokeWidth = 1.5 + ..style = PaintingStyle.fill; + canvas.drawRRect(barRRect, barPaint); + } // 绘制柱状图上的数值 TextStyle textStyle = TextStyle(color: Colors.white, fontSize: 12); this.barItemEnumerator((int barBundleIndex, @@ -753,6 +812,60 @@ class BrnProgressBarChartPainter extends CustomPainter { textPainter.paint(canvas, textOffset); }); }); + + + // 最后画选中柱形的提示文字,否则可能被遮挡 + if (null != this.selectedBarItem) { + // 画选中文字 Start + TextPainter selectedBarTextPainter = TextPainter( + text: TextSpan( + text: selectedBarItem!.selectedHintText ?? + (selectedBarItem!.text ?? ''), + style: + TextStyle(fontSize: 12, color: this.selectedHintTextColor)), + textDirection: TextDirection.ltr) + ..layout(maxWidth: double.infinity, minWidth: 0); + double textWidth = selectedBarTextPainter.size.width; + double textHeight = selectedBarTextPainter.size.height; + + Offset selectedBarTextBgCenterOffset; + if (selectedBarItem!.barRect!.centerLeft.dy + 10 + textHeight + 10 * 2 > + this.contentRect.bottom) { + // 需要显示在上侧 + selectedBarTextBgCenterOffset = Offset( + this.xAxisRect.bottomRight.dx - 10 - 10 - textWidth / 2, + selectedBarItem!.barRect!.centerRight.dy - (10 + textWidth / 2)); + } else { + // 需要显示在下侧 + selectedBarTextBgCenterOffset = Offset( + this.xAxisRect.bottomRight.dx - 10 - 10 - textWidth / 2, + selectedBarItem!.barRect!.centerRight.dy + (10 + textWidth / 2)); + } + + // 文本背景区域超出整个图形范围 + if (textHeight / 2 + 8 > selectedBarTextBgCenterOffset.dy) { + selectedBarTextBgCenterOffset = + Offset(selectedBarTextBgCenterOffset.dx, textHeight / 2 + 8); + } + + // 画选中文字背景 + Paint selectTextBgPaint = Paint() + ..color = this.selectedHintTextBackgroundColor + ..style = PaintingStyle.fill; + RRect selectTextBgRRect = RRect.fromRectAndRadius( + Rect.fromCenter( + center: selectedBarTextBgCenterOffset, + width: textWidth + 10 * 2, + height: textHeight + 8 * 2), + Radius.circular(2)); + canvas.drawRRect(selectTextBgRRect, selectTextBgPaint); + selectedBarTextPainter.paint( + canvas, + Offset(selectedBarTextBgCenterOffset.dx - textWidth / 2, + selectedBarTextBgCenterOffset.dy - textHeight / 2)); + + // 画选中文字 End + } } Size getTextAreaSize(String text, TextStyle textStyle) { @@ -770,8 +883,7 @@ class BrnProgressBarChartPainter extends CustomPainter { @override bool? hitTest(Offset position) { - if (this.brnProgressBarChartSelectCallback != null && - BarChartStyle.vertical == this.barChartStyle) { + if (this.brnProgressBarChartSelectCallback != null) { this.barItemEnumerator((int barBundleIndex, BrnProgressBarBundle barBundle, int barGroupIndex, diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index 9954bb76..7b83a4f1 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -1,4 +1,5 @@ import 'package:bruno/src/components/dialog/brn_dialog.dart'; +import 'package:bruno/src/theme/brn_theme.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -56,7 +57,10 @@ class BrnMiddleInputDialog { /// 点击取消/确认按钮之后,是否自动关闭弹窗,默认为 true,关闭 final bool dismissOnActionsTap; - const BrnMiddleInputDialog( + /// 点击取消/确认按钮之后,是否自动关闭弹窗,默认为 true,关闭 + BrnDialogConfig? themeData; + + BrnMiddleInputDialog( {this.title, this.message, this.hintText, @@ -73,7 +77,14 @@ class BrnMiddleInputDialog { this.onCancel, this.dismissOnActionsTap = true, this.barrierDismissible = true, - this.autoFocus = false}); + this.autoFocus = false, + this.themeData}) { + this.themeData ??= BrnDialogConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .dialogConfig + .merge(this.themeData); + } void show(BuildContext context) { _doShow(context); @@ -83,10 +94,18 @@ class BrnMiddleInputDialog { String _value = inputEditingController?.text ?? ""; var dialogMessageWidgets = []; if (message != null && message!.isNotEmpty) { - dialogMessageWidgets.add(Text( - message!, - style: cContentTextStyle, - textAlign: cContentTextAlign, + dialogMessageWidgets.add(Flexible( + child: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Align( + alignment: _getMessageAlign(themeData!.contentTextAlign), + child: Text( + message!, + style: themeData!.contentTextStyle.generateTextStyle(), + textAlign: themeData!.contentTextAlign, + ), + ), + ), )); dialogMessageWidgets.add(Container( height: 12, @@ -158,8 +177,9 @@ class BrnMiddleInputDialog { confirm: confirmText, title: title, barrierDismissible: barrierDismissible, + themeData: themeData, messageWidget: Padding( - padding: const EdgeInsets.only(top: 12, left: 24, right: 24), + padding: themeData!.contentPaddingLg, child: Column( mainAxisSize: MainAxisSize.min, children: dialogMessageWidgets, @@ -170,4 +190,15 @@ class BrnMiddleInputDialog { if (onCancel != null) onCancel!(); }); } + + + Alignment _getMessageAlign(TextAlign messageTextAlign) { + if(messageTextAlign == TextAlign.left || messageTextAlign == TextAlign.start) { + return Alignment.centerLeft; + } + if(messageTextAlign == TextAlign.right || messageTextAlign == TextAlign.end) { + return Alignment.centerRight; + } + return Alignment.center; + } } \ No newline at end of file diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index e30654df..324256f3 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -162,6 +162,7 @@ class MultiSelectPickerWidgetState extends State { Widget build(BuildContext context) { return BrnContentExportWidget( Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ _generateContentWidget(), Container( @@ -247,11 +248,15 @@ class MultiSelectPickerWidgetState extends State { padding: EdgeInsets.only(bottom: 8, left: 20, right: 20), child: Text( widget.messageText!, - style: cContentTextStyle, + style: BrnThemeConfigurator.instance + .getConfig() + .dialogConfig + .contentTextStyle + .generateTextStyle(), ), ); } - return Container(); + return const SizedBox.shrink(); } Widget _buildItem(BuildContext context, int index) { diff --git a/lib/src/components/dialog/brn_scrollable_text_dialog.dart b/lib/src/components/dialog/brn_scrollable_text_dialog.dart index 9de95c0d..451b636b 100644 --- a/lib/src/components/dialog/brn_scrollable_text_dialog.dart +++ b/lib/src/components/dialog/brn_scrollable_text_dialog.dart @@ -112,21 +112,25 @@ class BrnScrollableText extends StatelessWidget { Widget build(BuildContext context) { return BrnContentExportWidget( Padding( - padding: EdgeInsets.fromLTRB(20, 0, 20, 0), + padding: EdgeInsets.fromLTRB(20, 0, 8, 0), child: Container( - constraints: BoxConstraints(maxHeight: 220), - child: Scrollbar( - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ + constraints: BoxConstraints(maxHeight: 220), + child: Scrollbar( + radius: Radius.circular(2.0), + thickness: 4.0, + child: Padding( + padding: EdgeInsets.only(right: 8), + child: SingleChildScrollView( + child: Column(mainAxisSize: MainAxisSize.min, children: [ BrnCSS2Text.toTextView(contentText, linksCallback: linksCallback, defaultStyle: TextStyle( - fontSize: textFontSize, - color: textColor, - fontWeight: FontWeight.normal)) - ])))), + fontSize: textFontSize, color: textColor, fontWeight: FontWeight.normal)) + ]), + ), + ), + ), + ), ), title: title, isClose: isClose, diff --git a/lib/src/components/dialog/brn_single_select.dart b/lib/src/components/dialog/brn_single_select.dart index 97e2c3a1..22bebc18 100644 --- a/lib/src/components/dialog/brn_single_select.dart +++ b/lib/src/components/dialog/brn_single_select.dart @@ -53,6 +53,9 @@ class BrnSingleSelectDialog extends Dialog { /// 是否在点击时让 Diallog 消失,默认为 true final bool canDismissOnConfirmClick; + /// 点击关闭按钮回调 + final VoidCallback? onCloseClick; + const BrnSingleSelectDialog( {this.isClose: true, this.title: "", @@ -65,6 +68,7 @@ class BrnSingleSelectDialog extends Dialog { this.onItemClick, this.checkedItem, this.customWidget, + this.onCloseClick, this.canDismissOnConfirmClick = true, this.isCustomFollowScroll = true}); @@ -83,7 +87,8 @@ class BrnSingleSelectDialog extends Dialog { checkedItem: checkedItem, customWidget: customWidget, canDismissOnConfirmClick: canDismissOnConfirmClick, - isCustomFollowScroll: isCustomFollowScroll); + isCustomFollowScroll: isCustomFollowScroll, + onCloseClick: onCloseClick,); } } @@ -106,6 +111,9 @@ class BrnSingleSelectDialogWidget extends StatefulWidget { final bool canDismissOnConfirmClick; + /// 点击关闭按钮回调 + final VoidCallback? onCloseClick; + BrnDialogConfig? themeData; BrnSingleSelectDialogWidget( @@ -120,6 +128,7 @@ class BrnSingleSelectDialogWidget extends StatefulWidget { this.onItemClick, this.checkedItem, this.customWidget, + this.onCloseClick, this.isCustomFollowScroll = true, this.canDismissOnConfirmClick = true, this.themeData}) { @@ -254,14 +263,18 @@ class BrnSingleSelectDialogWidgetState right: 0.0, child: InkWell( onTap: () { - Navigator.of(context).pop(); + if (widget.onCloseClick != null) { + widget.onCloseClick!(); + } else { + Navigator.of(context).pop(); + } }, child: Padding( padding: EdgeInsets.all(15), child: BrunoTools.getAssetImage( BrnAsset.iconPickerClose), ))) - : Container() + : SizedBox.shrink() ], ), ))); diff --git a/lib/src/components/form/items/general/brn_quick_select_input_item.dart b/lib/src/components/form/items/general/brn_quick_select_input_item.dart index 917b1a3a..1dc06f97 100644 --- a/lib/src/components/form/items/general/brn_quick_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_quick_select_input_item.dart @@ -322,7 +322,7 @@ class QuickButtonsState extends State { ); } } else { - return SizedBox.shrink(); + return const SizedBox.shrink(); } } diff --git a/lib/src/components/form/items/general/brn_step_input_item.dart b/lib/src/components/form/items/general/brn_step_input_item.dart index ce7f0ee1..0162a526 100644 --- a/lib/src/components/form/items/general/brn_step_input_item.dart +++ b/lib/src/components/form/items/general/brn_step_input_item.dart @@ -2,6 +2,7 @@ import 'package:bruno/bruno.dart'; import 'package:bruno/src/components/form/utils/brn_form_util.dart'; import 'package:bruno/src/constants/brn_fonts_constants.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; /// /// 递增/递减型录入项 @@ -63,6 +64,11 @@ class BrnStepInputFormItem extends StatefulWidget { /// 当前值变化回调 final OnBrnFormValueChanged? onChanged; + /// 是否可通过键盘手动输入内容 + final bool canManualInput; + + final TextEditingController? controller; + /// form配置 BrnFormItemConfig? themeData; @@ -83,9 +89,18 @@ class BrnStepInputFormItem extends StatefulWidget { this.maxLimit = 10, this.minLimit = 0, this.onChanged, + this.canManualInput = false, + this.controller, this.themeData, - }) : assert(value == null || value >= minLimit && value <= maxLimit), - super(key: key) { + }) : super(key: key) { + if (value != null) { + assert(value! >= minLimit && value! <= maxLimit); + } + if (controller != null) { + int? defaultValue = int.tryParse(controller!.text); + assert(defaultValue == null || (defaultValue >= minLimit && defaultValue <= maxLimit), + 'The text or value in the controller is not in the limits.'); + } this.themeData ??= BrnFormItemConfig(); this.themeData = BrnThemeConfigurator.instance .getConfig(configId: this.themeData!.configId) @@ -100,12 +115,33 @@ class BrnStepInputFormItem extends StatefulWidget { } class BrnStepInputFormItemState extends State { - late int _value; - + late TextEditingController _textEditingController; + late int _oldValue; @override void initState() { super.initState(); - _value = widget.value ?? widget.minLimit; + if (widget.controller == null) { + _textEditingController = TextEditingController(); + _textEditingController.text = (widget.value ?? 0).toString(); + } else { + _textEditingController = widget.controller!; + } + _oldValue = _value; + _textEditingController.addListener(_onControllerTextChangedHandleTicker); + } + + @override + void dispose() { + _textEditingController.removeListener(_onControllerTextChangedHandleTicker); + super.dispose(); + } + + void _onControllerTextChangedHandleTicker() { + if (_oldValue != _value) { + BrnFormUtil.notifyValueChanged(widget.onChanged, context, _oldValue, _value); + setState(() {}); + _oldValue = _value; + } } @override @@ -124,19 +160,14 @@ class BrnStepInputFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( - padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, - widget.isRequire, widget.themeData!), + padding: BrnFormUtil.titleEdgeInsets( + widget.prefixIconType, widget.isRequire, widget.themeData!), child: Row( children: [ - BrnFormUtil.buildPrefixIcon( - widget.prefixIconType, - widget.isEdit, - context, - widget.onAddTap, - widget.onRemoveTap), + BrnFormUtil.buildPrefixIcon(widget.prefixIconType, widget.isEdit, context, + widget.onAddTap, widget.onRemoveTap), BrnFormUtil.buildRequireWidget(widget.isRequire), - BrnFormUtil.buildTitleWidget( - widget.title, widget.themeData!), + BrnFormUtil.buildTitleWidget(widget.title, widget.themeData!), BrnFormUtil.buildTipLabelWidget( widget.tipLabel, widget.onTip, widget.themeData!), ], @@ -147,55 +178,25 @@ class BrnStepInputFormItemState extends State { children: [ GestureDetector( onTap: () { - if (!isEnable()) { + if (!widget.isEdit) { return; } - - if (isReachMinLevel()) { - return; - } - - if (!isReachMinLevel()) { - _value = _value - 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, _value + 1, _value); - setState(() {}); - } + _checkReachMinLevel(); }, child: Container( - child: getMinusIcon(), - ), - ), - Container( - alignment: Alignment.center, - width: 50, - child: Text( - "$_value", - style: TextStyle( - color: Color(0xFF222222), - fontSize: BrnFonts.f16, - ), + child: _getMinusIcon(), ), ), + _buildValueWidget(), GestureDetector( onTap: () { - if (!isEnable()) { + if (!widget.isEdit) { return; } - - if (isReachMaxLevel()) { - return; - } - - if (!isReachMaxLevel()) { - _value = _value + 1; - BrnFormUtil.notifyValueChanged( - widget.onChanged, context, _value - 1, _value); - setState(() {}); - } + _checkReachMaxLevel(); }, child: Container( - child: getAddIcon(), + child: _getAddIcon(), ), ), ], @@ -213,45 +214,126 @@ class BrnStepInputFormItemState extends State { ); } - bool isEnable() { - return widget.isEdit; - } - - Image getAddIcon() { + Image _getAddIcon() { if (!widget.isEdit) { return BrunoTools.getAssetImage(BrnAsset.iconAddDisable); } - if (isReachMaxLevel()) { + if (_isReachMaxLevel()) { return BrunoTools.getAssetImage(BrnAsset.iconAddDisable); } return BrunoTools.getAssetImage(BrnAsset.iconAddEnable); } - bool isReachMaxLevel() { + bool _isReachMaxLevel() { if (_value >= widget.maxLimit) { return true; } return false; } - Image getMinusIcon() { + Image _getMinusIcon() { if (!widget.isEdit) { return BrunoTools.getAssetImage(BrnAsset.iconMinusDisable); } - if (isReachMinLevel()) { + if (_isReachMinLevel()) { return BrunoTools.getAssetImage(BrnAsset.iconMinusDisable); } return BrunoTools.getAssetImage(BrnAsset.iconMinusEnable); } - bool isReachMinLevel() { + bool _isReachMinLevel() { if (_value <= widget.minLimit) { return true; } return false; } + + Widget _buildValueWidget() { + if (widget.canManualInput) { + return Container( + alignment: Alignment.center, + width: 50, + child: TextField( + maxLines: 1, + minLines: 1, + enabled: widget.isEdit, + textAlign: TextAlign.center, + controller: _textEditingController, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + RangeLimitedTextInputFormatter(minValue: widget.minLimit, maxValue: widget.maxLimit) + ], + style: TextStyle( + color: Color(0xFF222222), + fontSize: BrnFonts.f16, + ), + decoration: InputDecoration( + hintText: '0', + hintStyle: TextStyle( + color: Color(0xFFCCCCCC), + fontSize: BrnFonts.f16, + ), + border: InputBorder.none, + contentPadding: EdgeInsets.all(0), + isDense: true, + ), + ), + ); + } else { + return Container( + alignment: Alignment.center, + width: 50, + child: Text( + "$_value", + style: TextStyle( + color: Color(0xFF222222), + fontSize: BrnFonts.f16, + ), + ), + ); + } + } + + void _checkReachMinLevel() { + if (!_isReachMinLevel()) { + _value = _value - 1; + return; + } + } + + void _checkReachMaxLevel() { + if (!_isReachMaxLevel()) { + _value = _value + 1; + return; + } + } + + int get _value => int.tryParse(_textEditingController.text) ?? 0; + + set _value(int value) { + _textEditingController.text = value.toString(); + } +} + +class RangeLimitedTextInputFormatter extends TextInputFormatter { + int minValue; + int maxValue; + + RangeLimitedTextInputFormatter({this.minValue = 0, this.maxValue = 0}); + + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + int? newNum = int.tryParse(newValue.text); + if(newNum == null && minValue == 0) { + return TextEditingValue(text: ''); + } else if (newNum != null && minValue <= newNum && newNum <= maxValue) { + return TextEditingValue(text: newNum.toString()); + } else { + return oldValue; + } + } } diff --git a/lib/src/components/form/items/general/brn_text_block_input_item.dart b/lib/src/components/form/items/general/brn_text_block_input_item.dart index a2ec5da3..210a2615 100644 --- a/lib/src/components/form/items/general/brn_text_block_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_block_input_item.dart @@ -66,6 +66,9 @@ class BrnTextBlockInputFormItem extends StatefulWidget { /// 输入内容类型 final String? inputType; + /// 是否自动获取焦点 + bool autofocus; + /// 指定对输入数据的格式化要求 final List? inputFormatters; @@ -100,6 +103,7 @@ class BrnTextBlockInputFormItem extends StatefulWidget { this.onChanged, this.hint = "请输入", this.maxCharCount, + this.autofocus: false, this.inputType, this.inputFormatters, this.controller, @@ -176,6 +180,7 @@ class BrnTextBlockInputFormItemState extends State { Container( padding: BrnFormUtil.errorEdgeInsets(widget.themeData!), child: TextField( + autofocus: widget.autofocus, keyboardType: BrnFormUtil.getInputType(widget.inputType), controller: _controller, maxLength: widget.maxCharCount, diff --git a/lib/src/components/form/items/general/brn_text_input_item.dart b/lib/src/components/form/items/general/brn_text_input_item.dart index d5580025..f2fde8fd 100644 --- a/lib/src/components/form/items/general/brn_text_input_item.dart +++ b/lib/src/components/form/items/general/brn_text_input_item.dart @@ -71,6 +71,9 @@ class BrnTextInputFormItem extends StatefulWidget { /// 输入内容类型 final String? inputType; + /// 是否自动获取焦点 + bool autofocus; + /// 最大可输入字符数 final int? maxCharCount; final List? inputFormatters; @@ -101,6 +104,7 @@ class BrnTextInputFormItem extends StatefulWidget { this.hint = "请输入", this.unit, this.maxCharCount, + this.autofocus: false, this.inputType, this.inputFormatters, this.onChanged, @@ -174,6 +178,7 @@ class BrnTextInputFormItemState extends State { ), Expanded( child: TextField( + autofocus: widget.autofocus, keyboardType: BrnFormUtil.getInputType(widget.inputType), enabled: widget.isEdit, maxLines: 1, diff --git a/lib/src/components/form/items/general/brn_title_select_input_item.dart b/lib/src/components/form/items/general/brn_title_select_input_item.dart index 4410cb96..ab24bb09 100644 --- a/lib/src/components/form/items/general/brn_title_select_input_item.dart +++ b/lib/src/components/form/items/general/brn_title_select_input_item.dart @@ -74,6 +74,9 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { /// 输入类型 final String inputType; + /// 是否自动获取焦点 + bool autofocus; + /// 选中title索引 final int selectedIndex; @@ -111,6 +114,7 @@ class BrnTitleSelectInputFormItem extends StatefulWidget { this.inputType = BrnInputType.text, this.selectedIndex = -1, this.inputFormatters, + this.autofocus: false, this.onChanged, this.onTitleSelected, this.controller, @@ -284,6 +288,7 @@ class BrnTitleSelectInputFormItemState Widget _buildTextField() { return TextField( + autofocus: widget.autofocus, inputFormatters: widget.inputFormatters, textAlign: TextAlign.end, controller: _controller, diff --git a/lib/src/components/navbar/brn_appbar.dart b/lib/src/components/navbar/brn_appbar.dart index 233f7ccb..6f9b2746 100644 --- a/lib/src/components/navbar/brn_appbar.dart +++ b/lib/src/components/navbar/brn_appbar.dart @@ -136,7 +136,7 @@ class BrnAppBar extends PreferredSize { final VoidCallback? backLeadCallback; /// 是否显示默认的eeeeee分割线,默认显示,可以设置为不显示 - final bool showDefaultBottom; + final bool? showDefaultBottom; final bool showLeadingDivider; final BrnAppBarConfig? themeData; @@ -156,7 +156,7 @@ class BrnAppBar extends PreferredSize { this.titleAlignment = Alignment.center, this.flexibleSpace, this.backLeadCallback, - this.showDefaultBottom = true, + this.showDefaultBottom, this.themeData, this.leadingWidth, this.shadowColor, @@ -233,7 +233,7 @@ class BrnAppBar extends PreferredSize { _defaultConfig = _defaultConfig.merge(BrnAppBarConfig.dark()); } _defaultConfig = _defaultConfig - .merge(BrnAppBarConfig(backgroundColor: this.backgroundColor)); + .merge(BrnAppBarConfig(backgroundColor: this.backgroundColor, showDefaultBottom: this.showDefaultBottom)); _defaultConfig = BrnThemeConfigurator.instance .getConfig(configId: _defaultConfig.configId) @@ -246,9 +246,9 @@ class BrnAppBar extends PreferredSize { return super.build(context); } - PreferredSizeWidget? _buildBarBottom() { + PreferredSizeWidget? _buildBarBottom(BrnAppBarConfig defaultConfig) { if (brightness == null || brightness == Brightness.light) { - if (bottom == null && showDefaultBottom) { + if (bottom == null && defaultConfig.showDefaultBottom) { return BrnBarBottomDivider(); } } @@ -292,7 +292,7 @@ class BrnAppBar extends PreferredSize { elevation: elevation, backgroundColor: _defaultConfig.backgroundColor, actions: _wrapActions(_defaultConfig), - bottom: _buildBarBottom(), + bottom: _buildBarBottom(_defaultConfig), brightness: brightness ?? Brightness.light, toolbarOpacity: toolbarOpacity, bottomOpacity: bottomOpacity, @@ -598,7 +598,7 @@ class _BrnSearchResultAppBar extends StatelessWidget { final bool showLeadingDivider; final Widget? flexibleSpace; final VoidCallback? backLeadCallback; - final bool showDefaultBottom; + final bool? showDefaultBottom; _BrnSearchResultAppBar( {this.appBarConfig, @@ -622,7 +622,11 @@ class _BrnSearchResultAppBar extends StatelessWidget { } _defaultConfig = _defaultConfig - .merge(BrnAppBarConfig(backgroundColor: this.backgroundColor)); + .merge(BrnAppBarConfig( + backgroundColor: this.backgroundColor, + showDefaultBottom: this.showDefaultBottom, + )); + _defaultConfig = BrnThemeConfigurator.instance .getConfig(configId: _defaultConfig.configId) .appBarConfig diff --git a/lib/src/components/picker/brn_multi_picker.dart b/lib/src/components/picker/brn_multi_picker.dart index 46b4c7af..eed332bc 100644 --- a/lib/src/components/picker/brn_multi_picker.dart +++ b/lib/src/components/picker/brn_multi_picker.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/src/components/picker/base/brn_picker.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title.dart'; import 'package:bruno/src/components/picker/base/brn_picker_title_config.dart'; @@ -211,17 +209,14 @@ class _BrnMultiDataPickerState extends State { color: widget.themeData?.backgroundColor, child: Row( mainAxisSize: MainAxisSize.max, - children: widget.pickerTitles != null - ? _pickersWithTitle() - : _pickers())); + children: widget.pickerTitles != null ? _pickersWithTitle() : _pickers())); } List _pickersWithTitle() { List pickersWithTitle = []; for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); - FixedExtentScrollController controller = - FixedExtentScrollController(initialItem: initRow); + FixedExtentScrollController controller = FixedExtentScrollController(initialItem: initRow); widget.controllers.add(controller); if (i >= _selectedIndexList.length) _selectedIndexList.add(0); Widget picker = _configSinglePicker(i); @@ -237,8 +232,7 @@ class _BrnMultiDataPickerState extends State { child: Text( widget.pickerTitles == null ? '' : widget.pickerTitles![i], style: TextStyle( - fontSize: widget.pickerTitleFontSize, - color: widget.pickerTitleColor), + fontSize: widget.pickerTitleFontSize, color: widget.pickerTitleColor), ), ), ), @@ -254,8 +248,7 @@ class _BrnMultiDataPickerState extends State { List pickers = []; for (int i = 0; i < widget.delegate.numberOfComponent(); i++) { int initRow = widget.delegate.initSelectedRowForComponent(i); - FixedExtentScrollController controller = - FixedExtentScrollController(initialItem: initRow); + FixedExtentScrollController controller = FixedExtentScrollController(initialItem: initRow); widget.controllers.add(controller); if (i >= _selectedIndexList.length) _selectedIndexList.add(0); Widget picker = _configSinglePicker(i); @@ -274,27 +267,21 @@ class _BrnMultiDataPickerState extends State { createWidgetList: () { if (widget.createItemWidget != null) { List widgetList = []; - for (int i = 0; - i < widget.delegate.numberOfRowsInComponent(component); - i++) { + for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { bool isSelect = _selectedIndexList[component] == i; widgetList.add(widget.createItemWidget != null - ? widget.createItemWidget!( - isSelect, component, i, _selectedIndexList) + ? widget.createItemWidget!(isSelect, component, i, _selectedIndexList) : Container()); } return widgetList; } else { List list = []; - for (int i = 0; - i < widget.delegate.numberOfRowsInComponent(component); - i++) { + for (int i = 0; i < widget.delegate.numberOfRowsInComponent(component); i++) { list.add(Center( child: Text( widget.delegate.titleForRowInComponent(component, i), style: _selectedIndexList[component] == i - ? widget.themeData!.itemTextSelectedStyle - .generateTextStyle() + ? widget.themeData!.itemTextSelectedStyle.generateTextStyle() : widget.themeData!.itemTextStyle.generateTextStyle(), ), )); @@ -302,21 +289,15 @@ class _BrnMultiDataPickerState extends State { return list; } }, - itemExtent: widget.delegate.rowHeightForComponent(component) ?? - widget.themeData!.itemHeight, + itemExtent: widget.delegate.rowHeightForComponent(component) ?? widget.themeData!.itemHeight, changed: (int index) { widget.delegate.selectRowInComponent(component, index); _selectedIndexList[component] = index; setState(() { - for (int i = component + 1; - i < widget.delegate.numberOfComponent(); - i++) { + for (int i = component + 1; i < widget.delegate.numberOfComponent(); i++) { List list = []; - for (int j = 0; - j < widget.delegate.numberOfRowsInComponent(component); - j++) { - list.add( - widget.delegate.titleForRowInComponent(component, index)); + for (int j = 0; j < widget.delegate.numberOfRowsInComponent(component); j++) { + list.add(widget.delegate.titleForRowInComponent(component, index)); } FixedExtentScrollController controller = widget.controllers[i]; if (widget.sync) { @@ -398,8 +379,130 @@ class _MyPickerState extends State { ///默认的选择轮盘滚动行为,Android去除默认的水波纹动画效果 class _DefaultScrollBehavior extends ScrollBehavior { @override - Widget buildViewportChrome( - BuildContext context, Widget child, AxisDirection axisDirection) { + Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) { return child; } } + +/// 实现了部分默认逻辑的 Delegate +class BrnDefaultMultiDataPickerDelegate implements BrnMultiDataPickerDelegate { + ///数据源 + List data; + + ///第一列选中角标,默认0 + int firstSelectedIndex; + + ///第二列选中角标,默认0 + int secondSelectedIndex; + + ///第三列选中角标,默认0 + int thirdSelectedIndex; + + int _numberOfComponent = 0; + + BrnDefaultMultiDataPickerDelegate( + {required this.data, + this.firstSelectedIndex = 0, + this.secondSelectedIndex = 0, + this.thirdSelectedIndex = 0}) { + if (data.isNotEmpty) { + _numberOfComponent = 1; + for (BrnMultiDataPickerEntity brnPickerItem in data) { + if (brnPickerItem.children.isNotEmpty) { + _numberOfComponent = 2; + + for (BrnMultiDataPickerEntity brnPickerItem1 in brnPickerItem.children) { + if (brnPickerItem1.children.isNotEmpty) { + _numberOfComponent = 3; + } + } + } + } + } + } + + @override + int initSelectedRowForComponent(int component) { + if (0 == component) { + return firstSelectedIndex; + } else if (1 == component) { + return secondSelectedIndex; + } else { + return thirdSelectedIndex; + } + } + + ///显示几列内容 + @override + int numberOfComponent() { + return _numberOfComponent; + } + + @override + int numberOfRowsInComponent(int component) { + if (data.isEmpty) { + return 0; + } + + if (0 == component) { + return data.length; + } else if (1 == component) { + List fl = data[firstSelectedIndex].children; + return fl.length; + } else { + List secondMap = data[firstSelectedIndex].children; + List thirdMap = secondMap[secondSelectedIndex].children; + return thirdMap.length; + } + } + + @override + double rowHeightForComponent(int component) { + return pickerItemHeight; + } + + @override + void selectRowInComponent(int component, int row) { + if (0 == component) { + firstSelectedIndex = row; + } else if (1 == component) { + secondSelectedIndex = row; + } else { + thirdSelectedIndex = row; + } + } + + @override + String titleForRowInComponent(int component, int index) { + if (0 == component) { + return data[index].text; + } else if (1 == component) { + BrnMultiDataPickerEntity brnPickerItem = data[firstSelectedIndex]; + List secondList = brnPickerItem.children; + return secondList[index].text; + } else { + BrnMultiDataPickerEntity brnPickerItem = data[firstSelectedIndex]; + List secondList = brnPickerItem.children; + List threeList = secondList[secondSelectedIndex].children; + return threeList[index].text; + } + } +} + +/// 适用于 BrnDefaultMultiDataPickerDelegate 的数据类 +class BrnMultiDataPickerEntity { + /// 显示内容 + final String text; + + /// 数据值 + final dynamic value; + + /// 子项 + final List children; + + BrnMultiDataPickerEntity({ + required this.text, + this.value, + this.children = const [], + }); +} diff --git a/lib/src/components/radio/brn_checkbox.dart b/lib/src/components/radio/brn_checkbox.dart index ae1f216c..98a1e597 100644 --- a/lib/src/components/radio/brn_checkbox.dart +++ b/lib/src/components/radio/brn_checkbox.dart @@ -36,6 +36,10 @@ class BrnCheckbox extends StatefulWidget { /// 默认值MainAxisAlignment.start final MainAxisAlignment mainAxisAlignment; + /// 控件和选择按钮在row布局里面的crossAxisAlignment + /// 默认值CrossAxisAlignment.center + final CrossAxisAlignment crossAxisAlignment; + /// 控件和选择按钮在row布局里面的mainAxisSize /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; @@ -53,6 +57,7 @@ class BrnCheckbox extends StatefulWidget { this.child, this.childOnRight = true, this.mainAxisAlignment = MainAxisAlignment.start, + this.crossAxisAlignment = CrossAxisAlignment.center, this.mainAxisSize = MainAxisSize.min, this.behavior = HitTestBehavior.translucent}); @@ -80,6 +85,7 @@ class BrnCheckboxState extends State { iconPadding: widget.iconPadding, childOnRight: widget.childOnRight, mainAxisAlignment: widget.mainAxisAlignment, + crossAxisAlignment: widget.crossAxisAlignment, mainAxisSize: widget.mainAxisSize, selectedImage: BrunoTools.getAssetImageWithBandColor( BrnAsset.iconRadioMultiSelected), diff --git a/lib/src/components/radio/brn_radio_button.dart b/lib/src/components/radio/brn_radio_button.dart index 44c93e20..071f229b 100644 --- a/lib/src/components/radio/brn_radio_button.dart +++ b/lib/src/components/radio/brn_radio_button.dart @@ -36,6 +36,10 @@ class BrnRadioButton extends StatelessWidget { /// 默认值MainAxisAlignment.start final MainAxisAlignment mainAxisAlignment; + /// 控件和选择按钮在row布局里面的crossAxisAlignment + /// 默认值CrossAxisAlignment.center + final CrossAxisAlignment crossAxisAlignment; + /// 控件和选择按钮在row布局里面的mainAxisSize /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; @@ -53,6 +57,7 @@ class BrnRadioButton extends StatelessWidget { this.child, this.childOnRight = true, this.mainAxisAlignment = MainAxisAlignment.start, + this.crossAxisAlignment = CrossAxisAlignment.center, this.mainAxisSize = MainAxisSize.min, this.behavior = HitTestBehavior.translucent}); @@ -65,6 +70,7 @@ class BrnRadioButton extends StatelessWidget { iconPadding: iconPadding, childOnRight: childOnRight, mainAxisAlignment: mainAxisAlignment, + crossAxisAlignment: crossAxisAlignment, mainAxisSize: mainAxisSize, selectedImage: BrunoTools.getAssetImageWithBandColor( BrnAsset.iconRadioSingleSelected), diff --git a/lib/src/components/radio/brn_radio_core.dart b/lib/src/components/radio/brn_radio_core.dart index 2d0af1e0..c4545f90 100644 --- a/lib/src/components/radio/brn_radio_core.dart +++ b/lib/src/components/radio/brn_radio_core.dart @@ -35,6 +35,10 @@ class BrnRadioCore extends StatefulWidget { /// 默认值MainAxisAlignment.start final MainAxisAlignment mainAxisAlignment; + /// 控件和选择按钮在row布局里面的crossAxisAlignment + /// 默认值CrossAxisAlignment.center + final CrossAxisAlignment crossAxisAlignment; + /// 控件和选择按钮在row布局里面的mainAxisSize /// 默认值MainAxisSize.min final MainAxisSize mainAxisSize; @@ -61,6 +65,7 @@ class BrnRadioCore extends StatefulWidget { this.child, this.childOnRight = true, this.mainAxisAlignment = MainAxisAlignment.start, + this.crossAxisAlignment = CrossAxisAlignment.center, this.mainAxisSize = MainAxisSize.min, this.selectedImage, this.unselectedImage, @@ -129,6 +134,7 @@ class _BrnRadioCoreState extends State { radioWidget = Row( mainAxisSize: widget.mainAxisSize, mainAxisAlignment: widget.mainAxisAlignment, + crossAxisAlignment: widget.crossAxisAlignment, children: list, ); } diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 35b96e3a..53fa92c4 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -1,16 +1,15 @@ import 'dart:async'; +import 'package:bruno/src/components/popup/brn_measure_size.dart'; import 'package:bruno/src/components/tabbar/normal/brn_tab_bar.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; /// 构建指定索引的Widget -typedef AnchorTabWidgetIndexedBuilder = Widget Function( - BuildContext context, int index); +typedef AnchorTabWidgetIndexedBuilder = Widget Function(BuildContext context, int index); /// 构建指定索引的Tab -typedef AnchorTabIndexedBuilder = BadgeTab Function( - BuildContext context, int index); +typedef AnchorTabIndexedBuilder = BadgeTab Function(BuildContext context, int index); class BrnAnchorTab extends StatefulWidget { // TabBar的样式 @@ -30,8 +29,7 @@ class BrnAnchorTab extends StatefulWidget { this.tabBarStyle = const BrnAnchorTabBarStyle()}); @override - _BrnScrollAnchorTabWidgetState createState() => - _BrnScrollAnchorTabWidgetState(); + _BrnScrollAnchorTabWidgetState createState() => _BrnScrollAnchorTabWidgetState(); } class _BrnScrollAnchorTabWidgetState extends State @@ -39,9 +37,6 @@ class _BrnScrollAnchorTabWidgetState extends State //用于控制 滑动 late ScrollController _scrollController; - //用于 滑动 和 tab 之间的通信 - late StreamController _streamController; - //用于控制tab late TabController _tabController; @@ -51,18 +46,12 @@ class _BrnScrollAnchorTabWidgetState extends State //当前选中的索引 int currentIndex = 0; - //滑动组件的元素、 - late List _bodyWidgetList; - //滑动组件的元素的key late List _bodyKeyList; //每个元素在滑动组件中的位置 late List _cardOffsetList; - //tab - late List _tabList; - //是否点击滑动 bool tab = false; @@ -71,32 +60,48 @@ class _BrnScrollAnchorTabWidgetState extends State @override void initState() { - _streamController = StreamController(); + super.initState(); _scrollController = ScrollController(); _key = GlobalKey(); _cardOffsetList = List.filled(widget.itemCount, -1.0); - _bodyWidgetList = []; _bodyKeyList = []; - _tabList = []; - + currentIndex = 0; _tabController = TabController(length: widget.itemCount, vsync: this); fillKeyList(); - fillList(); - fillTab(); - WidgetsBinding.instance!.addPostFrameCallback((da) { + WidgetsBinding.instance?.addPostFrameCallback((da) { fillOffset(); _scrollController.addListener(() { - updateOffset(); + _updateOffset(); currentIndex = createIndex(_scrollController.offset); //防止再次 发送消息 - if (!tab) _streamController.add(currentIndex); + if (!tab) { + _tabController.index = currentIndex; + } }); }); + } - super.initState(); + @override + void didUpdateWidget(BrnAnchorTab oldWidget) { + super.didUpdateWidget(oldWidget); + _cardOffsetList = List.filled(widget.itemCount, -1.0); + int sub = widget.itemCount - oldWidget.itemCount; + if (sub < 0) { + _bodyKeyList = _bodyKeyList.sublist(0, widget.itemCount); + } else if (sub > 0) { + for (int i = 0; i < sub; i++) { + _bodyKeyList.add(GlobalKey()); + } + } + if (sub != 0) { + _tabController = TabController(length: widget.itemCount, vsync: this); + } + WidgetsBinding.instance?.addPostFrameCallback((da) { + fillOffset(); + }); } @override @@ -104,48 +109,36 @@ class _BrnScrollAnchorTabWidgetState extends State return Column( mainAxisSize: MainAxisSize.min, children: [ - StreamBuilder( - initialData: currentIndex, - stream: _streamController.stream, - builder: (context, snap) { - _tabController.index = currentIndex; - return BrnTabBar( - indicatorColor: widget.tabBarStyle.indicatorColor, - indicatorWeight: widget.tabBarStyle.indicatorWeight, - indicatorPadding: widget.tabBarStyle.indicatorPadding, - labelColor: widget.tabBarStyle.labelColor, - labelStyle: widget.tabBarStyle.labelStyle, - labelPadding: widget.tabBarStyle.labelPadding ?? EdgeInsets.zero, - unselectedLabelColor: widget.tabBarStyle.unselectedLabelColor, - unselectedLabelStyle: widget.tabBarStyle.unselectedLabelStyle, - dragStartBehavior: widget.tabBarStyle.dragStartBehavior, - controller: _tabController, - tabs: _tabList, - onTap: (state, index) { - state.refreshBadgeState(index); - currentIndex = index; - tab = true; - _scrollController - .animateTo(_cardOffsetList[index], - duration: Duration(milliseconds: 100), - curve: Curves.linear) - .whenComplete(() { - tab = false; - }); - }, - ); + BrnTabBar( + indicatorColor: widget.tabBarStyle.indicatorColor, + indicatorWeight: widget.tabBarStyle.indicatorWeight, + indicatorPadding: widget.tabBarStyle.indicatorPadding, + labelColor: widget.tabBarStyle.labelColor, + labelStyle: widget.tabBarStyle.labelStyle, + labelPadding: widget.tabBarStyle.labelPadding ?? EdgeInsets.zero, + unselectedLabelColor: widget.tabBarStyle.unselectedLabelColor, + unselectedLabelStyle: widget.tabBarStyle.unselectedLabelStyle, + dragStartBehavior: widget.tabBarStyle.dragStartBehavior, + controller: _tabController, + tabs: _fillTab(), + onTap: (state, index) { + state.refreshBadgeState(index); + currentIndex = index; + tab = true; + _scrollController + .animateTo(_cardOffsetList[index], + duration: Duration(milliseconds: 100), curve: Curves.linear) + .whenComplete(() { + tab = false; + }); }, ), - widget.tabDivider ?? - Container( - height: 0, - width: 0, - ), + widget.tabDivider ?? SizedBox.shrink(), Expanded( child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, - children: _bodyWidgetList, + children: _fillList(), ), key: _key, controller: _scrollController, @@ -155,14 +148,22 @@ class _BrnScrollAnchorTabWidgetState extends State ); } - void fillList() { - for (int i = 0, n = widget.itemCount; i < n; i++) { - _bodyWidgetList.add( - Container( - key: _bodyKeyList[i], - child: widget.widgetIndexedBuilder(context, i)), - ); + List _fillList() { + List tmpWidget = []; + if (widget.widgetIndexedBuilder != null) { + for (int i = 0, n = widget.itemCount; i < n; i++) { + Widget itemWidget = + Container(key: _bodyKeyList[i], child: widget.widgetIndexedBuilder(context, i)); + itemWidget = MeasureSize( + onChange: (size) { + _updateOffset(); + }, + child: itemWidget, + ); + tmpWidget.add(itemWidget); + } } + return tmpWidget; } void fillKeyList() { @@ -173,49 +174,44 @@ class _BrnScrollAnchorTabWidgetState extends State void fillOffset() { Offset globalToLocal = - (_key.currentContext!.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero); + (_key.currentContext!.findRenderObject() as RenderBox).localToGlobal(Offset.zero); listDy = globalToLocal.dy; for (int i = 0, n = widget.itemCount; i < n; i++) { - if (_cardOffsetList[i] == -1.0) { - if (_bodyKeyList[i].currentContext != null) { - double cardOffset = - (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 - - _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; - } + if (_cardOffsetList[i] == -1.0 && _bodyKeyList[i].currentContext != null) { + double cardOffset = (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 + + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; } } } - void fillTab() { + List _fillTab() { + List tmp = []; for (int i = 0, n = widget.itemCount; i < n; i++) { - _tabList.add(widget.tabIndexedBuilder(context, i)); + tmp.add(widget.tabIndexedBuilder(context, i)); } + return tmp; } - void updateOffset() { + void _updateOffset() { for (int i = 0, n = widget.itemCount; i < n; i++) { - if (_cardOffsetList[i] == -1.0) { - if (_bodyKeyList[i].currentContext != null) { - double cardOffset = - (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) - .localToGlobal(Offset.zero) //相对于原点 控件的位置 - .dy; //y点坐标 - - _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; - } + if (_bodyKeyList[i].currentContext != null) { + double cardOffset = (_bodyKeyList[i].currentContext!.findRenderObject() as RenderBox) + .localToGlobal(Offset.zero) //相对于原点 控件的位置 + .dy; //y点坐标 + + _cardOffsetList[i] = cardOffset + _scrollController.offset - listDy; } } } //根据偏移量 确定tab索引 int createIndex(double offset) { - int index = 0; - for (int i = 0, n = widget.itemCount; i < n; i++) { + int index = widget.itemCount - 1;; + for (int i = 0; i < widget.itemCount - 1; i++) { if (offset >= _cardOffsetList[i] && (offset <= _cardOffsetList[i + 1])) { return i; } @@ -227,7 +223,6 @@ class _BrnScrollAnchorTabWidgetState extends State void dispose() { super.dispose(); _tabController.dispose(); - _streamController.close(); _scrollController.dispose(); } } diff --git a/lib/src/components/selection/bean/brn_selection_common_entity.dart b/lib/src/components/selection/bean/brn_selection_common_entity.dart index 48e6ab4c..1b71d5ac 100644 --- a/lib/src/components/selection/bean/brn_selection_common_entity.dart +++ b/lib/src/components/selection/bean/brn_selection_common_entity.dart @@ -521,11 +521,11 @@ class BrnSelectionEntity { /// 接口返回默认展示tag个数 int getDefaultShowCount() { - int defaultCount = 3; + int defaultShowCount = 3; if (extMap.containsKey('defaultShowCount')) { - defaultCount = extMap['defaultShowCount'] ?? 3; + defaultShowCount = extMap['defaultShowCount'] ?? defaultShowCount; } - return defaultCount; + return defaultShowCount; } List currentRangeListForEntity() { diff --git a/lib/src/components/selection/brn_more_selection.dart b/lib/src/components/selection/brn_more_selection.dart index b07f6ee0..81165709 100644 --- a/lib/src/components/selection/brn_more_selection.dart +++ b/lib/src/components/selection/brn_more_selection.dart @@ -94,7 +94,7 @@ class _BrnMoreSelectionPageState extends State ), //为了解决 键盘抬起按钮的问题 将按钮移动到 此区域 bottomNavigationBar: Container( - height: 80, + height: 80 + _getBottomAreaHeight(), child: Row( children: [ _buildLeftSlide(context), @@ -266,6 +266,10 @@ class _BrnMoreSelectionPageState extends State }); } } + + double _getBottomAreaHeight() { + return MediaQuery.of(context).padding.bottom; + } } /// 底部的重置+确定 diff --git a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart index 949514ce..bac2587a 100644 --- a/lib/src/components/selection/widget/brn_layer_more_selection_page.dart +++ b/lib/src/components/selection/widget/brn_layer_more_selection_page.dart @@ -133,6 +133,7 @@ class _BrnLayerMoreSelectionPageState extends State .colorTextBase, ), onPressed: () { + BrnSelectionUtil.resetSelectionDatas(widget.entityData); //将选中的筛选项返回 _originalSelectedItemsList.forEach((data) { data.isSelected = true; @@ -340,6 +341,8 @@ class _BrnLayerMoreSelectionPageState extends State padding: const EdgeInsets.only(left: 20), child: Text( name, + maxLines: 2, + overflow: TextOverflow.ellipsis, style: textStyle, ), ), @@ -428,7 +431,7 @@ class _BrnLayerMoreSelectionPageState extends State Widget _buildRightMultiItem(BrnSelectionEntity? entity) { if (entity == null) { - return SizedBox.shrink(); + return const SizedBox.shrink(); } else { return Row( children: [ @@ -455,7 +458,7 @@ class _BrnLayerMoreSelectionPageState extends State Widget _buildRightSingleItem(BrnSelectionEntity? entity) { if (entity == null) { - return SizedBox.shrink(); + return const SizedBox.shrink(); } else { return Text(entity.title, textAlign: TextAlign.left, diff --git a/lib/src/components/sugsearch/brn_search_text.dart b/lib/src/components/sugsearch/brn_search_text.dart index 1efe3253..343a2f1d 100644 --- a/lib/src/components/sugsearch/brn_search_text.dart +++ b/lib/src/components/sugsearch/brn_search_text.dart @@ -2,6 +2,7 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; /// 搜索框内容变化回调 typedef BrnOnSearchTextChange = void Function(String content); @@ -61,6 +62,11 @@ class BrnSearchText extends StatefulWidget { /// 用于控制键盘动作 final TextInputAction? textInputAction; + + final TextInputType? textInputType; + + final List? inputFormatters; + final TextEditingController? controller; final FocusNode? focusNode; @@ -107,6 +113,8 @@ class BrnSearchText extends StatefulWidget { this.focusNode, this.autoFocus = false, this.textInputAction, + this.inputFormatters, + this.textInputType, }) : super(key: key); @override @@ -201,16 +209,14 @@ class _SearchTextState extends State { autofocus: widget.autoFocus, textInputAction: this.widget.textInputAction, focusNode: focusNode, - // 控制器属性,控制正在编辑的文本。 controller: textEditingController, - // 光标颜色属性,绘制光标时使用的颜色。 + keyboardType: widget.textInputType, + inputFormatters: widget.inputFormatters, cursorColor: BrnThemeConfigurator.instance .getConfig() .commonConfig .brandPrimary, - // 光标宽度属性,光标的厚度,默认是2.0。 cursorWidth: 2.0, - // 样式属性,用于正在编辑的文本的样式。 style: widget.textStyle ?? TextStyle( textBaseline: TextBaseline.alphabetic, @@ -219,18 +225,14 @@ class _SearchTextState extends State { .commonConfig .colorTextBase, fontSize: 16), - // 装饰(`decoration`)属性,在文本字段周围显示的装饰。 decoration: InputDecoration( - // 边框属性,装饰的容器周围绘制的形状。 border: InputBorder.none, contentPadding: EdgeInsets.only(left: 8, right: 6), // 填充颜色属性,填充装饰容器的颜色。 fillColor: widget.innerColor, // 是密集属性,输入子项是否是密集形式的一部分(即使用较少的垂直空间)。 isDense: true, - // 填充属性,如果为`true`,则装饰的容器将填充fillColor颜色。 filled: true, - // 提示样式属性,用于提示文本(`hintText`)的样式。 hintStyle: widget.hintStyle ?? TextStyle( fontSize: 16, @@ -238,9 +240,7 @@ class _SearchTextState extends State { textBaseline: TextBaseline.alphabetic, color: Color(0xff999999), ), - // 提示文本属性,提示字段接受哪种输入的文本。 hintText: widget.hintText ?? "请输入搜索内容", - // 不显示计数面板 counterText: '', ), // 在改变属性,当正在编辑的文本发生更改时调用。 diff --git a/lib/src/components/tag/tagview/brn_delete_tag.dart b/lib/src/components/tag/tagview/brn_delete_tag.dart index 37a72a20..8f58885b 100644 --- a/lib/src/components/tag/tagview/brn_delete_tag.dart +++ b/lib/src/components/tag/tagview/brn_delete_tag.dart @@ -107,7 +107,7 @@ class _BrnDeleteTagState extends State { /// 根据标签集合构建标签 UI Widget _buildContent(List tags) { if (tags.isEmpty) { - return SizedBox.shrink(); + return const SizedBox.shrink(); } List itemList = []; diff --git a/lib/src/theme/base/brn_default_config_utils.dart b/lib/src/theme/base/brn_default_config_utils.dart index fd63dc05..f5a63dc3 100644 --- a/lib/src/theme/base/brn_default_config_utils.dart +++ b/lib/src/theme/base/brn_default_config_utils.dart @@ -424,6 +424,7 @@ class BrnDefaultConfigUtils { iconSize: BrnAppBarTheme.iconSize, configId: BRUNO_CONFIG_ID, systemUiOverlayStyle: SystemUiOverlayStyle.dark, + showDefaultBottom: false, ); /// 内容信息(两列)配置 diff --git a/lib/src/theme/configs/brn_appbar_config.dart b/lib/src/theme/configs/brn_appbar_config.dart index 5249b3cb..e5d2ee05 100644 --- a/lib/src/theme/configs/brn_appbar_config.dart +++ b/lib/src/theme/configs/brn_appbar_config.dart @@ -27,6 +27,7 @@ class BrnAppBarConfig extends BrnBaseConfig { EdgeInsets? titlePadding, double? iconSize, SystemUiOverlayStyle? systemUiOverlayStyle, + bool? showDefaultBottom, String configId = GLOBAL_CONFIG_ID, }) : _backgroundColor = backgroundColor, _appBarHeight = appBarHeight, @@ -39,6 +40,7 @@ class BrnAppBarConfig extends BrnBaseConfig { _titlePadding = titlePadding, _iconSize = iconSize, _systemUiOverlayStyle = systemUiOverlayStyle, + _showDefaultBottom = showDefaultBottom, super(configId: configId); BrnAppBarConfig.dark({ @@ -196,6 +198,14 @@ class BrnAppBarConfig extends BrnBaseConfig { _systemUiOverlayStyle ?? BrnDefaultConfigUtils.defaultAppBarConfig.systemUiOverlayStyle; + /// 是否展示Appbar bottom 分割线 + /// 默认为 [false] + bool? _showDefaultBottom; + + bool get showDefaultBottom => + _showDefaultBottom ?? + BrnDefaultConfigUtils.defaultAppBarConfig.showDefaultBottom; + @override void initThemeConfig( String configId, { @@ -222,6 +232,7 @@ class BrnAppBarConfig extends BrnBaseConfig { _titlePadding ??= appbarConfig._titlePadding; _iconSize ??= appbarConfig._iconSize; _systemUiOverlayStyle ??= appbarConfig._systemUiOverlayStyle; + _showDefaultBottom ??= appbarConfig._showDefaultBottom; } BrnAppBarConfig copyWith({ @@ -236,6 +247,7 @@ class BrnAppBarConfig extends BrnBaseConfig { EdgeInsets? titlePadding, double? iconSize, SystemUiOverlayStyle? systemUiOverlayStyle, + bool? showDefaultBottom, }) { return BrnAppBarConfig( backgroundColor: backgroundColor ?? _backgroundColor, @@ -249,6 +261,7 @@ class BrnAppBarConfig extends BrnBaseConfig { titlePadding: titlePadding ?? _titlePadding, iconSize: iconSize ?? _iconSize, systemUiOverlayStyle: systemUiOverlayStyle ?? _systemUiOverlayStyle, + showDefaultBottom: showDefaultBottom ?? _showDefaultBottom, ); } @@ -266,6 +279,7 @@ class BrnAppBarConfig extends BrnBaseConfig { titlePadding: other._titlePadding, iconSize: other._iconSize, systemUiOverlayStyle: other._systemUiOverlayStyle, + showDefaultBottom: other._showDefaultBottom, ); } } From 9c5612e8a005d84c85e8b74d4c45cca4282e77ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=87=91=E5=B1=B1?= <1919437986@qq.com> Date: Fri, 29 Apr 2022 10:32:23 +0800 Subject: [PATCH 14/19] opt: expand bottomNavigationTile click area, not only the icon and label. (#202) --- lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart index ad706fe6..948f903b 100644 --- a/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart +++ b/lib/src/components/tabbar/bottom/brn_bottom_tab_bar_main.dart @@ -576,6 +576,7 @@ class _BottomNavigationTile extends StatelessWidget { } return GestureDetector( onTap: onTap, + behavior: HitTestBehavior.opaque, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, From 3454832c8e35322c3dda3eae68f75f05befefe5f Mon Sep 17 00:00:00 2001 From: Morale Date: Fri, 29 Apr 2022 11:32:48 +0800 Subject: [PATCH 15/19] Adapt to flutter 2.10.5 (#203) Fix a compile error caused by a generic definition --- .../brn_selected_list_action_sheet.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index 62a877e8..d8eeca9b 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -6,8 +6,8 @@ import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/utils/brn_tools.dart'; import 'package:flutter/material.dart'; -typedef BrnItemTitleBuilder = dynamic Function(int index, T entity); -typedef BrnItemDeleteCallback = bool Function(int deleteIdx, T deleteEntity); +typedef BrnItemTitleBuilder = dynamic Function(int index, T entity); +typedef BrnItemDeleteCallback = bool Function(int deleteIdx, T deleteEntity); typedef BrnListDismissCallback = void Function(bool isClosedByClearButton); @@ -165,10 +165,10 @@ class BrnSelectedListActionSheet { if (_overlayEntry != null) { return; } - BrnSelectedListActionSheetController? tempCcontroller = controller; - if (tempCcontroller == null) { - tempCcontroller = BrnSelectedListActionSheetController(); - tempCcontroller._isHidden = false; + BrnSelectedListActionSheetController? tempController = controller; + if (tempController == null) { + tempController = BrnSelectedListActionSheetController(); + tempController._isHidden = false; } _BrnActionSheetSelectedItemListContentWidget content = _BrnActionSheetSelectedItemListContentWidget( @@ -178,7 +178,7 @@ class BrnSelectedListActionSheet { }, itemTitleBuilder: this.itemTitleBuilder, onItemDelete: this.onItemDelete, - controller: tempCcontroller, + controller: tempController, ); content._overlayState = Overlay.of(context); OverlayEntry overlayEntry = OverlayEntry(builder: (context) { From 1c1949ac1e399ad3f8b24d75f3d1747397279dec Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Fri, 29 Apr 2022 12:23:03 +0800 Subject: [PATCH 16/19] =?UTF-8?q?1.add=20BrnSwitchFormItem=E3=80=81BrnGene?= =?UTF-8?q?ralFormItem=E3=80=81BrnMetaSwitch=20(#198)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1.add BrnSwitchFormItem、BrnGeneralFormItem、BrnMetaSwitch * sync doc delete 'mate' * fix issue #199 * delete invail annotation * 同步 BrnBaseSwitchButton 代码 * fix error function * fix BrnSelectedListActionSheet delete error --- .../dashedLine/BrnDashedLine/BrnDashedLine.md | 8 +- .../BrnGeneralFormItem/BrnGeneralFormItem.md | 148 ++++++++++++ .../img/BrnGeneralFormItem1.png | Bin 0 -> 19374 bytes .../img/BrnGeneralFormItem2.png | Bin 0 -> 38331 bytes .../form/BrnStarsFormItem/BrnStarsFormItem.md | 8 +- .../BrnStepInputFormItem.md | 8 +- .../BrnSwitchFormItem/BrnSwitchFormItem.md | 142 ++++++++++++ .../BrnSwitchFormItem/img/BrnSwitchItem1.png | Bin 0 -> 17592 bytes .../BrnSwitchFormItem/img/BrnSwitchItem2.png | Bin 0 -> 38495 bytes .../BrnTextInputFormItem.md | 8 +- .../BrnBigMainButton/BrnBigMainButton.md | 2 +- .../BrnHorizontalSteps/BrnHorizontalSteps.md | 4 +- ...ntalSteps1.jpg => BrnHorizontalSteps1.jpg} | Bin ...ntalSteps2.jpg => BrnHorizontalSteps2.jpg} | Bin ...ntalSteps3.jpg => BrnHorizontalSteps3.jpg} | Bin ...ntalSteps4.jpg => BrnHorizontalSteps4.jpg} | Bin ...ntalSteps5.png => BrnHorizontalSteps5.png} | Bin .../switchButton/BrnSwitchButton.md | 91 ++++++++ .../img/BrnSwitchButtonDisable.png | Bin 0 -> 2793 bytes .../img/BrnSwitchButtonExample.png | Bin 0 -> 49358 bytes .../switchButton/img/BrnSwitchButtonNomal.png | Bin 0 -> 3212 bytes .../img/BrnSwitchButtonOffDisable.png | Bin 0 -> 3254 bytes .../switchButton/img/BrnSwitchButtonSize.png | Bin 0 -> 5757 bytes .../img/BrnSwitchButtonUnSelect.png | Bin 0 -> 3212 bytes doc/components/tag/BrnStateTag/BrnStateTag.md | 4 +- ...StateTagIntro.png => BrnStateTagIntro.png} | Bin ...eTagSucceed.png => BrnStateTagSucceed.png} | Bin .../tag/BrnTagCustom/BrnTagCustom.md | 2 +- .../BrnEnhanceNumberCard.md | 12 +- .../BrnCommonCardTitle/BrnCommonCardTitle.md | 23 +- .../actionsheet_selected_list_example.dart | 2 +- .../card_title/brn_common_title_example.dart | 5 + .../form/all_item_style_example.dart | 58 +++-- .../items_example/general_item_example.dart | 101 ++++++++ .../form/items_example/switch_example.dart | 134 +++++++++++ .../components/switch/brn_switch_example.dart | 134 +++++++++++ example/lib/sample/home/card_data_config.dart | 12 + lib/bruno.dart | 5 + .../brn_selected_list_action_sheet.dart | 4 +- .../content_card/brn_pair_info_table.dart | 18 +- .../dialog/brn_middle_input_diaolg.dart | 1 - .../dialog/brn_multi_select_dialog.dart | 1 - .../form/base/brn_form_item_type.dart | 1 + .../form/items/general/brn_switch_item.dart | 210 +++++++++++++++++ .../form/items/misc/brn_general_item.dart | 216 ++++++++++++++++++ .../scroll_anchor/brn_scroll_anchor_tab.dart | 6 +- .../components/switch/brn_switch_button.dart | 75 ++++++ .../switch/brn_switch_button_base.dart | 93 ++++++++ 48 files changed, 1467 insertions(+), 69 deletions(-) create mode 100644 doc/components/form/BrnGeneralFormItem/BrnGeneralFormItem.md create mode 100644 doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem1.png create mode 100644 doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem2.png create mode 100644 doc/components/form/BrnSwitchFormItem/BrnSwitchFormItem.md create mode 100644 doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem1.png create mode 100644 doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem2.png rename doc/components/stepBar/BrnHorizontalSteps/img/{BrnMetaHorizontalSteps1.jpg => BrnHorizontalSteps1.jpg} (100%) rename doc/components/stepBar/BrnHorizontalSteps/img/{BrnMetaHorizontalSteps2.jpg => BrnHorizontalSteps2.jpg} (100%) rename doc/components/stepBar/BrnHorizontalSteps/img/{BrnMetaHorizontalSteps3.jpg => BrnHorizontalSteps3.jpg} (100%) rename doc/components/stepBar/BrnHorizontalSteps/img/{BrnMetaHorizontalSteps4.jpg => BrnHorizontalSteps4.jpg} (100%) rename doc/components/stepBar/BrnHorizontalSteps/img/{BrnMetaHorizontalSteps5.png => BrnHorizontalSteps5.png} (100%) create mode 100644 doc/components/switchButton/BrnSwitchButton.md create mode 100644 doc/components/switchButton/img/BrnSwitchButtonDisable.png create mode 100644 doc/components/switchButton/img/BrnSwitchButtonExample.png create mode 100644 doc/components/switchButton/img/BrnSwitchButtonNomal.png create mode 100644 doc/components/switchButton/img/BrnSwitchButtonOffDisable.png create mode 100644 doc/components/switchButton/img/BrnSwitchButtonSize.png create mode 100644 doc/components/switchButton/img/BrnSwitchButtonUnSelect.png rename doc/components/tag/BrnStateTag/img/{BrnMetaStateTagIntro.png => BrnStateTagIntro.png} (100%) rename doc/components/tag/BrnStateTag/img/{BrnMetaStateTagSucceed.png => BrnStateTagSucceed.png} (100%) create mode 100644 example/lib/sample/components/form/items_example/general_item_example.dart create mode 100644 example/lib/sample/components/form/items_example/switch_example.dart create mode 100644 example/lib/sample/components/switch/brn_switch_example.dart create mode 100644 lib/src/components/form/items/general/brn_switch_item.dart create mode 100644 lib/src/components/form/items/misc/brn_general_item.dart create mode 100644 lib/src/components/switch/brn_switch_button.dart create mode 100644 lib/src/components/switch/brn_switch_button_base.dart diff --git a/doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md b/doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md index 6850c05c..307ef692 100644 --- a/doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md +++ b/doc/components/dashedLine/BrnDashedLine/BrnDashedLine.md @@ -28,7 +28,7 @@ group: ```dart -BrnMetaDashedLine({ +BrnDashedLine({ Key key, @required this.contentWidget, this.axis, @@ -61,7 +61,7 @@ BrnMetaDashedLine({ ```dart // 内部有内容 -BrnMetaDashedLine( +BrnDashedLine( dashedLength: 20, dashedThickness: 5, axis: Axis.vertical, @@ -81,7 +81,7 @@ BrnMetaDashedLine( ```dart // 内部没有内容 -BrnMetaDashedLine( +BrnDashedLine( dashedLength: 10, dashedThickness: 3, axis: Axis.horizontal, @@ -106,7 +106,7 @@ Container( width: 300, padding: EdgeInsets.all(5), color: Colors.red, - child: BrnMetaDashedLine( + child: BrnDashedLine( axis: Axis.horizontal, dashedOffset: 10, ), diff --git a/doc/components/form/BrnGeneralFormItem/BrnGeneralFormItem.md b/doc/components/form/BrnGeneralFormItem/BrnGeneralFormItem.md new file mode 100644 index 00000000..2b94edcb --- /dev/null +++ b/doc/components/form/BrnGeneralFormItem/BrnGeneralFormItem.md @@ -0,0 +1,148 @@ +--- +title: BrnGeneralFormItem +group: + title: Form + order: 12 +--- + +# BrnGeneralFormItem + +## 一、效果总览 + + + +## 二、描述 + +### 适用场景 + +1. 基础表单项框架适用于自定义基础表单项 +2. 可自定义标题、副标题、右侧操作区域 + +包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示"、"多选项"等元素。 + +### 交互规则 + +1. 设置是否为"必填项"("\*") + +2. 设置“添加/删除”图标("+"、"-"):用于接收回调函数处理新增/删除录入项操作 + +3. 设置“提示”图标&文案("?"):用于接收回调函数为用户展示提示信息 + +4. 设置此录入项是否可编辑(禁用) + +5. 设置展示错误信息(error) + +### 使用规范 + +一般用于扩展基础表单项 + +## 三、构造函数及参数说明 + +### 构造函数 + +```dart +BrnGeneralFormItem({ + Key? key, + this.label, + this.title: "", + this.titleWidget, + this.subTitle, + this.subTitleWidget, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error: "", + this.isEdit: true, + this.isRequire: false, + this.operateWidget, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.themeData, + }): super(key: key){ + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); + } +``` + +### 参数说明: + +| **参数名** | 参数类型 | **描述** | **是否必填** | **默认值** | **备注** | +| --- | --- | --- | --- | --- | --- | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| title | String | 录入项标题 | 否 | '' | | +| titleWidget | Widget? | 录入项标题Widget | 否 | 无 | | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| subTitleWidget | Widget? | 录入项子标题Widget | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | +| error | String | 录入项错误提示 | 否 | '' | | +| isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | +| isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| themeData | BrnFormItemConfig? | form 配置 | 否 | 无 | | + +### 其他数据说明: + +#### BrnPrefixIconType: + +```dart +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; +} +``` + +## 四、代码演示 + +### 效果 1:基本样式 + + + +```dart +BrnGeneralFormItem( + title: "自然到访保护期", + subTitle: "这里是副标题", + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, +) +``` + +### 效果 2:全功能样式 + + + +```dart +BrnGeneralFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + error: "必填项不能为空", + titleWidget: Text("自然到访保护期"), + subTitleWidget: Text("这里是副标题"), + tipLabel: "标签", + operateWidget: Text("右侧操作区"), + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, +) +``` + diff --git a/doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem1.png b/doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem1.png new file mode 100644 index 0000000000000000000000000000000000000000..4bb09eac600554bddfb314eb79fa824040253c56 GIT binary patch literal 19374 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 literal 0 HcmV?d00001 diff --git a/doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem2.png b/doc/components/form/BrnGeneralFormItem/img/BrnGeneralFormItem2.png new file mode 100644 index 0000000000000000000000000000000000000000..f029b16ad0fc4972382ab78e54bf1b4c5ec787c9 GIT binary patch literal 38331 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 + + + +## 二、描述 + +### 适用场景 + +1. 带开关表单项组件 +1. 包括"标题"、"副标题"、"错误信息提示"、"必填项提示"、"添加/删除按钮"、"消息提示"、"多选项"等元素。 + +### 交互规则 + +1. 设置是否为"必填项"("\*") + +2. 设置“添加/删除”图标("+"、"-"):用于接收回调函数处理新增/删除录入项操作 + +3. 设置“提示”图标&文案("?"):用于接收回调函数为用户展示提示信息 + +4. 设置此录入项是否可编辑(禁用) + +5. 设置展示错误信息(error) + +### 使用规范 + +一般用于控制表单内容开关。 + +## 三、构造函数及参数说明 + +### 构造函数 + +```dart +BrnSwitchFormItem({ + Key? key, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error= "", + this.isEdit = true, + this.isRequire = true, + this.onAddTap, + this.onRemoveTap, + this.onTip, + required this.value, + this.onChanged, + this.themeData, + }) : super() { + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); + } +``` + +### 参数说明: + +| **参数名** | 参数类型 | **描述** | **是否必填** | **默认值** | **备注** | +| --- | --- | --- | --- | --- | --- | +| label | String? | 录入项的唯一标识,主要用于录入类型页面框架中 | 否 | 无 | | +| title | String | 录入项标题 | 否 | '' | | +| subTitle | String? | 录入项子标题 | 否 | 无 | | +| tipLabel | String? | 录入项提示(问号图标&文案) 用户点击时触发 onTip 回调。 | 否 | 备注中类型 3 | 1. 设置"空字符串"时展示问号图标 2. 设置"非空字符串"时展示问号图标&文案 3. 若不赋值或赋值为 null 时,不显示提示项 | +| prefixIconType | String | 录入项前缀图标样式 "添加项" "删除项" 详见 BrnPrefixIconType 类 | 否 | BrnPrefixIconType.normal | 1. 不展示图标:BrnPrefixIconType.normal 2. 展示加号图标:BrnPrefixIconType.add 3. 展示减号图标:BrnPrefixIconType.remove | +| error | String | 录入项错误提示 | 否 | '' | | +| isRequire | bool | 录入项是否为必填项(展示\*图标) 默认为 false 不必填 | 否 | false | | +| isEdit | bool | 录入项 是否可编辑 | 否 | true | true:可编辑 false:禁用 | +| onAddTap | VoidCallback? | 点击"+"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| onRemoveTap | VoidCallback? | 点击"-"图标回调 | 否 | 无 | 见**prefixIconType**字段 | +| value | bool | 初始值 | 是 | 无 | | +| onTip | VoidCallback? | 点击"?"图标回调 | 否 | 无 | 见**tipLabel**字段 | +| themeData | BrnFormItemConfig? | form 配置 | 否 | 无 | | + +### 其他数据说明: + +#### BrnPrefixIconType: + +```dart +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; +} +``` + +## 四、代码演示 + +### 效果 1:基本样式 + + + +```dart +BrnSwitchFormItem( + title: "自然到访保护期", + value: _isFirstSwitchOn, + onChanged: (oldValue, newValue) { + setState(() { + _isFirstSwitchOn = newValue; + }); + BrnToast.show( + "点击触发回调${oldValue}_${newValue}_onChanged", context); + }, +) +``` + +### 效果 2:全功能样式 + + + +```dart +BrnSwitchFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + error: "必填项不能为空", + title: "自然到访保护期", + subTitle: "这里是副标题", + tipLabel: "标签", + value: _isSecondSwitchOn, + onChanged: (oldValue, newValue) { + setState(() { + _isSecondSwitchOn = newValue; + }); + BrnToast.show( + "点击触发回调${oldValue}_${newValue}_onChanged", context); + }, +) +``` + diff --git a/doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem1.png b/doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem1.png new file mode 100644 index 0000000000000000000000000000000000000000..32f1ca9714260b36d2fd747e4e6d531bb975ed5c GIT binary patch literal 17592 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 literal 0 HcmV?d00001 diff --git a/doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem2.png b/doc/components/form/BrnSwitchFormItem/img/BrnSwitchItem2.png new file mode 100644 index 0000000000000000000000000000000000000000..853b68557a46bc19a2a253c76b4b89269bfd939a GIT binary patch literal 38495 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

tzM_gKH;Ke3BB|3lJT=b7TtKz^4*vwVN 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 TRV7S=0{%(9krOKs(f9j5qM^`v literal 0 HcmV?d00001 diff --git a/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md b/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md index 0bee0186..5ba14897 100644 --- a/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md +++ b/doc/components/form/BrnTextInputFormItem/BrnTextInputFormItem.md @@ -107,10 +107,10 @@ BrnTextInputFormItem({ ```dart -class BrnPrefixIconType { - static const String TYPE_NORMAL = "type_normal"; - static const String TYPE_ADD = "type_add"; - static const String TYPE_REMOVE = "type_remove"; +class BrnPrefixIconType { + static const String normal = "type_normal"; + static const String add = "type_add"; + static const String remove = "type_remove"; } ``` #### BrnInputType diff --git a/doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md b/doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md index c5e7b70f..2c4462c5 100644 --- a/doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md +++ b/doc/components/normalButton/BrnBigMainButton/BrnBigMainButton.md @@ -70,7 +70,7 @@ BrnBigMainButton( ```dart //置灰效果 无法点击 -BrnMetaBigMainButtonWidget( +BrnBigMainButton( title: '提交', isEnable: false, onTap: () { diff --git a/doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md b/doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md index e5d627da..e280cbe9 100644 --- a/doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md +++ b/doc/components/stepBar/BrnHorizontalSteps/BrnHorizontalSteps.md @@ -13,7 +13,7 @@ group: ## 一、效果总览 - + ## 二、描述 @@ -80,7 +80,7 @@ const BrnHorizontalSteps({ ### 效果1 -![](./img/BrnMetaHorizontalSteps5.png) +![](img/BrnHorizontalSteps5.png) diff --git a/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps1.jpg similarity index 100% rename from doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps1.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps1.jpg diff --git a/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps2.jpg similarity index 100% rename from doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps2.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps2.jpg diff --git a/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps3.jpg similarity index 100% rename from doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps3.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps3.jpg diff --git a/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg b/doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps4.jpg similarity index 100% rename from doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps4.jpg rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps4.jpg diff --git a/doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png b/doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps5.png similarity index 100% rename from doc/components/stepBar/BrnHorizontalSteps/img/BrnMetaHorizontalSteps5.png rename to doc/components/stepBar/BrnHorizontalSteps/img/BrnHorizontalSteps5.png diff --git a/doc/components/switchButton/BrnSwitchButton.md b/doc/components/switchButton/BrnSwitchButton.md new file mode 100644 index 00000000..ad5882a8 --- /dev/null +++ b/doc/components/switchButton/BrnSwitchButton.md @@ -0,0 +1,91 @@ +--- +title: BrnSwitchButton +group: + title: Button + order: 5 +--- + +# BrnBigMainButton + +## 一、效果总览 + + + +## 二、描述 + +### 适用场景 + +常用于选项开关 + + +## 三、构造函数及参数说明 + +### 构造函数 + +```dart + BrnSwitchButton({ + Key? key, + required this.value, + this.enabled = true, + required this.onChanged, + this.size = const Size(42, 26), + this.borderColor, + }) : super(key: key); +``` +### 参数说明 + +| **参数名** | **参数类型** | 描述 | **是否必填** | **默认值** | +| --- | --- | --- | --- | --- | +| value | bool | 选中的状态 | 是 | 无 | +| enabled | bool | 是否可以交互 | 否 | true | +| onChanged | ValueChanged | 点击事件 | 否 | 无 | +| borderColor | Color? | 未选中时边框的颜色 | 否 | 主题色 | + + + +## 四、代码演示 + +### 效果1 + + + +```dart +BrnSwitchButton( + enabled: false, + value: value2, + onChanged: (value) { + setState(() { + value2 = value; + }); + }, +) +``` + + +### 效果2 + +![](./img/BrnSwitchButtonNomal.png) + +```dart +BrnSwitchButton( + value: value1, + onChanged: (value) { + setState(() { + value1 = value; + }); + }, +) +``` + +### 效果3 + +![](./img/BrnSwitchButtonOffDisable.png) + +```dart +//置灰效果 无法点击 +BrnSwitchButton( + enabled: false, + value: false, + onChanged: (value) {}, +) +``` \ No newline at end of file diff --git a/doc/components/switchButton/img/BrnSwitchButtonDisable.png b/doc/components/switchButton/img/BrnSwitchButtonDisable.png new file mode 100644 index 0000000000000000000000000000000000000000..c94816e0b1e70ae967af6024e796d72a7c474213 GIT binary patch literal 2793 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 J4VI|n{{SCmR}ugK literal 0 HcmV?d00001 diff --git a/doc/components/switchButton/img/BrnSwitchButtonExample.png b/doc/components/switchButton/img/BrnSwitchButtonExample.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4db7d79cfa868f50b45c6260825db6d9b813c5 GIT binary patch literal 49358 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 literal 0 HcmV?d00001 diff --git a/doc/components/switchButton/img/BrnSwitchButtonOffDisable.png b/doc/components/switchButton/img/BrnSwitchButtonOffDisable.png new file mode 100644 index 0000000000000000000000000000000000000000..aeeefd2b03c862d4b9406236ccaeeb4cad8910ff GIT binary patch literal 3254 zcmb_ec{JNu8;+o*+L6$ztt~1VyI)({FocLDq$(;XttF+Mq*NQGI%-K!dl75wDJ@Ei z8e6DsMD2o7ODSUsZP7uknaY>>{+R#2bG|>G_rB*o=Y8%y&$;KlZ;Y*t#jzu@M?fIZ zF^nbJj=ysF2oyQQk7Wbe;UJKJ8PU|#7Gr9vU`zJBP4xBxf#9@T?(Py84S1J_hr4@M zzq;xXa)4cQbiAE==)2ZG6xv%m6b2Y+^cy#3r6IF|_J4p1acy;XkH#zPS7~*t4ySfMhGDUCoWOEsSELFhD^LR#XDD7dEH-GZ^RWc`{2RWI!;9AJaBPG zVfMzb35H}Q8vSrUyF{Z0%ZB6b3q{(MhTUnrHhR-@g(DzLlb)54$@*;3c4XX$P%DSBOgRD2ui2kNrD)rY% z9xuOLMtWRVM*6^&$K&m6^Me-OsAl02?lI88-yWCiX!|XEUoU$(VQyc!0#f7WA|Qb% zB1njz3GgAy2M7dafdAd$Fa-b21OFkLBopdDpd-r|w2A#Afz@15zmNJyBXU0xhcO4d z7Vm^ltB-$7d6ZFA =X67p79U}_^}Wg z3k!qXkETR_)`6eLh(yzS1Qcf>0?_v!ww}ol2#_X-YE=X)6}2|^QUNd)p>+9NBg_}W$n5xgu#V=+o8tUuEk)i8z z9SJ|a=j?bOTG^?GBVD|zeqGUX@vpE;QeaTQ#jP| zd%fu+C7n(#du=hC>Ba!APZ==c>n1b>k=zP=^k`i2L24{*wi-7-7MWL-VYjot-%zW5 z3MozflcfP$Ag^^8eXJVNcCkZk=YK4aJdVWKLccSiJ3Gv0tmmFTwpTy?e*8$)^QRjr ztEuLgzDU`k)tB=!;waynHb^gv&)l3><>lq}bLrsAf7L6p&>e7>OpDXk&PTU_4~v~D zmRMKCD$30xec-ldmUT}xVc85eMxX|gcX0P;Rtq;wuT+dFRmuQ~wB+A)dv{+uI^S(` zGRQ*!3w>#|N=ve&z@|gg{^%Gx4ks1vIU+W5W3GGecy7*kMX##vMN;UBiW}G2WjO|G z#aN0+R&UBgCOTv8(Im#%7>j;!aDPm97^Zw7&Zg&hl`h$?!9uk^MZ4ERidmmt#u20z zu{?#-?bxox=qm;36-=E!ZMr`iBbwdlAVb{RO6{_%oy+z~x7c6QqeG7!pwq+HO1X(aY? zKHtlGar5E}yvT)aGcP{ZlcK7y`qC=<+TMN|dM`l^s@}X}|GxPHx$iZ1 zZlPe0^8tS5TT2#QXh>^Y=Q%!k{x&Nlz}yW#kkH>vB5+2MCA0&Yd|#D)e44j;seu%h zZtvHa^IPc>iICUmtU|eCf92*Fc4(F7WY#y;FH~Z&u!kp#{59bqI^_6EW>Lv=&Hm_y z`O@gj#-GUpGfC{d0VFA53f%_`sSn7mZFsoo*`M7I-hQDCn=p zwZ&q4oD5p3U)%@{c$fGK06J^^Vcj9`cH0s=|Ehs;ez`e=PESvDA`g%`^OG5 zD;i*-TlL4l9V|}|_X*o4U3CST!7nEc3zj8Gm1P}R$Y;A)OM7%8o?b^|!CoictIQ*) zzXaDfQSknw@kWldz{bH_I^99o`+Q(PkTq9B%Kb!B)}U^`<^@jWHzfkc;Y-1}Pl^{8 zD;6rF%js%&dN-dfbSV*>Ym`5eyPXJwM>{D`U z?1*)bmpiQl0#J6w#IP^k7z*4ugl-lU5a;*M(*+805fl?+)U$ zb`csHI9{;+JJ&Vj1y<$HMQLU%WlIMEvYT+6D5hytO02SnRul3(#Bkw2(7k1d?faZS zm_$TfdAAw9k>AOuWBERM@jB`{U7-M=QA{7gKNFsHcaI^yAptgQBl~yTXfE5SgH;`i z3D{46d^&uYMC8Hl@Gcs*K;vS%+3f4&FEjFM+bxm}*t0rSM;d~Ve;h0>dI?=9u6jeK z_aRo^h70|CXOtCSjf%rnuXMj|wb)cFXzF0GCZ?w5b9mX#0|Ac@+g2-Qt~>TAu^6#* zrrWimoSIUoK(w>m`b7Fh$(03RKTxYN?gi(`!JyeqFcyrc!<$UB#yG) zHa8pXVnC_wrJd3{`|(+uCu`ze5fGOeK*U}$g}gL{_cO1t7d41XB94#>N~2xeIvIoS5;BYnHG+ihnm*vK{&=GPrtWQXc7Or-B55L`z)(@V!YlX$K zr~O;M_I2J?IA^rL>F2wUEed!0bvhZlHIyYOS!WcqTj^-?mEcb78W{B9JjnJ0TSaaLkwZhmhg^J*8 zsH9vXEoE4o9LOs_qn7Wo+=iq{93QDQcE3g-=**PYx3sw7PjK}5tPS<)o$1-W#(~GhBHk6E1lqVgyE$Jk_}npNFK z35q(YbYru*!n~M^>?h)|@SLebUH|>p<-TBNR*-cjmXmMDTxRgo{TxnmVUq8Kwfh8> zOID&;3BK#nxk))WbW_rUVl%z?)%IgRhK}vr`C@BQT~NhVh~4z*TQ#+YTb-i9Pwcz1 zAThkeQM)9JJre3YGoSkeHNTa;k90^dGdE_%%NtG@ uX@ZqF)z8vy(fEVmS&OT+SN{iz+0c@zPsLYHnW_9U`(n&&(B&xiu>Sx9=LsbM literal 0 HcmV?d00001 diff --git a/doc/components/switchButton/img/BrnSwitchButtonSize.png b/doc/components/switchButton/img/BrnSwitchButtonSize.png new file mode 100644 index 0000000000000000000000000000000000000000..f8b7ed19e964bc3407f78bfe3355eee344e1c0bf GIT binary patch literal 5757 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 literal 0 HcmV?d00001 diff --git a/doc/components/switchButton/img/BrnSwitchButtonUnSelect.png b/doc/components/switchButton/img/BrnSwitchButtonUnSelect.png new file mode 100644 index 0000000000000000000000000000000000000000..87920ef9da736a87b8c11b056c4785fbd39937c8 GIT binary patch literal 3212 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 A6#xJL literal 0 HcmV?d00001 diff --git a/doc/components/tag/BrnStateTag/BrnStateTag.md b/doc/components/tag/BrnStateTag/BrnStateTag.md index a1ac1c18..b8671b21 100644 --- a/doc/components/tag/BrnStateTag/BrnStateTag.md +++ b/doc/components/tag/BrnStateTag/BrnStateTag.md @@ -9,7 +9,7 @@ group: ## 一、效果总览 -![](./img/BrnMetaStateTagIntro.png) +![](img/BrnStateTagIntro.png) ## 二、描述 @@ -58,7 +58,7 @@ enum TagState { ### 效果 1 - + ```dart BrnStateTag( diff --git a/doc/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png b/doc/components/tag/BrnStateTag/img/BrnStateTagIntro.png similarity index 100% rename from doc/components/tag/BrnStateTag/img/BrnMetaStateTagIntro.png rename to doc/components/tag/BrnStateTag/img/BrnStateTagIntro.png diff --git a/doc/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png b/doc/components/tag/BrnStateTag/img/BrnStateTagSucceed.png similarity index 100% rename from doc/components/tag/BrnStateTag/img/BrnMetaStateTagSucceed.png rename to doc/components/tag/BrnStateTag/img/BrnStateTagSucceed.png diff --git a/doc/components/tag/BrnTagCustom/BrnTagCustom.md b/doc/components/tag/BrnTagCustom/BrnTagCustom.md index 0dbae402..2417f9dc 100644 --- a/doc/components/tag/BrnTagCustom/BrnTagCustom.md +++ b/doc/components/tag/BrnTagCustom/BrnTagCustom.md @@ -50,7 +50,7 @@ BrnTagCustom({ | textPadding | EdgetInsets | 标签文字的 padding | 否 | EdgeInsets.symmetric(horizontal:2) | | fontSize | double | 标签文字的大小 | 否 | 11 | | fontWeight | FontWeight | 文字的粗细 | 否 | FontWeight.normal | -| maxWidth | Double | 标签高度 | 否 | double.infinity | +| maxWidth | Double | 标签宽度 | 否 | double.infinity | | border | Border? | 标签边框 | 否 | 无 | ## 四、代码演示 diff --git a/doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md b/doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md index 3554fab2..08d9ad6a 100644 --- a/doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md +++ b/doc/components/text/BrnEnhanceNumberCard/BrnEnhanceNumberCard.md @@ -24,7 +24,7 @@ group: ### **注意事项** -1、需要强化的信息,必须是非中文(BrnMetaNumberInfoItemModel的number 字段),否则会显示异常,如下所示: +1、需要强化的信息,必须是非中文(BrnNumberInfoItemModel的number 字段),否则会显示异常,如下所示: ![image-20211031145233093](./img/BrnEnhanceNumberCardIntro1.png) @@ -69,9 +69,9 @@ BrnEnhanceNumberCard({ ![image-20211031143416320](./img/BrnEnhanceNumberCardDemo1.png) ```dart -BrnMetaNumberInfoWidget( +BrnEnhanceNumberCard( itemChildren: [ - BrnMetaNumberInfoItemModel( + BrnNumberInfoItemModel( title: '数字信息', number: '3', ) @@ -106,14 +106,14 @@ BrnEnhanceNumberCard( ```dart -BrnMetaNumberInfoWidget( +BrnEnhanceNumberCard( rowCount: 2, itemChildren: [ - BrnMetaNumberInfoItemModel( + BrnNumberInfoItemModel( title: '文案信息', number: '24', ), - BrnMetaNumberInfoItemModel( + BrnNumberInfoItemModel( title: '文案信息', number: '180', ), diff --git a/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md b/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md index b733f463..5107737c 100644 --- a/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md +++ b/doc/components/title/BrnCommonCardTitle/BrnCommonCardTitle.md @@ -67,10 +67,13 @@ BrnCommonCardTitle( ```dart BrnCommonCardTitle( title: '非箭头Title', - accessoryWidget: BrnMetaStateTag(tagText: '状态标签'), - subTitleWidget: BrnMetaStartRatingIndicator(rating: 4), + accessoryWidget: BrnStateTag(tagText: '状态标签'), + subTitleWidget: BrnRatingStar( + count: 4, + selectedCount: 2, + ), onTap: () { - BrnToast.show('BrnMetaPlainCardTitle is clicked', context); + BrnToast.show('BrnPlainCardTitle is clicked', context); }, ) ``` @@ -82,13 +85,15 @@ BrnCommonCardTitle( ```dart BrnCommonCardTitle( title: '非箭头Title', - accessoryWidget: BrnMetaStateTag(tagText: '状态标签'), - subTitleWidget: BrnMetaStartRatingIndicator(rating: 4), - detailTextString: '副标题副标题副标题', + accessoryWidget: BrnStateTag(tagText: '状态标签'), + subTitleWidget: BrnRatingStar( + count: 4, + selectedCount: 2, + ), onTap: () { - BrnToast.show('BrnMetaPlainCardTitle is clicked', context); + BrnToast.show('BrnPlainCardTitle is clicked', context); }, -) +), ``` ### 效果 3:标题和副文本 @@ -100,7 +105,7 @@ BrnCommonCardTitle( title: '非箭头Title', accessoryText: '辅助文本', onTap: () { - BrnToast.show('BrnMetaPlainCardTitle is clicked', context); + BrnToast.show('BrnPlainCardTitle is clicked', context); }, ) ``` diff --git a/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart b/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart index fd68e9ca..10f04ba9 100644 --- a/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart +++ b/example/lib/sample/components/actionsheet/actionsheet_selected_list_example.dart @@ -119,7 +119,7 @@ class SelectedListActionSheetExamplePageState onListShowed: () { BrnToast.show("显示了哦~~", context); }, - onItemDelete: (int idx, String entity) { + onItemDelete: (int idx, String? entity) { _data[idx] = '$idx 变化了哈'; controller.reloadData(); BrnToast.show("$idx 奇数行无法删除", context); diff --git a/example/lib/sample/components/card_title/brn_common_title_example.dart b/example/lib/sample/components/card_title/brn_common_title_example.dart index fd5bd176..7b8589dd 100644 --- a/example/lib/sample/components/card_title/brn_common_title_example.dart +++ b/example/lib/sample/components/card_title/brn_common_title_example.dart @@ -45,6 +45,11 @@ class _BrnCommonTitleExampleState extends State { ), BrnCommonCardTitle( title: '非箭头Title', + accessoryWidget: BrnStateTag(tagText: '状态标签'), + subTitleWidget: BrnRatingStar( + count: 2, + selectedCount: 2, + ), onTap: () { BrnToast.show('BrnPlainCardTitle is clicked', context); }, diff --git a/example/lib/sample/components/form/all_item_style_example.dart b/example/lib/sample/components/form/all_item_style_example.dart index 0322b638..2e17f930 100644 --- a/example/lib/sample/components/form/all_item_style_example.dart +++ b/example/lib/sample/components/form/all_item_style_example.dart @@ -1,5 +1,3 @@ - - import 'package:bruno/bruno.dart'; import 'package:example/sample/components/form/group_example/expansion_group_example.dart'; import 'package:example/sample/components/form/group_example/group_add_example.dart'; @@ -14,12 +12,14 @@ import 'package:example/sample/components/form/items_example/ratio_input_example import 'package:example/sample/components/form/items_example/select_all_title_example.dart'; import 'package:example/sample/components/form/items_example/star_example.dart'; import 'package:example/sample/components/form/items_example/step_input_example.dart'; +import 'package:example/sample/components/form/items_example/switch_example.dart'; import 'package:example/sample/components/form/items_example/text_block_input_example.dart'; import 'package:example/sample/components/form/items_example/text_input_example.dart'; import 'package:example/sample/components/form/items_example/text_quick_select_input_example.dart'; import 'package:example/sample/components/form/items_example/text_select_example.dart'; import 'package:example/sample/components/form/items_example/title_example.dart'; import 'package:example/sample/components/form/items_example/title_select_example.dart'; +import 'package:example/sample/components/form/items_example/general_item_example.dart'; import 'package:example/sample/home/list_item.dart'; import 'package:flutter/material.dart'; @@ -45,8 +45,38 @@ class AllFormItemStyleExamplePage extends StatelessWidget { Widget getBodyWidget(BuildContext context) { return ListView( children: [ + ListItem( - title: "选择类型: 2种", + title: "基础类型 ", + titleFontSize: 22, + titleColor: Colors.red, + ), + ListItem( + title: "基础标题表单项", + describe: "基础类型", + isSupportTheme: true, + onPressed: () { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return BaseTitleExamplePage("标题表单项"); + }, + )); + }, + ), + ListItem( + title: "基础通用表单项", + describe: "自定义基础表单", + isSupportTheme: true, + onPressed: () { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return GeneralFormExamplePage("自定义基础表单"); + }, + )); + }, + ), + ListItem( + title: "选择类型", titleFontSize: 22, titleColor: Colors.red, ), @@ -198,61 +228,61 @@ class AllFormItemStyleExamplePage extends StatelessWidget { titleColor: Colors.red, ), ListItem( - title: "基础标题表单项", + title: "标题表单项", describe: "杂项类型", isSupportTheme: true, onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return BaseTitleExamplePage("标题表单项"); + return TitleExamplePage("标题表单项"); }, )); }, ), ListItem( - title: "标题表单项", + title: "全选表单项", describe: "杂项类型", isSupportTheme: true, onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return TitleExamplePage("标题表单项"); + return SelectAllTitleExamplePage("全选表单项"); }, )); }, ), ListItem( - title: "全选表单项", - describe: "杂项类型", + title: "评星表单项", + describe: '各种形态', isSupportTheme: true, onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return SelectAllTitleExamplePage("全选表单项"); + return StarInputExamplePage("评星表单项"); }, )); }, ), ListItem( - title: "评星表单项", + title: "递增表单项", describe: '各种形态', isSupportTheme: true, onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return StarInputExamplePage("评星表单项"); + return StepInputExamplePage(title: "递增表单项"); }, )); }, ), ListItem( - title: "递增表单项", + title: "Switch表单项", describe: '各种形态', isSupportTheme: true, onPressed: () { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { - return StepInputExamplePage(title: "递增表单项"); + return SwitchInputExamplePage("Switch表单项"); }, )); }, diff --git a/example/lib/sample/components/form/items_example/general_item_example.dart b/example/lib/sample/components/form/items_example/general_item_example.dart new file mode 100644 index 00000000..e4e07fa7 --- /dev/null +++ b/example/lib/sample/components/form/items_example/general_item_example.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import 'package:bruno/bruno.dart'; + +class GeneralFormExamplePage extends StatelessWidget { + final String _title; + + GeneralFormExamplePage(this._title); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: BrnAppBar( + title: _title, + ), + body: ListView( + children: [ + Container( + padding: EdgeInsets.fromLTRB(20, 5, 20, 5), + child: Text( + "基本样式:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + )), + ), + BrnGeneralFormItem( + title: "自然到访保护期", + subTitle: "这里是副标题", + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + ), + Container( + padding: EdgeInsets.fromLTRB(20, 20, 20, 5), + child: Text( + "全功能样式:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + ), + ), + ), + BrnGeneralFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + error: "必填项不能为空", + titleWidget: Text("自然到访保护期"), + subTitleWidget: Text("这里是副标题"), + tipLabel: "标签", + operateWidget: Text("右侧操作区"), + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + ), + Container( + padding: EdgeInsets.fromLTRB(20, 20, 20, 5), + child: Text( + "no error:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + ), + ), + ), + BrnGeneralFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + titleWidget: Text("自然到访保护期"), +// subTitleWidget: Text("这里是副标题"), + tipLabel: "标签", + operateWidget: Text("右侧操作区"), + + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + ), + ], + )); + } +} diff --git a/example/lib/sample/components/form/items_example/switch_example.dart b/example/lib/sample/components/form/items_example/switch_example.dart new file mode 100644 index 00000000..bae47be8 --- /dev/null +++ b/example/lib/sample/components/form/items_example/switch_example.dart @@ -0,0 +1,134 @@ +import 'package:bruno/bruno.dart'; +import 'package:flutter/material.dart'; + +class SwitchInputExamplePage extends StatefulWidget { + final String _title; + + SwitchInputExamplePage(this._title); + + @override + State createState() { + return SwitchInputExampleState(); + } +} + +class SwitchInputExampleState extends State{ + + bool _isFirstSwitchOn = true; + bool _isSecondSwitchOn = true; + bool _isThirdSwitchOn = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: BrnAppBar( + title: widget._title, + ), + body: ListView( + children: [ + Container( + padding: EdgeInsets.fromLTRB(20, 5, 20, 5), + child: Text( + "基本样式:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + ), + ), + ), + BrnSwitchFormItem( + title: "自然到访保护期", + value: _isFirstSwitchOn, + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + onChanged: (oldValue, newValue) { + setState(() { + _isFirstSwitchOn = newValue; + }); + BrnToast.show( + "点击触发回调${oldValue}_${newValue}_onChanged", context); + }, + ), + Container( + padding: EdgeInsets.fromLTRB(20, 20, 20, 5), + child: Text( + "全功能样式:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + ), + ), + ), + BrnSwitchFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: true, + error: "必填项不能为空", + title: "自然到访保护期", + subTitle: "这里是副标题", + tipLabel: "标签", + value: _isSecondSwitchOn, + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + onChanged: (oldValue, newValue) { + setState(() { + _isSecondSwitchOn = newValue; + }); + BrnToast.show( + "点击触发回调${oldValue}_${newValue}_onChanged", context); + }, + ), + Container( + padding: EdgeInsets.fromLTRB(20, 20, 20, 5), + child: Text( + "no error:", + style: TextStyle( + color: Color(0xFF222222), + fontSize: 22, + ), + ), + ), + BrnSwitchFormItem( + prefixIconType: BrnPrefixIconType.add, + isRequire: true, + isEdit: false, + title: "自然到访保护期", + subTitle: "这里是副标题", + tipLabel: "标签", + value: _isThirdSwitchOn, + onTip: () { + BrnToast.show("点击触发onTip回调", context); + }, + onAddTap: () { + BrnToast.show("点击触发onAddTap回调", context); + }, + onRemoveTap: () { + BrnToast.show("点击触发onRemoveTap回调", context); + }, + onChanged: (oldValue, newValue) { + setState(() { + _isThirdSwitchOn = newValue; + }); + BrnToast.show( + "点击触发回调${oldValue}_${newValue}_onChanged", context); + }, + ), + ], + )); + } + +} diff --git a/example/lib/sample/components/switch/brn_switch_example.dart b/example/lib/sample/components/switch/brn_switch_example.dart new file mode 100644 index 00000000..01f49150 --- /dev/null +++ b/example/lib/sample/components/switch/brn_switch_example.dart @@ -0,0 +1,134 @@ +import 'package:bruno/bruno.dart'; +import 'package:flutter/material.dart'; + +class BrnSwitchButtonExample extends StatefulWidget { + @override + _BrnSwitchButtonExampleState createState() => _BrnSwitchButtonExampleState(); +} + +class _BrnSwitchButtonExampleState extends State { + bool value1 = true; + bool value2 = true; + bool value3 = false; + bool value5 = true; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: BrnAppBar( + title: '开关元件', + ), + body: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '规则', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + fontWeight: FontWeight.bold), + ), + BrnBubbleText(maxLines: 2, text: '具备选中、未选中、以及禁用状态'), + Text( + '正常案例', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: BrnSwitchButton( + value: value1, + onChanged: (value) { + setState(() { + value1 = value; + }); + }, + ), + ), + Text( + '禁用案例', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: BrnSwitchButton( + enabled: false, + value: value2, + onChanged: (value) { + setState(() { + value2 = value; + }); + }, + ), + ), + Text( + '未选案例', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: BrnSwitchButton( + value: value3, + onChanged: (value) { + setState(() { + value3 = value; + }); + }, + ), + ), + Text( + '禁用案例', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: BrnSwitchButton( + enabled: false, + value: false, + onChanged: (value) {}, + ), + ), + Text( + '自定义大小', + style: TextStyle( + color: Color(0xFF222222), + fontSize: 28, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: BrnSwitchButton( + size: Size(80, 40), + value: value5, + onChanged: (value) { + setState(() { + value5 = value; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/lib/sample/home/card_data_config.dart b/example/lib/sample/home/card_data_config.dart index e3ee0a88..e2f1d98b 100644 --- a/example/lib/sample/home/card_data_config.dart +++ b/example/lib/sample/home/card_data_config.dart @@ -38,6 +38,7 @@ import 'package:example/sample/components/scroll_anchor/scroll_actor_tab_example import 'package:example/sample/components/selection/selection_entry_page.dart'; import 'package:example/sample/components/step/step_example.dart'; import 'package:example/sample/components/sugsearch/search_text_example.dart'; +import 'package:example/sample/components/switch/brn_switch_example.dart'; import 'package:example/sample/components/switch/checkbox_example.dart'; import 'package:example/sample/components/switch/radio_example.dart'; import 'package:example/sample/components/tabbar/brn_tab_example.dart'; @@ -423,6 +424,17 @@ class CardDataConfig { }, )); })); + children.add(GroupInfo( + groupName: "SwitchButton 普通按钮", + desc: "Switch 按钮", + isSupportTheme: true, + navigatorPage: (BuildContext context) { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return BrnSwitchButtonExample(); + }, + )); + })); return GroupInfo(groupName: "按钮", children: children, isExpand: false); } diff --git a/lib/bruno.dart b/lib/bruno.dart index 8ca380d3..54b9dab8 100644 --- a/lib/bruno.dart +++ b/lib/bruno.dart @@ -125,6 +125,8 @@ export 'src/components/form/items/group/brn_normal_group.dart'; export 'src/components/form/items/group/brn_expandable_group.dart'; export 'src/components/form/items/group/brn_portrait_radio_group.dart'; export 'src/components/form/items/group/brn_expandable_group_with_opreate.dart'; +export 'src/components/form/items/misc/brn_general_item.dart'; +export 'src/components/form/items/general/brn_switch_item.dart'; // 新增表单项 export 'src/components/form/items/title/brn_base_title_item.dart'; @@ -241,3 +243,6 @@ export 'src/components/scroll_anchor/brn_scroll_anchor_tab.dart'; // 城市选择 export 'src/components/selectcity/brn_single_select_city_page.dart'; + +// 切换 +export 'src/components/switch/brn_switch_button.dart'; diff --git a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart index d8eeca9b..6fe2a758 100644 --- a/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart +++ b/lib/src/components/actionsheet/brn_selected_list_action_sheet.dart @@ -214,8 +214,8 @@ class BrnSelectedListActionSheet { class _BrnActionSheetSelectedItemListContentWidget extends StatefulWidget { final BrnSelectedListActionSheet itemWidget; final void Function(bool isClear)? onDismiss; - final dynamic Function(int index, T entity) itemTitleBuilder; - final bool Function(int deleteIdx, T deleteEntity)? onItemDelete; + final BrnItemTitleBuilder itemTitleBuilder; + final BrnItemDeleteCallback? onItemDelete; final BrnSelectedListActionSheetController? controller; OverlayState? _overlayState; diff --git a/lib/src/components/card/content_card/brn_pair_info_table.dart b/lib/src/components/card/content_card/brn_pair_info_table.dart index 3dd6835b..564ca01e 100644 --- a/lib/src/components/card/content_card/brn_pair_info_table.dart +++ b/lib/src/components/card/content_card/brn_pair_info_table.dart @@ -322,7 +322,7 @@ class _BrnPairInfoTableState extends State { Widget foldButtonWidget = layerCtn; /// 将原有的value显示替换为 stack - BrnInfoModal brnMetaInfoModal = BrnInfoModal( + BrnInfoModal brnInfoModal = BrnInfoModal( isArrow: indexModal!.isArrow, keyPart: indexModal!.keyPart, valuePart: indexModal!.valuePart, @@ -330,13 +330,13 @@ class _BrnPairInfoTableState extends State { Container stack = Container( child: Stack( children: [ - _finalValueWidget(brnMetaInfoModal, itemSpacing: 0), + _finalValueWidget(brnInfoModal, itemSpacing: 0), Positioned(bottom: 0, right: 0, child: foldButtonWidget), ], ), ); - brnMetaInfoModal.valuePart = stack; - return brnMetaInfoModal; + brnInfoModal.valuePart = stack; + return brnInfoModal; } BrnInfoModal _expandedButtonWidget() { @@ -381,7 +381,7 @@ class _BrnPairInfoTableState extends State { ///收起的widget Widget foldButtonWidget = layerCtn; - BrnInfoModal brnMetaInfoModal = BrnInfoModal( + BrnInfoModal brnInfoModal = BrnInfoModal( isArrow: widget.children.last.isArrow, keyPart: widget.children.last.keyPart, valuePart: widget.children.last.valuePart, @@ -390,13 +390,13 @@ class _BrnPairInfoTableState extends State { Container stack = Container( child: Stack( children: [ - _finalValueWidget(brnMetaInfoModal, itemSpacing: 0), + _finalValueWidget(brnInfoModal, itemSpacing: 0), Positioned(bottom: 0, right: 0, child: foldButtonWidget), ], ), ); - brnMetaInfoModal.valuePart = stack; - return brnMetaInfoModal; + brnInfoModal.valuePart = stack; + return brnInfoModal; } Widget _valueTitleText(String text, @@ -706,7 +706,7 @@ class BrnAlignPairInfo extends StatelessWidget with PairInfoPart { /// 用于展示信息的modal,封装了key和value的基本信息 /// /// 基本的文本展示只需 传入keyPart和valuePart为字符串 -/// 复杂的展示 需要传入Widget,BrnMetaInfoModal的若干静态方法 提供了丰富简便的富文本使用方式 +/// 复杂的展示 需要传入Widget,BrnInfoModal的若干静态方法 提供了丰富简便的富文本使用方式 /// class BrnInfoModal { /// 方便业务调用,具备两种类型 string 和 widget diff --git a/lib/src/components/dialog/brn_middle_input_diaolg.dart b/lib/src/components/dialog/brn_middle_input_diaolg.dart index 7b83a4f1..edd807f2 100644 --- a/lib/src/components/dialog/brn_middle_input_diaolg.dart +++ b/lib/src/components/dialog/brn_middle_input_diaolg.dart @@ -1,6 +1,5 @@ import 'package:bruno/src/components/dialog/brn_dialog.dart'; import 'package:bruno/src/theme/brn_theme.dart'; -import 'package:bruno/src/theme/brn_theme_configurator.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/src/components/dialog/brn_multi_select_dialog.dart b/lib/src/components/dialog/brn_multi_select_dialog.dart index 324256f3..d75c5b1c 100644 --- a/lib/src/components/dialog/brn_multi_select_dialog.dart +++ b/lib/src/components/dialog/brn_multi_select_dialog.dart @@ -1,5 +1,4 @@ import 'package:bruno/src/components/dialog/brn_content_export_dialog.dart'; -import 'package:bruno/src/components/dialog/brn_dialog.dart'; import 'package:bruno/src/components/line/brn_line.dart'; import 'package:bruno/src/constants/brn_asset_constants.dart'; import 'package:bruno/src/theme/brn_theme_configurator.dart'; diff --git a/lib/src/components/form/base/brn_form_item_type.dart b/lib/src/components/form/base/brn_form_item_type.dart index ffeeacc1..6fd1cc43 100644 --- a/lib/src/components/form/base/brn_form_item_type.dart +++ b/lib/src/components/form/base/brn_form_item_type.dart @@ -44,6 +44,7 @@ class BrnInputItemType { static const String labelTitle = "label_title"; static const String labelAdd = "label_add"; + static const String labelGeneralType = "label_general_type"; } class BrnInputType { diff --git a/lib/src/components/form/items/general/brn_switch_item.dart b/lib/src/components/form/items/general/brn_switch_item.dart new file mode 100644 index 00000000..fe9e584c --- /dev/null +++ b/lib/src/components/form/items/general/brn_switch_item.dart @@ -0,0 +1,210 @@ +import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; +import 'package:bruno/src/components/form/base/input_item_interface.dart'; +import 'package:bruno/src/components/form/utils/brn_form_util.dart'; +import 'package:bruno/src/components/switch/brn_switch_button.dart'; +import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:flutter/material.dart'; + +/// 带开关按钮表单 +// ignore: must_be_immutable +class BrnSwitchFormItem extends StatefulWidget { + + /// 录入项的唯一标识,主要用于录入类型页面框架中 + final String? label; + + /// 录入项类型,主要用于录入类型页面框架中 + final String type = BrnInputItemType.switchType; + + /// 录入项标题 + final String title; + + /// 录入项子标题 + final String? subTitle; + + /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 + /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, + /// 2. 若赋值为非空字符串时 展示"问号图标&文案", + /// 3. 若不赋值或赋值为null时 不显示提示项 + /// 默认值为 3 + final String? tipLabel; + + /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 + final String prefixIconType; + + /// 录入项错误提示 + final String error; + + /// 录入项是否为必填项(展示*图标) 默认为 false 不必填 + final bool isRequire; + + /// 录入项 是否可编辑 + final bool isEdit; + + /// 点击"+"图标回调 + final VoidCallback? onAddTap; + + /// 点击"-"图标回调 + final VoidCallback? onRemoveTap; + + /// 点击"?"图标回调 + final VoidCallback? onTip; + + /// 特有字段 + final bool value; + + /// 开关变化回调 + final OnBrnFormSwitchChanged? onChanged; + + /// form配置 + BrnFormItemConfig? themeData; + + BrnSwitchFormItem({ + Key? key, + this.label, + this.title = "", + this.subTitle, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error= "", + this.isEdit = true, + this.isRequire = true, + this.onAddTap, + this.onRemoveTap, + this.onTip, + required this.value, + this.onChanged, + this.themeData, + }) : super() { + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); + } + + @override + BrnSwitchFormItemState createState() { + return BrnSwitchFormItemState(); + } +} + +class BrnSwitchFormItemState extends State { + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: 25, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + + Container( + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, widget.isRequire,widget.themeData!), + child: Row( + children: [ + + Offstage( + offstage: (widget.prefixIconType == BrnPrefixIconType.normal), + child: Container( + padding: EdgeInsets.only(right: 6), + child: GestureDetector( + onTap: () { + + if (!BrnFormUtil.isEdit(widget.isEdit)) { + return; + } + + BrnFormUtil.notifyAddRemoveTap(context,widget.prefixIconType, widget.onAddTap, widget.onRemoveTap); + + }, + child: BrnFormUtil.getPrefixIcon(widget.prefixIconType), + ), + ), + ), + + Offstage( + offstage: (!widget.isRequire), + child: BrnFormUtil.getRequireIcon(widget.isRequire), + ), + Container( + child: Text(widget.title, style: BrnFormUtil.getTitleTextStyle(widget.themeData!),) + ), + + Offstage( + offstage: (widget.tipLabel == null), + child: GestureDetector( + onTap: () { + if (widget.onTip != null) { + widget.onTip!(); + } + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(left:6, right: 7), + child: BrnFormUtil.getQuestionMarkIcon() + ), + + Container( + child: Text(widget.tipLabel ?? "", style: BrnFormUtil.getTipsTextStyle(widget.themeData!),), + ), + ], + ), + ), + ), + + ], + ), + ), + BrnSwitchButton( + size: Size(42,25), + value: widget.value, + enabled: widget.isEdit, + onChanged: (bool value) { + bool oldValue = widget.value; + BrnFormUtil.notifySwitchChanged(widget.onChanged, context, oldValue, value); + setState(() {}); + }, + ), + ], + ), + ), + + /// 副标题 + Offstage( + offstage: (widget.subTitle == null || widget.subTitle!.isEmpty), + child: Container( + padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData!), + child: Text(widget.subTitle ?? "", style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!),)), + ), + + Offstage( + offstage: (widget.error.isEmpty), + child: Container( + padding: BrnFormUtil.errorEdgeInsets(widget.themeData!), + child: Text(widget.error, style: BrnFormUtil.getErrorTextStyle(widget.themeData!),), + ), + ) + ], + ), + + ); + } + +} + + + + + + + diff --git a/lib/src/components/form/items/misc/brn_general_item.dart b/lib/src/components/form/items/misc/brn_general_item.dart new file mode 100644 index 00000000..af3cd8b2 --- /dev/null +++ b/lib/src/components/form/items/misc/brn_general_item.dart @@ -0,0 +1,216 @@ +import 'package:bruno/src/components/form/base/brn_form_item_type.dart'; +import 'package:bruno/src/components/form/utils/brn_form_util.dart'; +import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:flutter/material.dart'; + +// ignore: must_be_immutable +class BrnGeneralFormItem extends StatefulWidget{ + + /// 录入项的唯一标识,主要用于录入类型页面框架中 + final String? label; + + /// 录入项类型,主要用于录入类型页面框架中 + final String type = BrnInputItemType.labelGeneralType; + + /// 录入项标题 + final String title; + + /// 录入项子标题 + final Widget? titleWidget; + + /// 录入项子标题 + final String? subTitle; + + /// 录入项子标题 widget + final Widget? subTitleWidget; + + /// 录入项提示(问号图标&文案) 用户点击时触发onTip回调。 + /// 1. 若赋值为 空字符串("")时仅展示"问号"图标, + /// 2. 若赋值为非空字符串时 展示"问号图标&文案", + /// 3. 若不赋值或赋值为null时 不显示提示项 + /// 默认值为 3 + final String? tipLabel; + + /// 录入项前缀图标样式 "添加项" "删除项" 详见 PrefixIconType类 + final String prefixIconType; + + /// 录入项错误提示 + final String error; + + /// 录入项是否为必填项(展示*图标) 默认为 false 不必填 + final bool isRequire; + + /// 录入项 是否可编辑 + final bool isEdit; + + /// 点击"+"图标回调 + final VoidCallback? onAddTap; + + /// 点击"-"图标回调 + final VoidCallback? onRemoveTap; + + /// 点击"?"图标回调 + final VoidCallback? onTip; + + /// 右侧操作widget + final Widget? operateWidget; + + /// form配置 + BrnFormItemConfig? themeData; + + BrnGeneralFormItem({ + Key? key, + this.label, + this.title: "", + this.titleWidget, + this.subTitle, + this.subTitleWidget, + this.tipLabel, + this.prefixIconType = BrnPrefixIconType.normal, + this.error: "", + this.isEdit: true, + this.isRequire: false, + this.operateWidget, + this.onAddTap, + this.onRemoveTap, + this.onTip, + this.themeData, + }): super(key: key){ + this.themeData ??= BrnFormItemConfig(); + this.themeData = BrnThemeConfigurator.instance + .getConfig(configId: this.themeData!.configId) + .formItemConfig + .merge(this.themeData); + } + + @override + State createState() { + return BrnGeneralFormItemState(); + } + +} + +class BrnGeneralFormItemState extends State { + + @override + Widget build(BuildContext context) { + + return Container( + color: Colors.white, + padding: BrnFormUtil.itemEdgeInsets(widget.themeData!), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: BrnFormUtil.titleEdgeInsets(widget.prefixIconType, + widget.isRequire, widget.themeData!), + child: Row( + children: [ + + Offstage( + offstage: widget.prefixIconType == BrnPrefixIconType.normal, + child: Container( + padding: EdgeInsets.only(right: 6), + child: GestureDetector( + onTap: () { + + if ( !widget.isEdit) { + return; + } + + if (BrnPrefixIconType.add == widget.prefixIconType) { + if (widget.onAddTap != null) { + widget.onAddTap!(); + } + } else if (BrnPrefixIconType.remove == widget.prefixIconType) { + if (widget.onRemoveTap != null) { + widget.onRemoveTap!(); + } + } + + }, + child: BrnFormUtil.getPrefixIcon(widget.prefixIconType), + ), + ), + ), + + Offstage( + offstage: (!widget.isRequire), + child: BrnFormUtil.getRequireIcon(widget.isRequire), + ), + Container( + child: widget.titleWidget ?? Text(widget.title, style: BrnFormUtil.getTitleTextStyle(widget.themeData!),) + ), + + Offstage( + offstage: (widget.tipLabel == null), + child: GestureDetector( + onTap: () { + + if (widget.onTip != null) { + widget.onTip!(); + } + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(left:6, right: 7), + child: BrnFormUtil.getQuestionMarkIcon() + ), + + Container( + child: Text(widget.tipLabel ?? "", style: BrnFormUtil.getTipsTextStyle(widget.themeData!),), + ), + ], + ), + ), + ), + + ], + ), + ), + + + Container( + child: widget.operateWidget ?? SizedBox.shrink(), + ), + + ], + ), + + Offstage( + offstage: ((widget.subTitleWidget == null) && (widget.subTitle == null || widget.subTitle!.isEmpty)), + child: Container( + padding: BrnFormUtil.subTitleEdgeInsets(widget.themeData!), + child: widget.subTitleWidget ?? Text(widget.subTitle ?? "", style: BrnFormUtil.getSubTitleTextStyle(widget.themeData!),)), + ), + + Offstage( + offstage: (widget.error.isEmpty), + child: Container( + padding: BrnFormUtil.computeErrorEdgeInsets(widget.prefixIconType, widget.isRequire), + child: Text(widget.error, style: BrnFormUtil.getErrorTextStyle(widget.themeData!),)) + ) + ], + ), + + ); + + + } + + +} + + + + + + + + + diff --git a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart index 53fa92c4..90bf83e3 100644 --- a/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart +++ b/lib/src/components/scroll_anchor/brn_scroll_anchor_tab.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:bruno/src/components/popup/brn_measure_size.dart'; import 'package:bruno/src/components/tabbar/normal/brn_tab_bar.dart'; import 'package:flutter/gestures.dart'; @@ -14,7 +12,7 @@ typedef AnchorTabIndexedBuilder = BadgeTab Function(BuildContext context, int in class BrnAnchorTab extends StatefulWidget { // TabBar的样式 final BrnAnchorTabBarStyle tabBarStyle; - final AnchorTabWidgetIndexedBuilder widgetIndexedBuilder; + final AnchorTabWidgetIndexedBuilder? widgetIndexedBuilder; final AnchorTabIndexedBuilder tabIndexedBuilder; final Widget? tabDivider; @@ -153,7 +151,7 @@ class _BrnScrollAnchorTabWidgetState extends State if (widget.widgetIndexedBuilder != null) { for (int i = 0, n = widget.itemCount; i < n; i++) { Widget itemWidget = - Container(key: _bodyKeyList[i], child: widget.widgetIndexedBuilder(context, i)); + Container(key: _bodyKeyList[i], child: widget.widgetIndexedBuilder!(context, i)); itemWidget = MeasureSize( onChange: (size) { _updateOffset(); diff --git a/lib/src/components/switch/brn_switch_button.dart b/lib/src/components/switch/brn_switch_button.dart new file mode 100644 index 00000000..98f59bf2 --- /dev/null +++ b/lib/src/components/switch/brn_switch_button.dart @@ -0,0 +1,75 @@ +import 'package:bruno/src/theme/brn_theme.dart'; +import 'package:flutter/material.dart'; + +import 'brn_switch_button_base.dart'; + + +/// 描述: 开关按钮 +class BrnSwitchButton extends StatefulWidget { + final Size size; + + ///选中的状态 + final bool value; + + ///是否可以交互 + final bool enabled; + + ///点击事件 + final ValueChanged onChanged; + + ///未选中时边框的颜色 + final Color? borderColor; + + BrnSwitchButton({ + Key? key, + required this.value, + required this.onChanged, + this.enabled = true, + this.size = const Size(42, 26), + this.borderColor, + }) : super(key: key); + + @override + _BrnSwitchButtonState createState() => _BrnSwitchButtonState(); +} + +class _BrnSwitchButtonState extends State { + @override + Widget build(BuildContext context) { + return BrnBaseSwitchButton( + borderColor: widget.borderColor ?? _getBorderColor(), + value: widget.value, + enabled: widget.enabled, + size: widget.size, + trackColor: _getTrackColor(), + thumbColor: widget.enabled ? Colors.white : Color(0xFFFDFDFD), + onChanged: widget.enabled ? widget.onChanged : null, + ); + } + + Color _getTrackColor() { + if (widget.value) { + return widget.enabled + ? BrnThemeConfigurator.instance.getConfig().commonConfig.brandPrimary + : BrnThemeConfigurator.instance + .getConfig() + .commonConfig + .brandPrimary + .withAlpha(20); + } else { + return widget.enabled ? Color(0xFFFAFAFA) : Color(0xFFeeeeee); + } + } + + Color _getBorderColor() { + if (widget.value) { + return _getTrackColor(); + } else { + if (widget.enabled) { + return const Color(0xffeeeeee); + } else { + return const Color(0xffeeeeee); + } + } + } +} diff --git a/lib/src/components/switch/brn_switch_button_base.dart b/lib/src/components/switch/brn_switch_button_base.dart new file mode 100644 index 00000000..3e2a3bf7 --- /dev/null +++ b/lib/src/components/switch/brn_switch_button_base.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; + +const double _borderWidth = 1.5; + +class BrnBaseSwitchButton extends StatelessWidget { + final Size size; + + /// Whether this switch is on or off. + /// + /// This property must not be null. + final bool value; + + /// can click + final bool enabled; + + final ValueChanged? onChanged; + + final Color borderColor; + + final Color? trackColor; + + final Color thumbColor; + + const BrnBaseSwitchButton({ + Key? key, + required this.value, + required this.onChanged, + required this.size, + this.thumbColor = Colors.white, + this.trackColor, + this.borderColor = const Color(0xffeeeeee), + this.enabled = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + if (enabled) { + onChanged?.call(!value); + } + }, + child: Stack( + alignment: value ? Alignment.centerRight : Alignment.centerLeft, + children: [ + Container( + height: size.height, + width: size.width, + decoration: BoxDecoration( + color: trackColor, + border: Border.all( + color: value ? Colors.transparent : borderColor, + width: _borderWidth), + borderRadius: + BorderRadius.all(Radius.circular(size.height / 2)), + ), + ), + _getThumb(value) + ], + ), + ); + } + + Positioned _getThumb(bool value) { + return (value) + ? Positioned( + child: Padding( + padding: EdgeInsets.only(right: _borderWidth), + child: Container( + height: size.height - 2 * _borderWidth, + width: size.height - 2 * _borderWidth, + decoration: BoxDecoration( + color: thumbColor, + borderRadius: BorderRadius.all( + Radius.circular(size.height / 2 - _borderWidth)), + ), + ), + ), + ) + : Positioned( + child: Container( + height: size.height, + width: size.height, + decoration: BoxDecoration( + color: thumbColor, + border: Border.all(color: borderColor, width: _borderWidth), + borderRadius: + BorderRadius.all(Radius.circular(size.height / 2)), + ), + ), + ); + } +} From 3e28f7f2cb1ff44913a77f8611396eaf4d77dcf3 Mon Sep 17 00:00:00 2001 From: Sandy <15143015732@163.com> Date: Fri, 29 Apr 2022 14:25:15 +0800 Subject: [PATCH 17/19] update version to 2.2.0 (#201) * update version to 2.2.0 * update img size --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ README.en-US.md | 7 +++++++ README.md | 8 ++++++++ pubspec.yaml | 2 +- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aca34a4f..e39526f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +## [2.2.0] - 2022-4-29 + +### Changed + +#### base +- Adapt flutter sdk 2.10.5. +- Fix flutter analyze issues. +- Fixed some component theme configurations customization not taking effect [#177](https://github.com/LianjiaTech/bruno/issues/177) . + +#### components + +**New components** BrnSwitchFormItem BrnGeneralFormItem BrnMetaSwitch. + +- BrnTitleFormItem: fix isRequire parameter invalid [#179](https://github.com/LianjiaTech/bruno/issues/179). +- BrnTextBlockInputFormItem : change the minLines and maxLines attributes to be nullable [#181](https://github.com/LianjiaTech/bruno/pull/181) thanks to **xiao luobei**. +- BrnSelectionView : fix "unlimited" option not taking effect . +- BrnBottomTabBar: remove the restriction on type by item.length in the construction method. +- BrnPairInfoTable adds a callback attribute onFolded for expanding and collapsing state changes. +- BrnCheckbox: add attribute crossAxisAlignment. +- BrnRadioButton: add attribute crossAxisAlignment. +- BrnMiddleInputDialog: add attribute themeData support theme. +- BrnTextButtonPanel: optimize button display, fix the space cannot be filled in some cases. +- BrnCommonCardTitle: add attribute titleMaxLines and titleOverflow. +- BrnMultiSelectDialog: uses the default contentStyle of BrnDialogConfig. +- BrnScrollableTextDialog: optimize ScrollBar placement and styling. +- BrnSingleSelectDialog: Add click callback for closeIcon. +- BrnSelectionView: optimizes the data display of the [More] filter page, and supports the display of up to 2 rows. +- BrnTextInputFormItem BrnTextBlockInputFormItem BrnTitleSelectInputFormItem : add attribute autofocus and default value is false. +- BrnAppBar theme customization BrnAppBarConfig supports the attribute showDefaultBottom to control the bottom dividing line of the AppBar +- BrnMultiDataPicker: add default delegate implementationBrnDefaultMultiDataPickerDelegate. +- BrnStepInputFormItem: add attribute canManualInput and controller to support manual input function. +- BrnPairInfoTable: add a callback onExpanded for expanding and collapsing state changes. +- BrnSearchText: add attribute inputFormatterstextInputType. +- BrnAnchorTab: support content dynamic change. +- BrnProgressBarChart: when barChartStyle is BarChartStyle.horizontal support item click callback. + + + ## [2.1.1] - 2022-4-1 ### Changed diff --git a/README.en-US.md b/README.en-US.md index 56120bac..bf28ddc7 100644 --- a/README.en-US.md +++ b/README.en-US.md @@ -27,6 +27,12 @@ An enterprise-class package of Flutter components for mobile applications. ![](https://img.ljcdn.com/beike/zjz/bruno/img/1638883534391.png) +#### New components :tada: :tada: :tada: + +BrnSwitchButton BrnSwitchFormItem BrnGeneralFormItem + + + ## ✨ Features * Enterprise-class UI designed for mobile applications. @@ -49,6 +55,7 @@ If you cannot access the demo, you can directly watch [Overview](https://github. | 1.0.0 | 1.22.4 | | 2.0.0 | 2.2.2 | | 2.1.1 (support nullsafety) | 2.2.2 | +| 2.2.0 | 2.10.5 | ## Preparing for use diff --git a/README.md b/README.md index 11d3ef29..1f1b1696 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,13 @@ ![](https://img.ljcdn.com/beike/zjz/bruno/img/1638883534391.png) +#### 组件上新 :tada: :tada: :tada: + +BrnSwitchButton BrnSwitchFormItem BrnGeneralFormItem + + + + ## ✨ 特性 @@ -45,6 +52,7 @@ | 1.0.0 | 1.22.4 | | 2.0.0 | 2.2.2 | | 2.1.1 (支持空安全) | 2.2.2 | +| 2.2.0 | 2.10.5 | diff --git a/pubspec.yaml b/pubspec.yaml index 0553c37a..bd8ceea0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bruno description: An enterprise-class package of Flutter components for mobile applications. -version: 2.1.1 +version: 2.2.0 homepage: https://github.com/LianjiaTech/bruno environment: From e90f411fdcfceb8b699370d72a3e1b731b0a4e39 Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 29 Apr 2022 14:26:48 +0800 Subject: [PATCH 18/19] =?UTF-8?q?perf:=20`Example=20Theme`=20=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20Example=20=E4=B8=BB=E9=A2=98=E8=89=B2=E3=80=82=20(#?= =?UTF-8?q?204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: `Demo Theme` 修改 Demo 主题色。 * perf: remove async --- example/lib/main.dart | 2 +- example/web/main.dart | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index f1993428..af9a7870 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,7 +13,7 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Flutter Example', theme: ThemeData( - primarySwatch: Colors.grey, + primarySwatch: Colors.blue, ), home: HomePage(), ); diff --git a/example/web/main.dart b/example/web/main.dart index 002f07d0..6de19551 100644 --- a/example/web/main.dart +++ b/example/web/main.dart @@ -1,7 +1,21 @@ // TODO: change `my_app` to refer to your app package name. -import 'package:example/main.dart' as app; +import 'package:example/sample/home/home.dart'; +import 'package:flutter/material.dart'; -main() async { - app.main(); +main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Example', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: HomePage(), + ); + } } \ No newline at end of file From 66e9efeca07acbc8a17beeb718625f27a9ab6ccf Mon Sep 17 00:00:00 2001 From: violinday Date: Fri, 29 Apr 2022 15:47:58 +0800 Subject: [PATCH 19/19] change build_test flutter-version to 2.10.5 (#205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: `Demo Theme` 修改 Demo 主题色。 * perf: remove async * mod: change build_test flutter-version to 2.10.5 --- .github/workflows/build_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index e544af93..fef521c5 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -20,7 +20,7 @@ jobs: java-version: '8.x' - uses: subosito/flutter-action@v1 with: - flutter-version: '2.10.3' + flutter-version: '2.10.5' - run: dart --version - run: flutter --version - run: flutter pub get @@ -40,7 +40,7 @@ jobs: java-version: '8.x' - uses: subosito/flutter-action@v1 with: - flutter-version: '2.10.3' + flutter-version: '2.10.5' - run: dart --version - run: flutter --version - run: flutter pub get