├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── .gitignore ├── .metadata ├── README.md ├── SponsoredByMyTextAi.png ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── dev │ │ │ │ │ └── glasberg │ │ │ │ │ └── example_xaxa │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── lib │ ├── images │ │ ├── buttonBar.png │ │ ├── columnSuper.png │ │ ├── fitHorizontally.png │ │ ├── non_uniform_borders.png │ │ ├── rowSuperWithFitHorizontally.jpg │ │ ├── rowXRowSuperComparison.png │ │ ├── sideBySide.png │ │ ├── sideBySideComparison.gif │ │ ├── wrapFit1.png │ │ ├── wrapFit2.png │ │ ├── wrapFit3.png │ │ ├── wrapFit4.png │ │ └── wrapType.jpg │ ├── main_box.dart │ ├── main_button_and_circle_button.dart │ ├── main_button_bar_super.dart │ ├── main_capture_gestures.dart │ ├── main_column_removing_zero_height.dart │ ├── main_column_row_gestures.dart │ ├── main_column_super.dart │ ├── main_column_super_playground.dart │ ├── main_decorated_box.dart │ ├── main_delayed.dart │ ├── main_detect_scroll.dart │ ├── main_fit_horizontally.dart │ ├── main_fit_horizontally_baseline.dart │ ├── main_global_keys.dart │ ├── main_non_uniform_outline_input_border.dart │ ├── main_non_uniform_rounded_rectangle_border.dart │ ├── main_normalized_overflow_box.dart │ ├── main_row_spacer.dart │ ├── main_row_super.dart │ ├── main_row_super_alignment.dart │ ├── main_row_super_fill.dart │ ├── main_row_super_playground.dart │ ├── main_row_super_with_fit_horizontally.dart │ ├── main_row_with_row_super_comparison.dart │ ├── main_show_dialog_super.dart │ ├── main_side_by_side.dart │ ├── main_side_by_side_comparison.dart │ ├── main_text_one_line.dart │ ├── main_timer_builder.dart │ ├── main_wrap_super.dart │ └── main_wrap_super_fit.dart └── pubspec.yaml ├── lib ├── assorted_layout_widgets.dart └── src │ ├── box.dart │ ├── box_animating_width.dart │ ├── button.dart │ ├── button_bar_super.dart │ ├── capture_gestures.dart │ ├── circle_button.dart │ ├── column_super.dart │ ├── delayed.dart │ ├── detect_scroll.dart │ ├── fit_horizontally.dart │ ├── global_keys.dart │ ├── keyboard_dismiss.dart │ ├── mask_function_text_input_formatter.dart │ ├── minimum_raggedness.dart │ ├── non_uniform_outline_input_border.dart │ ├── non_uniform_rounded_rectangle_border.dart │ ├── normalized_overflow_box.dart │ ├── pad.dart │ ├── row_super.dart │ ├── scroll_shadow.dart │ ├── show_dialog_super.dart │ ├── side_by_side.dart │ ├── text_one_line.dart │ ├── time_builder.dart │ └── wrap_super.dart ├── pubspec.yaml └── test └── src ├── global_keys_test.dart └── minimum_raggedness_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/.flutter-plugins-dependencies 25 | **/flutter_export_environment.sh 26 | **/doc/api/ 27 | .dart_tool/ 28 | .flutter-plugins 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | build/ 34 | ios/.generated/ 35 | ios/Flutter/Generated.xcconfig 36 | ios/Runner/GeneratedPluginRegistrant.* 37 | pubspec.lock 38 | *.lock 39 | .flutter-plugins-dependencies 40 | 41 | # Android related 42 | **/android/**/gradle-wrapper.jar 43 | **/android/.gradle 44 | **/android/captures/ 45 | **/android/gradlew 46 | **/android/gradlew.bat 47 | **/android/local.properties 48 | **/android/**/GeneratedPluginRegistrant.java 49 | 50 | # iOS/XCode related 51 | **/ios/**/*.mode1v3 52 | **/ios/**/*.mode2v3 53 | **/ios/**/*.moved-aside 54 | **/ios/**/*.pbxuser 55 | **/ios/**/*.perspectivev3 56 | **/ios/**/*sync/ 57 | **/ios/**/.sconsign.dblite 58 | **/ios/**/.tags* 59 | **/ios/**/.vagrant/ 60 | **/ios/**/DerivedData/ 61 | **/ios/**/Icon? 62 | **/ios/**/Pods/ 63 | **/ios/**/.symlinks/ 64 | **/ios/**/profile 65 | **/ios/**/xcuserdata 66 | **/ios/.generated/ 67 | **/ios/Flutter/App.framework 68 | **/ios/Flutter/Flutter.framework 69 | **/ios/Flutter/Generated.xcconfig 70 | **/ios/Flutter/app.flx 71 | **/ios/Flutter/app.zip 72 | **/ios/Flutter/flutter_assets/ 73 | **/ios/Flutter/flutter_export_environment.sh 74 | **/ios/ServiceDefinitions.json 75 | **/ios/Runner/GeneratedPluginRegistrant.* 76 | 77 | # Exceptions to above rules. 78 | !**/ios/**/default.mode1v3 79 | !**/ios/**/default.mode2v3 80 | !**/ios/**/default.pbxuser 81 | !**/ios/**/default.perspectivev3 82 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 83 | /example/pubspec.lock 84 | /pubspec.lock 85 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 68587a0916366e9512a78df22c44163d041dd5f3 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 by Marcelo Glasberg 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted 4 | provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions 7 | and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of 10 | conditions and the following disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 15 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 20 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 17 | base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 18 | - platform: android 19 | create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 20 | base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | 1. ColumnSuper Example 4 | 5 | 2. RowSuper Example 6 | 7 | 3. RowSuper Fill Example 8 | 9 | 4. ColumnSuper Playground 10 | 11 | 5. RowSuper Playground 12 | 13 | 6. RowSuper with RowSpacer Example 14 | 15 | 7. RowSuper with FitHorizontally Example 16 | 17 | 8. FitHorizontally Example 18 | 19 | 9. Box Example 20 | 21 | 10. WrapSuper Example 22 | 23 | 11. WrapSuper WrapFit Example 24 | 25 | 12. ButtonBarSuper Example 26 | 27 | 13. NormalizedOverflowBox Example 28 | 29 | 14. TimeBuilder Example 30 | 31 | 15. SideBySide Example 32 | 33 | 16. SideBySide vs. Row vs. RowSuper 34 | 35 | 17. Button and CircleButton Example Example 36 | 37 | 18. CaptureGesture Example 38 | 39 | 19. NonUniformOutlineInputBorder Example 40 | 41 | 20. NonUniformRoundedRectangleBorder Example 42 | -------------------------------------------------------------------------------- /example/SponsoredByMyTextAi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/SponsoredByMyTextAi.png -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | errors: 3 | # treat missing required parameters as a warning (not a hint) 4 | missing_required_param: warning 5 | # treat missing returns as a warning (not a hint) 6 | missing_return: error 7 | # allow having TODOs in the code 8 | todo: ignore 9 | exclude: 10 | - 'bin/cache/**' 11 | - 'lib/src/http/**' 12 | 13 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 14 | linter: 15 | rules: 16 | - always_declare_return_types 17 | - annotate_overrides 18 | - avoid_empty_else 19 | - avoid_field_initializers_in_const_classes 20 | # - avoid_function_literals_in_foreach_calls 21 | - avoid_init_to_null 22 | - avoid_null_checks_in_equality_operators 23 | - avoid_relative_lib_imports 24 | - avoid_renaming_method_parameters 25 | - avoid_return_types_on_setters 26 | - avoid_slow_async_io 27 | - await_only_futures 28 | # - camel_case_types 29 | - cancel_subscriptions 30 | - control_flow_in_finally 31 | - directives_ordering 32 | - empty_catches 33 | - empty_constructor_bodies 34 | - empty_statements 35 | - hash_and_equals 36 | - implementation_imports 37 | - collection_methods_unrelated_type 38 | - library_names 39 | - library_prefixes 40 | - no_duplicate_case_values 41 | - overridden_fields 42 | - package_names 43 | - package_prefixed_library_names 44 | - prefer_adjacent_string_concatenation 45 | - prefer_asserts_in_initializer_lists 46 | - prefer_collection_literals 47 | - prefer_conditional_assignment 48 | - prefer_const_constructors 49 | # - prefer_const_constructors_in_immutables 50 | - prefer_const_declarations 51 | - prefer_contains 52 | - prefer_final_fields 53 | # - prefer_foreach 54 | - prefer_generic_function_type_aliases 55 | - prefer_initializing_formals 56 | - prefer_is_empty 57 | - prefer_is_not_empty 58 | - prefer_typing_uninitialized_variables 59 | - recursive_getters 60 | - slash_for_doc_comments 61 | - sort_unnamed_constructors_first 62 | - test_types_in_equals 63 | - throw_in_finally 64 | - type_init_formals 65 | - unnecessary_brace_in_string_interps 66 | - unnecessary_getters_setters 67 | - unnecessary_null_aware_assignments 68 | - unnecessary_null_in_if_null_operators 69 | - unnecessary_overrides 70 | - unnecessary_this 71 | - unrelated_type_equality_checks 72 | - use_rethrow_when_possible 73 | - valid_regexps 74 | # - unnecessary_new 75 | # - unnecessary_const 76 | # - non_constant_identifier_names 77 | # - always_put_control_body_on_new_line 78 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 79 | # - always_specify_types 80 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 81 | # - avoid_as 82 | # - avoid_bool_literals_in_conditional_expressions # not yet tested 83 | # - avoid_catches_without_on_clauses # we do this commonly 84 | # - avoid_catching_errors # we do this commonly 85 | # - avoid_classes_with_only_static_members 86 | # - avoid_double_and_int_checks # only useful when targeting JS runtime 87 | # - avoid_js_rounded_ints # only useful when targeting JS runtime 88 | # - avoid_positional_boolean_parameters # not yet tested 89 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 90 | # - avoid_returning_null # we do this commonly 91 | # - avoid_returning_this # https://github.com/dart-lang/linter/issues/842 92 | # - avoid_setters_without_getters # not yet tested 93 | # - avoid_single_cascade_in_expression_statements # not yet tested 94 | # - avoid_types_as_parameter_names # https://github.com/dart-lang/linter/pull/954/files 95 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 96 | # - avoid_unused_constructor_parameters # https://github.com/dart-lang/linter/pull/847 97 | # - cascade_invocations # not yet tested 98 | # - close_sinks # https://github.com/flutter/flutter/issues/5789 99 | # - comment_references # blocked on https://github.com/dart-lang/dartdoc/issues/1153 100 | # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 101 | # - invariant_booleans # https://github.com/flutter/flutter/issues/5790 102 | # - join_return_with_assignment # not yet tested 103 | # - literal_only_boolean_expressions # https://github.com/flutter/flutter/issues/5791 104 | # - no_adjacent_strings_in_list 105 | # - omit_local_variable_types # opposite of always_specify_types 106 | # - one_member_abstracts # too many false positives 107 | # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 108 | # - parameter_assignments # we do this commonly 109 | # - prefer_const_literals_to_create_immutables 110 | # - prefer_constructors_over_static_methods # not yet tested 111 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 112 | # - prefer_final_locals 113 | # - prefer_function_declarations_over_variables # not yet tested 114 | # - prefer_interpolation_to_compose_strings # not yet tested 115 | # - prefer_iterable_whereType # https://github.com/dart-lang/sdk/issues/32463 116 | # - prefer_single_quotes 117 | # - sort_constructors_first 118 | # - type_annotate_public_apis # subset of always_specify_types 119 | # - unawaited_futures # https://github.com/flutter/flutter/issues/5793 120 | # - unnecessary_lambdas # https://github.com/dart-lang/linter/issues/498 121 | # - unnecessary_parenthesis 122 | # - unnecessary_statements # not yet tested 123 | # - use_setters_to_change_properties # not yet tested 124 | # - use_string_buffers # https://github.com/dart-lang/linter/pull/664 125 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 126 | # - void_checks # not yet tested 127 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/to/reference-keystore 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | android { 9 | namespace = "dev.glasberg.example" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = flutter.ndkVersion 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_1_8 15 | targetCompatibility = JavaVersion.VERSION_1_8 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_1_8 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "dev.glasberg.example" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.debug 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/dev/glasberg/example_xaxa/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package dev.glasberg.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.1.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.8.22" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /example/lib/images/buttonBar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/buttonBar.png -------------------------------------------------------------------------------- /example/lib/images/columnSuper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/columnSuper.png -------------------------------------------------------------------------------- /example/lib/images/fitHorizontally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/fitHorizontally.png -------------------------------------------------------------------------------- /example/lib/images/non_uniform_borders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/non_uniform_borders.png -------------------------------------------------------------------------------- /example/lib/images/rowSuperWithFitHorizontally.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/rowSuperWithFitHorizontally.jpg -------------------------------------------------------------------------------- /example/lib/images/rowXRowSuperComparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/rowXRowSuperComparison.png -------------------------------------------------------------------------------- /example/lib/images/sideBySide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/sideBySide.png -------------------------------------------------------------------------------- /example/lib/images/sideBySideComparison.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/sideBySideComparison.gif -------------------------------------------------------------------------------- /example/lib/images/wrapFit1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/wrapFit1.png -------------------------------------------------------------------------------- /example/lib/images/wrapFit2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/wrapFit2.png -------------------------------------------------------------------------------- /example/lib/images/wrapFit3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/wrapFit3.png -------------------------------------------------------------------------------- /example/lib/images/wrapFit4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/wrapFit4.png -------------------------------------------------------------------------------- /example/lib/images/wrapType.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcglasberg/assorted_layout_widgets/d07de6a67b54d534612329896e78e3e7941fff32/example/lib/images/wrapType.jpg -------------------------------------------------------------------------------- /example/lib/main_box.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({ super.key }); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | // 13 | return Scaffold( 14 | appBar: AppBar(title: const Text('Box Example')), 15 | body: SingleChildScrollView( 16 | child: Center( 17 | child: Column( 18 | children: [ 19 | example1(), 20 | example2(), 21 | example3(), 22 | example4(), 23 | example5(), 24 | example6(), 25 | example7(), 26 | example8(), 27 | example9(), 28 | example10(), 29 | example11(), 30 | example12(), 31 | example13(), 32 | example14(), 33 | example15(), 34 | example16(), 35 | example17(), 36 | example18(), 37 | ], 38 | ), 39 | ), 40 | ), 41 | ); 42 | } 43 | 44 | Widget example1() => const Box( 45 | color: Colors.purple, 46 | child: Text("Test 1"), 47 | ); 48 | 49 | Widget example2() => const Box.r( 50 | child: Text("Test 2"), 51 | ); 52 | 53 | // This is hidden because of show: false. 54 | Widget example3() => const Box.g( 55 | show: false, 56 | padding: Pad(top: 20), 57 | child: Text("Test 3"), 58 | ); 59 | 60 | Widget example4() => const Box.b( 61 | padding: Pad(top: 10, bottom: 10), 62 | child: Text("Test 4"), 63 | ); 64 | 65 | // This is hidden because child is null. Padding is applied. 66 | Widget example5() => const Box.y( 67 | color: Colors.purple, 68 | padding: Pad(top: 20), 69 | ); 70 | 71 | // This is the same as top:10, bottom:10. 72 | Widget example6() => const Box.r( 73 | padding: Pad(vertical: 10), 74 | child: Text("Test 6"), 75 | ); 76 | 77 | // This is the same as right:10, left:10. 78 | Widget example7() => const Box.g( 79 | padding: Pad(horizontal: 10), 80 | child: Text("Test 7"), 81 | ); 82 | 83 | Widget example8() => const Box.b( 84 | width: 200, 85 | height: 100, 86 | child: Text("Test 8"), 87 | ); 88 | 89 | Widget example9() => const Box.y( 90 | padding: Pad(vertical: 20, horizontal: 40), 91 | width: 200, 92 | height: 100, 93 | child: Text("Test 9"), 94 | ); 95 | 96 | // This will change color in each rebuild. 97 | Widget example10() => const Box.rand( 98 | padding: Pad(vertical: 20, horizontal: 40), 99 | child: Text("Test 10"), 100 | ); 101 | 102 | Box redBox(String text) => Box( 103 | color: Colors.red, 104 | padding: const Pad(vertical: 5, horizontal: 5), 105 | width: 280, 106 | height: 35, 107 | child: Text(text), 108 | ); 109 | 110 | Widget example11() => Padding( 111 | padding: const Pad(all: 2.0), 112 | child: redBox('box'), 113 | ); 114 | 115 | Widget example12() => Padding( 116 | padding: const Pad(all: 2.0), 117 | child: redBox('box + Colors.blue') + Colors.blue, 118 | ); 119 | 120 | Widget example13() => Padding( 121 | padding: const Pad(all: 2.0), 122 | child: redBox('box + Pad(left: 10)') + const Pad(left: 10), 123 | ); 124 | 125 | Widget example14() => Padding( 126 | padding: const Pad(all: 2.0), 127 | child: redBox('box + Alignment.bottomRight') + Alignment.bottomRight, 128 | ); 129 | 130 | Widget example15() => Padding( 131 | padding: const Pad(all: 2.0), 132 | child: const Box.b(padding: Pad(all: 8.0)) + redBox('Box.b(padding: Pad(all: 8.0)) + box'), 133 | ); 134 | 135 | // Must remove padding when has no child. But has child, so don't remove padding. 136 | Widget example16() => const Box( 137 | color: Colors.red, 138 | padding: Pad(all: 20.0), 139 | removePaddingWhenNoChild: true, 140 | child: Text('Has padding'), 141 | ); 142 | 143 | // Not visible: 144 | // Must remove padding when has no child. Has child, so removes padding. 145 | Widget example17() => const Box( 146 | color: Colors.green, 147 | padding: Pad(all: 20.0), 148 | removePaddingWhenNoChild: true, 149 | ); 150 | 151 | // Must NOT remove padding when has no child. Has no child, but don't remove padding. 152 | Widget example18() => const Box( 153 | color: Colors.green, 154 | padding: Pad(all: 20.0), 155 | removePaddingWhenNoChild: false, 156 | ); 157 | } 158 | -------------------------------------------------------------------------------- /example/lib/main_button_and_circle_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('Button and CircleButton Example')), 14 | body: SingleChildScrollView( 15 | child: Center( 16 | child: Column( 17 | children: [ 18 | _button(), 19 | const Box(height: 16), 20 | _circleButton(), 21 | const Box(height: 16), 22 | ], 23 | ), 24 | ), 25 | ), 26 | ); 27 | } 28 | 29 | Box _button() { 30 | return Box( 31 | padding: const EdgeInsets.all(16.0), 32 | color: Colors.indigo, 33 | child: Column( 34 | children: [ 35 | const Text('Button', 36 | style: TextStyle( 37 | fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white)), 38 | const Box(height: 20), 39 | Row( 40 | children: [ 41 | Expanded( 42 | child: Center( 43 | child: Button( 44 | builder: ({required bool isPressed}) { 45 | return Box( 46 | padding: const Pad(all: 8.0), 47 | color: isPressed ? Colors.blue : Colors.transparent, 48 | child: Text( 49 | 'Click Me', 50 | style: TextStyle( 51 | fontSize: 23, 52 | color: isPressed ? Colors.black : Colors.white), 53 | ), 54 | ); 55 | }, 56 | minVisualTapDuration: const Duration(milliseconds: 500), 57 | clickAreaMargin: const Pad(horizontal: 10.0, vertical: 45), 58 | onTap: () {}, 59 | ), 60 | ), 61 | ), 62 | Expanded( 63 | child: Center( 64 | child: Button( 65 | builder: ({required bool isPressed}) { 66 | return Box( 67 | padding: const Pad(all: 8.0), 68 | color: isPressed ? Colors.blue : Colors.transparent, 69 | child: Text( 70 | 'Click Me', 71 | style: TextStyle( 72 | fontSize: 23, 73 | color: isPressed ? Colors.black : Colors.white), 74 | ), 75 | ); 76 | }, 77 | minVisualTapDuration: const Duration(milliseconds: 500), 78 | clickAreaMargin: const Pad(horizontal: 10.0, vertical: 45), 79 | debugShowClickableArea: true, 80 | onTap: () {}, 81 | ), 82 | ), 83 | ), 84 | ], 85 | ), 86 | const Box(height: 20), 87 | const Text( 88 | 'Button(\n' 89 | ' builder: ({required bool isPressed}) => ...\n' 90 | ' minVisualTapDuration: Duration(milliseconds: 500),\n' 91 | ' clickAreaMargin: Pad(horizontal: 10.0, vertical: 45),\n' 92 | ' debugShowClickableArea: false / true', 93 | style: TextStyle(color: Colors.white), 94 | ), 95 | ], 96 | ), 97 | ); 98 | } 99 | 100 | Box _circleButton() { 101 | return Box( 102 | padding: const EdgeInsets.all(16.0), 103 | color: Colors.indigo, 104 | child: Column( 105 | children: [ 106 | const Text('CircleButton', 107 | style: TextStyle( 108 | fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white)), 109 | const Box(height: 20), 110 | Row( 111 | children: [ 112 | Expanded( 113 | child: Center( 114 | child: CircleButton( 115 | icon: const Icon(Icons.shopping_cart, color: Colors.white), 116 | clickAreaMargin: const Pad(left: 30, right: 50, vertical: 20), 117 | backgroundColor: Colors.white30, 118 | tapColor: Colors.black, 119 | border: Border.all(width: 1, color: Colors.black), 120 | size: 56, 121 | onTap: () {}, 122 | builder: ({ 123 | required bool isHover, 124 | required bool isPressed, 125 | required Widget child, 126 | }) => 127 | AnimatedScale( 128 | scale: isPressed ? 1.15 : 1, 129 | duration: const Duration(milliseconds: 50), 130 | child: child, 131 | ), 132 | ), 133 | ), 134 | ), 135 | Expanded( 136 | child: Center( 137 | child: CircleButton( 138 | icon: const Icon(Icons.shopping_cart, color: Colors.white), 139 | clickAreaMargin: const Pad(left: 50, right: 30, vertical: 20), 140 | debugShowClickableArea: true, 141 | backgroundColor: Colors.white30, 142 | tapColor: Colors.black, 143 | border: Border.all(width: 1, color: Colors.black), 144 | size: 56, 145 | onTap: () {}, 146 | builder: ({ 147 | required bool isHover, 148 | required bool isPressed, 149 | required Widget child, 150 | }) => 151 | AnimatedScale( 152 | scale: isPressed ? 0.85 : 1, 153 | duration: const Duration(milliseconds: 50), 154 | child: child, 155 | ), 156 | ), 157 | ), 158 | ), 159 | ], 160 | ), 161 | const Box(height: 20), 162 | const Text( 163 | 'CircleButton(\n' 164 | ' icon: Icon(Icons.shopping_cart, color: Colors.white),\n' 165 | ' backgroundColor: Colors.white30,\n' 166 | ' tapColor: Colors.black,\n' 167 | ' border: Border.all(width: 1, color: Colors.black),\n' 168 | ' size: 56,\n' 169 | ' onTap: () {},\n' 170 | ' builder: ({isPressed, ...} => AnimatedScale(...),\n' 171 | ' clickAreaMargin: Pad(left: 50, right: 30, vertical: 20),\n' 172 | ' debugShowClickableArea: false / true', 173 | style: TextStyle(color: Colors.white), 174 | ), 175 | ], 176 | ), 177 | ); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /example/lib/main_button_bar_super.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({ super.key }); 8 | 9 | @override 10 | Widget build(BuildContext context) => Scaffold( 11 | appBar: AppBar(title: const Text('ButtonBarSuper Example')), 12 | body: Container( 13 | color: Colors.grey, 14 | alignment: Alignment.center, 15 | child: SingleChildScrollView( 16 | child: Column( 17 | children: [ 18 | _example(WrapType.fit, WrapFit.min), 19 | _example(WrapType.fit, WrapFit.proportional), 20 | _example(WrapType.fit, WrapFit.divided), 21 | _example(WrapType.fit, WrapFit.larger), 22 | _example(WrapType.balanced, WrapFit.min), 23 | _example(WrapType.balanced, WrapFit.proportional), 24 | _example(WrapType.balanced, WrapFit.divided), 25 | _example(WrapType.balanced, WrapFit.larger), 26 | const Box(height: 20), 27 | ], 28 | ), 29 | ), 30 | ), 31 | ); 32 | 33 | Column _example(WrapType wrapType, WrapFit wrapFit) { 34 | return Column( 35 | children: [ 36 | const Box(height: 22), 37 | Text('$wrapType | $wrapFit'), 38 | const Box(height: 5), 39 | Container( 40 | width: 300, 41 | color: Colors.grey[300], 42 | child: _bar(wrapType, wrapFit), 43 | ), 44 | ], 45 | ); 46 | } 47 | 48 | ButtonBarSuper _bar(WrapType wrapType, WrapFit wrapFit) { 49 | return ButtonBarSuper( 50 | buttonTextTheme: ButtonTextTheme.primary, 51 | wrapType: wrapType, 52 | wrapFit: wrapFit, 53 | spacing: 2.0, 54 | lineSpacing: 10.0, 55 | buttonHeight: 48, 56 | buttonMinWidth: 40, 57 | children: [ 58 | ElevatedButton( 59 | style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), 60 | onPressed: () {}, 61 | child: const Text('I am a blue button like you')), 62 | ElevatedButton( 63 | style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), 64 | onPressed: () {}, 65 | child: const Text('Hey'), 66 | ), 67 | ElevatedButton( 68 | style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), 69 | onPressed: () {}, 70 | child: const Text('I am a blue button, ok?'), 71 | ), 72 | ], 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/lib/main_capture_gestures.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({ super.key }); 8 | 9 | @override 10 | Widget build(BuildContext context) => Scaffold( 11 | appBar: AppBar(title: const Text('CaptureGestures Example')), 12 | body: ListView( 13 | physics: const BouncingScrollPhysics(), 14 | children: [ 15 | const Box(height: 30), 16 | _greenArea(), 17 | const Box(height: 30), 18 | _yellowArea(), 19 | const Box(height: 2000), 20 | // 21 | ], 22 | ), 23 | ); 24 | 25 | Material _greenArea() { 26 | return Material( 27 | color: Colors.green[200], 28 | child: InkWell( 29 | highlightColor: Colors.green, 30 | splashColor: Colors.green, 31 | onTap: () { 32 | print('Green area tapped.'); 33 | }, 34 | child: CaptureGestures.only( 35 | child: Padding( 36 | padding: const Pad(vertical: 30, horizontal: 50), 37 | child: Column( 38 | children: [ 39 | ElevatedButton( 40 | onPressed: () {}, 41 | child: const Text('Button'), 42 | ), 43 | const Box(height: 20), 44 | const Text('CaptureGestures.only()\n\n' 45 | 'This green area can be used to scroll.\n' 46 | 'The Button (child) feels taps.\n' 47 | 'The green area (parent) feels taps.'), 48 | ], 49 | ), 50 | ), 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | Material _yellowArea() { 57 | return Material( 58 | color: Colors.yellow, 59 | child: InkWell( 60 | highlightColor: Colors.yellow[800], 61 | splashColor: Colors.yellow[800], 62 | onTap: () { 63 | print('Yellow area tapped.'); 64 | }, 65 | child: CaptureGestures.scroll( 66 | child: Padding( 67 | padding: const Pad(vertical: 30, horizontal: 50), 68 | child: Column( 69 | children: [ 70 | Center( 71 | child: ElevatedButton( 72 | onPressed: () {}, 73 | child: const Text('Button'), 74 | ), 75 | ), 76 | const Box(height: 20), 77 | const Text('CaptureGestures.scroll()\n\n' 78 | 'This yellow area CANNOT be used to scroll.\n' 79 | 'The Button (child) feels taps.\n' 80 | 'The yellow area (parent) feels taps.'), 81 | ], 82 | ), 83 | ), 84 | ), 85 | ), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /example/lib/main_column_removing_zero_height.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar(title: const Text('ColumnSuper Remove Children')), 13 | body: const Column( 14 | children: [ 15 | Padding( 16 | padding: Pad(all: 20), 17 | child: 18 | Text("Click the colored boxes to turn their height to zero (they keep their width)." 19 | "\n\n" 20 | "The left column has removeChildrenWithNoHeight: false" 21 | "\n\n" 22 | "The right column has removeChildrenWithNoHeight: true"), 23 | ), 24 | Expanded( 25 | child: Center( 26 | child: Row( 27 | mainAxisSize: MainAxisSize.min, 28 | children: [ 29 | ColoredColumn(removeChildrenWithNoHeight: false), 30 | Box(width: 50), 31 | ColoredColumn(removeChildrenWithNoHeight: true), 32 | ], 33 | ), 34 | ), 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | 41 | Widget coloredBox(Color color, double height) => Container( 42 | color: color.withOpacity(0.8), 43 | width: 50, 44 | height: height, 45 | ); 46 | } 47 | 48 | class ColoredColumn extends StatefulWidget { 49 | final bool removeChildrenWithNoHeight; 50 | 51 | const ColoredColumn({super.key, required this.removeChildrenWithNoHeight}); 52 | 53 | @override 54 | State createState() => _ColoredColumnState(); 55 | } 56 | 57 | class _ColoredColumnState extends State { 58 | static const separator = Box(width: 80, height: 3, color: Colors.black38); 59 | 60 | Set zeroHeight = {}; 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Box( 65 | color: Colors.black12, 66 | child: ColumnSuper( 67 | separator: separator, 68 | innerDistance: 20, 69 | outerDistance: 10, 70 | removeChildrenWithNoHeight: widget.removeChildrenWithNoHeight, 71 | children: [ 72 | coloredBox(0, Colors.red, zeroHeight.contains(0) ? 0 : 10), 73 | coloredBox(1, Colors.green, zeroHeight.contains(1) ? 0 : 30), 74 | coloredBox(2, Colors.blue, zeroHeight.contains(2) ? 0 : 130), 75 | coloredBox(3, Colors.purple, zeroHeight.contains(3) ? 0 : 90), 76 | coloredBox(4, Colors.orange, zeroHeight.contains(4) ? 0 : 60), 77 | ], 78 | ), 79 | ); 80 | } 81 | 82 | Widget coloredBox(int index, Color color, double height) => GestureDetector( 83 | onTap: () { 84 | setState(() { 85 | zeroHeight.add(index); 86 | }); 87 | }, 88 | child: Container( 89 | color: color.withOpacity(0.8), 90 | width: 50 + index * 20, 91 | height: height, 92 | ), 93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /example/lib/main_column_row_gestures.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatefulWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | State createState() => _DemoState(); 11 | } 12 | 13 | class _DemoState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | // 17 | return Scaffold( 18 | appBar: AppBar(title: const Text('Gestures: ColumnSuper/RowSuper')), 19 | body: SizedBox.expand( 20 | child: Box( 21 | color: Colors.grey[300], 22 | child: SingleChildScrollView( 23 | child: Column( 24 | crossAxisAlignment: CrossAxisAlignment.stretch, 25 | children: [ 26 | const Padding( 27 | padding: Pad(all: 24.0), 28 | child: Center( 29 | child: Text('This demonstrate that the GestureDetector ' 30 | 'works as it should when applied to colum/row cells.'), 31 | ), 32 | ), 33 | Row( 34 | mainAxisAlignment: MainAxisAlignment.center, 35 | children: [ 36 | Column( 37 | children: [ 38 | const Text('normal'), 39 | ColumnSuper( 40 | innerDistance: -40.0, 41 | outerDistance: 0.0, 42 | children: [ 43 | box(Colors.red, 'red'), 44 | box(Colors.green, 'green'), 45 | box(Colors.blue, 'blue'), 46 | ], 47 | ), 48 | ], 49 | ), 50 | // 51 | const Box(width: 30), 52 | // 53 | Column( 54 | children: [ 55 | const Text('inverted'), 56 | ColumnSuper( 57 | innerDistance: -40.0, 58 | outerDistance: 0.0, 59 | invert: true, 60 | children: [ 61 | box(Colors.red, 'red'), 62 | box(Colors.green, 'green'), 63 | box(Colors.blue, 'blue'), 64 | ], 65 | ), 66 | ], 67 | ), 68 | ], 69 | ), 70 | // 71 | const Box(height: 50), 72 | // 73 | Column( 74 | children: [ 75 | Column( 76 | children: [ 77 | const Text('normal'), 78 | RowSuper( 79 | innerDistance: -40.0, 80 | outerDistance: 8.0, 81 | children: [ 82 | box(Colors.red, 'red'), 83 | box(Colors.green, 'green'), 84 | box(Colors.blue, 'blue'), 85 | ], 86 | ), 87 | ], 88 | ), 89 | // 90 | const Box(height: 30), 91 | // 92 | Column( 93 | children: [ 94 | const Text('inverted'), 95 | RowSuper( 96 | innerDistance: -40.0, 97 | outerDistance: 8.0, 98 | invert: true, 99 | children: [ 100 | box(Colors.red, 'red'), 101 | box(Colors.green, 'green'), 102 | box(Colors.blue, 'blue'), 103 | ], 104 | ), 105 | ], 106 | ), 107 | ], 108 | ), 109 | ], 110 | ), 111 | ), 112 | ), 113 | ), 114 | ); 115 | } 116 | 117 | Widget box(Color color, String name) { 118 | return GestureDetector( 119 | onTap: () { 120 | ScaffoldMessenger.of(context).showSnackBar( 121 | SnackBar( 122 | content: Text( 123 | 'Tapped ${name.toUpperCase()}', 124 | style: const TextStyle(fontSize: 24), 125 | ), 126 | duration: const Duration(seconds: 1), 127 | ), 128 | ); 129 | }, 130 | child: Box(width: 100, height: 100, color: color.withOpacity(0.95)), 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /example/lib/main_column_super.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('ColumnSuper Example')), 14 | body: SizedBox.expand( 15 | child: SingleChildScrollView( 16 | child: ColumnSuper( 17 | innerDistance: 8.0, 18 | outerDistance: 8.0, 19 | children: [ 20 | example1(), 21 | example2(), 22 | example3(), 23 | example4(), 24 | example5(), 25 | example6(), 26 | example7(), 27 | example8(), 28 | example9(), 29 | example10(), 30 | example11(), 31 | example12(), 32 | example13(), 33 | example14(), 34 | example15(), 35 | example16(), 36 | ], 37 | ), 38 | ), 39 | ), 40 | ); 41 | } 42 | 43 | Widget example1() => Container( 44 | color: Colors.yellow, 45 | child: ColumnSuper( 46 | alignment: Alignment.center, 47 | invert: false, 48 | children: [redBox(), blueBox()], 49 | ), 50 | ); 51 | 52 | Widget example2() => Container( 53 | color: Colors.yellow, 54 | child: ColumnSuper( 55 | outerDistance: -3, 56 | alignment: Alignment.center, 57 | invert: false, 58 | children: [redBox(), blueBox()], 59 | ), 60 | ); 61 | 62 | Widget example3() => Container( 63 | color: Colors.yellow, 64 | child: ColumnSuper( 65 | alignment: Alignment.center, 66 | invert: false, 67 | innerDistance: -15, 68 | children: [redBox(), blueBox()], 69 | ), 70 | ); 71 | 72 | Widget example4() => Container( 73 | color: Colors.yellow, 74 | child: ColumnSuper( 75 | alignment: Alignment.center, 76 | invert: true, 77 | innerDistance: -15, 78 | children: [redBox(), blueBox()], 79 | ), 80 | ); 81 | 82 | Widget example5() => Container( 83 | color: Colors.yellow, 84 | child: ColumnSuper( 85 | alignment: Alignment.center, 86 | invert: false, 87 | outerDistance: 5, 88 | innerDistance: -15, 89 | children: [null, redBox(), null, blueBox(), null], 90 | ), 91 | ); 92 | 93 | Widget example6() => Container( 94 | color: Colors.yellow, 95 | child: ColumnSuper( 96 | alignment: Alignment.centerRight, 97 | innerDistance: -15, 98 | children: [redBox(), blueBox()], 99 | ), 100 | ); 101 | 102 | Widget example7() => Container( 103 | color: Colors.yellow, 104 | child: ColumnSuper( 105 | alignment: Alignment.centerLeft, 106 | innerDistance: -15, 107 | children: [redBox(), blueBox()], 108 | ), 109 | ); 110 | 111 | Widget example8() => Container( 112 | color: Colors.yellow, 113 | child: ColumnSuper( 114 | alignment: Alignment.centerLeft, 115 | innerDistance: 20, 116 | separator: separator(), 117 | children: [redBox(), blueBox()], 118 | ), 119 | ); 120 | 121 | Widget example9() => Container( 122 | color: Colors.yellow, 123 | child: ColumnSuper( 124 | alignment: Alignment.center, 125 | innerDistance: 20, 126 | separator: separator(), 127 | children: [redBox(), blueBox()], 128 | ), 129 | ); 130 | 131 | Widget example10() => Container( 132 | color: Colors.yellow, 133 | child: ColumnSuper( 134 | alignment: Alignment.center, 135 | innerDistance: 0, 136 | separator: separator(), 137 | children: [redBox(), blueBox()], 138 | ), 139 | ); 140 | 141 | Widget example11() => Container( 142 | color: Colors.yellow, 143 | child: ColumnSuper( 144 | alignment: Alignment.center, 145 | innerDistance: 0, 146 | separator: separator(), 147 | separatorOnTop: false, 148 | children: [redBox(), blueBox()], 149 | ), 150 | ); 151 | 152 | Widget example12() => Container( 153 | color: Colors.yellow, 154 | child: ColumnSuper( 155 | alignment: Alignment.center, 156 | innerDistance: -45, 157 | separatorOnTop: false, 158 | children: const [ 159 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 160 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 161 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 162 | ], 163 | ), 164 | ); 165 | 166 | Widget example13() => Container( 167 | color: Colors.yellow, 168 | child: ColumnSuper( 169 | alignment: Alignment.center, 170 | innerDistance: -45, 171 | invert: true, 172 | separatorOnTop: false, 173 | children: const [ 174 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 175 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 176 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 177 | ], 178 | ), 179 | ); 180 | 181 | Widget example14() => Container( 182 | color: Colors.yellow, 183 | child: ColumnSuper( 184 | alignment: Alignment.center, 185 | innerDistance: 0, 186 | separator: Container( 187 | width: 200, 188 | height: 1, 189 | color: Colors.black, 190 | ), 191 | separatorOnTop: false, 192 | children: const [ 193 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 194 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 195 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 196 | ], 197 | ), 198 | ); 199 | 200 | Widget example15() => Container( 201 | color: Colors.yellow, 202 | child: ColumnSuper( 203 | alignment: Alignment.center, 204 | innerDistance: 0, 205 | separator: Container( 206 | width: 200, 207 | height: 40, 208 | color: Colors.black, 209 | ), 210 | separatorOnTop: false, 211 | children: const [ 212 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 213 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 214 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 215 | ], 216 | ), 217 | ); 218 | 219 | Widget example16() => Container( 220 | color: Colors.yellow, 221 | child: ColumnSuper( 222 | alignment: Alignment.center, 223 | innerDistance: 0, 224 | separator: Container( 225 | width: 200, 226 | height: 40, 227 | color: Colors.black, 228 | ), 229 | separatorOnTop: true, 230 | children: const [ 231 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 232 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 233 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 234 | ], 235 | ), 236 | ); 237 | 238 | Widget separator() => Container( 239 | width: 70, 240 | height: 14, 241 | color: Colors.black.withOpacity(0.5), 242 | ); 243 | 244 | Widget redBox() => Container( 245 | width: 50, 246 | height: 50, 247 | color: Colors.red, 248 | ); 249 | 250 | Widget blueBox() => Container( 251 | width: 70, 252 | height: 30, 253 | color: Colors.blue.withOpacity(0.80), 254 | ); 255 | } 256 | -------------------------------------------------------------------------------- /example/lib/main_column_super_playground.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatefulWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | State createState() => _DemoState(); 11 | } 12 | 13 | class _DemoState extends State { 14 | late int itemCount; 15 | late double width; 16 | late double height; 17 | late double outer; 18 | late double inner; 19 | late bool withSeparator; 20 | late Alignment alignment; 21 | late double separatorHeight; 22 | late double? parentWidth; 23 | late bool intrinsic; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | itemCount = 5; 29 | width = height = 10.0; 30 | inner = 8.0; 31 | outer = 16.0; 32 | withSeparator = true; 33 | alignment = Alignment.center; 34 | separatorHeight = 1.0; 35 | parentWidth = null; 36 | intrinsic = false; 37 | } 38 | 39 | void _reset() { 40 | itemCount = 0; 41 | width = height = 10.0; 42 | inner = 0.0; 43 | outer = 0.0; 44 | withSeparator = true; 45 | alignment = Alignment.center; 46 | separatorHeight = 1.0; 47 | parentWidth = null; 48 | intrinsic = false; 49 | } 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | print('---'); 54 | print('count = $itemCount'); 55 | print('width = $width'); 56 | print('height = $height'); 57 | print('inner = $inner'); 58 | print('outer = $outer'); 59 | print('withSeparator = $withSeparator'); 60 | print('separatorHeight = $separatorHeight'); 61 | 62 | return Scaffold( 63 | appBar: AppBar(title: const Text('ColumnSuper Playground')), 64 | body: Column( 65 | children: [ 66 | Expanded( 67 | child: Center( 68 | child: SingleChildScrollView( 69 | child: Column( 70 | children: [ 71 | blueBox(), 72 | if (intrinsic) 73 | IntrinsicWidth( 74 | child: IntrinsicHeight(child: _content()), 75 | ) 76 | else 77 | _content(), 78 | blueBox(), 79 | ], 80 | ), 81 | ), 82 | ), 83 | ), 84 | // 85 | Container( 86 | width: double.infinity, 87 | color: Colors.grey, 88 | padding: const EdgeInsets.symmetric(vertical: 6.0), 89 | child: Column( 90 | children: [ 91 | Row( 92 | mainAxisSize: MainAxisSize.min, 93 | children: [ 94 | button("Add Item", () => itemCount++, color: Colors.green), 95 | button("Reset", _reset, color: Colors.red), 96 | ], 97 | ), 98 | Row( 99 | mainAxisSize: MainAxisSize.min, 100 | children: [ 101 | button("- Width", () => width -= (width > 0.0) ? 1.0 : 0.0), 102 | button("+ Width", () => width += 1.0), 103 | const Box(width: 10.0), 104 | button("- Height", () => height -= (height > 0.0) ? 1.0 : 0.0), 105 | button("+ Height", () => height += 1.0), 106 | ], 107 | ), 108 | Row( 109 | mainAxisSize: MainAxisSize.min, 110 | children: [ 111 | button("- Inner", () => inner -= 1.0), 112 | button("+ Inner", () => inner += 1.0), 113 | Text(" $inner"), 114 | ], 115 | ), 116 | Row( 117 | mainAxisSize: MainAxisSize.min, 118 | children: [ 119 | button("- Outer", () => outer -= 1.0), 120 | button("+ Outer", () => outer += 1.0), 121 | Text(" $outer"), 122 | ], 123 | ), 124 | Row( 125 | mainAxisSize: MainAxisSize.min, 126 | children: [ 127 | button("Separator ${withSeparator ? 'On' : 'Off'}", 128 | () => withSeparator = !withSeparator), 129 | button( 130 | "- Sep", 131 | withSeparator 132 | ? () => separatorHeight -= (separatorHeight > 0.0) ? 1.0 : 0.0 133 | : null), 134 | button("+ Sep", withSeparator ? () => separatorHeight += 1.0 : null), 135 | Text(" $separatorHeight"), 136 | ], 137 | ), 138 | Row( 139 | mainAxisSize: MainAxisSize.min, 140 | children: [ 141 | button("Parent Width = $parentWidth", () { 142 | if (parentWidth == null) { 143 | parentWidth = 70.0; 144 | } else if (parentWidth == 70.0) { 145 | parentWidth = double.infinity; 146 | } else if (parentWidth == double.infinity) { 147 | parentWidth = null; 148 | } 149 | }), 150 | const Box(width: 10.0), 151 | button("Alignment = $alignment", () { 152 | if (alignment == Alignment.center) { 153 | alignment = Alignment.topLeft; 154 | } else if (alignment == Alignment.topLeft) { 155 | alignment = Alignment.topRight; 156 | } else if (alignment == Alignment.topRight) { 157 | alignment = Alignment.center; 158 | } 159 | }), 160 | ], 161 | ), 162 | button("Intrinsic Width/Height = $intrinsic", () => intrinsic = !intrinsic), 163 | ], 164 | ), 165 | ), 166 | ], 167 | ), 168 | ); 169 | } 170 | 171 | Container _content() { 172 | return Container( 173 | color: Colors.yellow, 174 | width: parentWidth, 175 | child: ColumnSuper( 176 | alignment: alignment, 177 | separator: withSeparator ? separator() : null, 178 | innerDistance: inner, 179 | outerDistance: outer, 180 | removeChildrenWithNoHeight: true, 181 | children: [ 182 | for (int i = 0; i < itemCount; i++) coloredBox(i), 183 | ], 184 | ), 185 | ); 186 | } 187 | 188 | Widget button(String label, VoidCallback? func, {Color color = Colors.blue}) => Padding( 189 | padding: const EdgeInsets.symmetric(vertical: 4.0), 190 | child: MaterialButton( 191 | visualDensity: const VisualDensity(vertical: -1.0, horizontal: -3.0), 192 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 193 | color: color, 194 | onPressed: (func == null) ? null : () => setState(func), 195 | child: Text(label), 196 | ), 197 | ); 198 | 199 | Widget separator() => Container( 200 | width: 100, 201 | height: separatorHeight, 202 | color: Colors.black.withOpacity(0.5), 203 | ); 204 | 205 | Widget coloredBox(int index) => Container( 206 | decoration: BoxDecoration( 207 | color: Colors.red.withOpacity(0.5), 208 | border: Border.all(width: 0.5, color: Colors.black), 209 | ), 210 | width: width + index * 10.0, 211 | height: height, 212 | ); 213 | 214 | Widget blueBox() => Container( 215 | width: 120, 216 | height: 15, 217 | color: Colors.blue.withOpacity(0.80), 218 | ); 219 | } 220 | -------------------------------------------------------------------------------- /example/lib/main_decorated_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | /// Here we test the Box widget with decoration. 7 | /// If Box.color is defined, then the decoration cannot be defined, or it can 8 | /// be defined without a color (works for BoxDecoration and ShapeDecoration only). 9 | class Demo extends StatelessWidget { 10 | const Demo({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | // 15 | return Scaffold( 16 | appBar: AppBar(title: const Text('Box with Decoration Example')), 17 | body: SingleChildScrollView( 18 | child: Center( 19 | child: Column( 20 | children: [ 21 | example1(), 22 | const Box.gap(24), 23 | example2(), 24 | const Box.gap(24), 25 | example3(), 26 | const Box.gap(24), 27 | example4(), 28 | const Box.gap(24), 29 | example5(), 30 | ], 31 | ), 32 | ), 33 | ), 34 | ); 35 | } 36 | 37 | /// Color is separate, and Box decoration without color. 38 | Widget example1() => const Box( 39 | width: 100, 40 | height: 100, 41 | child: Text("Test 1"), 42 | color: Colors.purple, 43 | // Separate color. 44 | decoration: BoxDecoration( 45 | border: Border.symmetric( 46 | vertical: BorderSide(color: Colors.red, width: 6), 47 | horizontal: BorderSide(color: Colors.green, width: 16), 48 | ), 49 | ), 50 | ); 51 | 52 | /// Box decoration with color. 53 | Widget example2() => const Box( 54 | width: 100, 55 | height: 100, 56 | child: Text("Test 2"), 57 | decoration: BoxDecoration( 58 | color: Colors.yellow, // Color in decoration. 59 | border: Border.symmetric( 60 | vertical: BorderSide(color: Colors.red, width: 6), 61 | horizontal: BorderSide(color: Colors.green, width: 16), 62 | ), 63 | ), 64 | ); 65 | 66 | /// Bor.r etc overrides the color. 67 | Widget example3() => const Box.r( 68 | width: 100, 69 | height: 100, 70 | child: Text("Test 3"), 71 | color: Colors.black, 72 | decoration: BoxDecoration( 73 | color: Colors.black, 74 | border: Border.symmetric( 75 | vertical: BorderSide(color: Colors.red, width: 6), 76 | horizontal: BorderSide(color: Colors.green, width: 16), 77 | ), 78 | ), 79 | ); 80 | 81 | /// Bor.r etc overrides the color in the decoration. 82 | Widget example4() => const Box.r( 83 | width: 100, 84 | height: 100, 85 | child: Text("Test 4"), 86 | decoration: BoxDecoration( 87 | color: Colors.black, 88 | border: Border.symmetric( 89 | vertical: BorderSide(color: Colors.red, width: 6), 90 | horizontal: BorderSide(color: Colors.green, width: 16), 91 | ), 92 | ), 93 | ); 94 | 95 | /// Bor.rand etc overrides the color in the decoration. 96 | Widget example5() => const Box.rand( 97 | width: 100, 98 | height: 100, 99 | child: Text("Test 5"), 100 | color: Colors.black, 101 | decoration: BoxDecoration( 102 | color: Colors.black, 103 | border: Border.symmetric( 104 | vertical: BorderSide(color: Colors.red, width: 6), 105 | horizontal: BorderSide(color: Colors.green, width: 16), 106 | ), 107 | ), 108 | ); 109 | } 110 | -------------------------------------------------------------------------------- /example/lib/main_delayed.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('Delayed Example')), 14 | key: UniqueKey(), // Forces restart on hot reload. 15 | body: SingleChildScrollView( 16 | child: Column( 17 | children: [ 18 | for (int i = 0; i <= 100; i++) 19 | _delayed(i == 0 ? null : Duration(milliseconds: i * 500)), 20 | ], 21 | ), 22 | ), 23 | ); 24 | } 25 | 26 | Widget _delayed(Duration? delay) { 27 | return Delayed( 28 | delay: delay, 29 | builder: (_, bool initialized) => AnimatedOpacity( 30 | opacity: initialized ? 1.0 : 0.0, 31 | duration: const Duration(milliseconds: 500), 32 | child: _myWidget(delay?.inMilliseconds), 33 | ), 34 | ); 35 | } 36 | 37 | Widget _myWidget(int? delay) { 38 | // ignore: deprecated_member_use 39 | return Box.rand( 40 | height: 50.0, 41 | child: Center(child: Text(delay.toString())), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/lib/main_detect_scroll.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() { 6 | runApp( 7 | const HomePage(), 8 | ); 9 | } 10 | 11 | class HomePage extends StatelessWidget { 12 | const HomePage({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return MaterialApp( 17 | theme: ThemeData(scrollbarTheme: _scrollbarTheme()), 18 | home: const Demo(), 19 | ); 20 | } 21 | 22 | /// This theme makes the scrollbar always visible, with a thickness of 20 px. 23 | ScrollbarThemeData _scrollbarTheme() { 24 | return ScrollbarThemeData( 25 | thumbVisibility: MaterialStateProperty.all(true), 26 | trackVisibility: MaterialStateProperty.all(true), 27 | thickness: MaterialStateProperty.all(20.0), 28 | interactive: true, 29 | radius: const Radius.circular(8), 30 | minThumbLength: 32, 31 | trackColor: MaterialStateProperty.all(Colors.blue[100]), 32 | thumbColor: MaterialStateProperty.all(Colors.blue[900]), 33 | crossAxisMargin: 0, 34 | mainAxisMargin: 0, 35 | ); 36 | } 37 | } 38 | 39 | class Demo extends StatefulWidget { 40 | const Demo({super.key}); 41 | 42 | @override 43 | State createState() => _DemoState(); 44 | } 45 | 46 | class _DemoState extends State { 47 | int lines = 10; 48 | 49 | bool canScroll = false; 50 | double scrollbarWidth = 0; 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | return Scaffold( 55 | appBar: AppBar(title: const Text('DetectScroll Example')), 56 | body: Column( 57 | children: [ 58 | // 59 | Expanded( 60 | child: DetectScroll( 61 | onChange: _onChange, 62 | child: LinesOfText(lines: lines), 63 | ), 64 | ), 65 | // 66 | const Box.gap(20), 67 | Text('onChange gets: canScroll=$canScroll, scrollbarWidth=$scrollbarWidth'), 68 | const Box.gap(20), 69 | Padding( 70 | padding: const Pad(horizontal: 20), 71 | child: Row( 72 | children: [ 73 | Expanded( 74 | child: ElevatedButton( 75 | onPressed: () { 76 | setState(() { 77 | lines += 10; 78 | }); 79 | }, 80 | child: const Text('Add lines'), 81 | ), 82 | ), 83 | const Box.gap(20), 84 | Expanded( 85 | child: ElevatedButton( 86 | onPressed: () { 87 | setState(() { 88 | lines -= 10; 89 | if (lines < 0) lines = 0; 90 | }); 91 | }, 92 | child: const Text('Remove lines'), 93 | ), 94 | ), 95 | ], 96 | ), 97 | ), 98 | const Box.gap(40), 99 | ], 100 | ), 101 | ); 102 | } 103 | 104 | /// This callback is called whenever the scroll state changes. 105 | void _onChange({ 106 | required bool canScroll, 107 | required double scrollbarWidth, 108 | }) { 109 | setState(() { 110 | this.canScroll = canScroll; 111 | this.scrollbarWidth = scrollbarWidth; 112 | }); 113 | } 114 | } 115 | 116 | class LinesOfText extends StatelessWidget { 117 | final int lines; 118 | 119 | const LinesOfText({ 120 | super.key, 121 | required this.lines, 122 | }); 123 | 124 | @override 125 | Widget build(BuildContext context) { 126 | final ScrollController scrollController = ScrollController(); 127 | 128 | return Box( 129 | color: Colors.blue[200], 130 | width: double.infinity, 131 | child: Stack( 132 | children: [ 133 | Scrollbar( 134 | child: SingleChildScrollView( 135 | controller: scrollController, 136 | child: Padding( 137 | padding: const Pad(horizontal: 12, vertical: 6), 138 | child: Column( 139 | mainAxisSize: MainAxisSize.max, 140 | children: List.generate( 141 | lines, 142 | (index) => SizedBox( 143 | width: double.infinity, 144 | child: Text('$lines lines of text'), 145 | ), 146 | ), 147 | ), 148 | ), 149 | ), 150 | ), 151 | Positioned( 152 | top: 0, 153 | right: DetectScroll.of(context).canScroll 154 | ? DetectScroll.of(context).scrollbarWidth 155 | : 0, 156 | child: IconButton( 157 | icon: const Icon(Icons.help_outline), 158 | onPressed: () { 159 | bool canScroll = DetectScroll.of(context).canScroll; 160 | double scrollbarWidth = DetectScroll.of(context).scrollbarWidth; 161 | 162 | showDialog( 163 | context: context, 164 | builder: (BuildContext context) { 165 | return AlertDialog( 166 | content: Text( 167 | 'DetectScroll.of(context).canScroll = $canScroll' 168 | '\n\n' 169 | 'DetectScroll.of(context).scrollbarWidth = $scrollbarWidth' 170 | '\n\n' 171 | 'Note the help button will move ' 172 | 'when the scrollbar is shown and removed.', 173 | ), 174 | ); 175 | }, 176 | ); 177 | }, 178 | ), 179 | ), 180 | ], 181 | ), 182 | ); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /example/lib/main_fit_horizontally.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('FitHorizontally Example')), 14 | body: Padding( 15 | padding: const EdgeInsets.all(8.0), 16 | child: Center( 17 | child: Column( 18 | mainAxisSize: MainAxisSize.min, 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | // 22 | const Box(height: 10), 23 | const Text("Simple text:"), 24 | const Box(height: 10), 25 | // 26 | Container( 27 | alignment: Alignment.centerLeft, 28 | color: Colors.yellow, 29 | width: double.infinity, 30 | height: 30, 31 | child: text(), 32 | ), 33 | Container( 34 | alignment: Alignment.centerLeft, 35 | color: Colors.yellow, 36 | width: 250, 37 | height: 30, 38 | child: text(), 39 | ), 40 | Container( 41 | alignment: Alignment.centerLeft, 42 | color: Colors.yellow, 43 | width: 150, 44 | height: 30, 45 | child: text(), 46 | ), 47 | // 48 | const Box(height: 30), 49 | const Text("Text wrapped with FitHorizontally:"), 50 | const Box(height: 10), 51 | // 52 | Container( 53 | alignment: Alignment.centerLeft, 54 | color: Colors.yellow, 55 | width: double.infinity, 56 | height: 30, 57 | child: FitHorizontally(child: text()), 58 | ), 59 | Container( 60 | alignment: Alignment.centerLeft, 61 | color: Colors.yellow, 62 | width: 250, 63 | height: 30, 64 | child: FitHorizontally(child: text()), 65 | ), 66 | Container( 67 | alignment: Alignment.centerLeft, 68 | color: Colors.yellow, 69 | width: 150, 70 | height: 30, 71 | child: FitHorizontally(child: text()), 72 | ), 73 | const Box(height: 50), 74 | ], 75 | ), 76 | ), 77 | ), 78 | ); 79 | } 80 | 81 | Container separator() => Container(width: 2, height: 50, color: Colors.black26); 82 | 83 | Text text() => const Text( 84 | "So long, farewell, auf Wiedersehen.", 85 | overflow: TextOverflow.fade, 86 | style: TextStyle(fontSize: 20, color: Colors.blue), 87 | maxLines: 1, 88 | softWrap: false, 89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /example/lib/main_fit_horizontally_baseline.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | // 13 | return Scaffold( 14 | appBar: AppBar(title: const Text('FitHorizontally Baseline Example')), 15 | body: Box( 16 | // color: Colors.red[800], 17 | child: Center( 18 | child: Column( 19 | children: [ 20 | const Box(height: 40), 21 | const Text("Row with CrossAxisAlignment.center:"), 22 | const Box(height: 20), 23 | _row(false), 24 | const Box(height: 70), 25 | const Text("Row with CrossAxisAlignment.baseline:"), 26 | const Box(height: 20), 27 | _row(true), 28 | ], 29 | ), 30 | ), 31 | ), 32 | ); 33 | } 34 | 35 | Row _row(bool baseline) { 36 | return Row( 37 | crossAxisAlignment: baseline ? CrossAxisAlignment.baseline : CrossAxisAlignment.center, 38 | textBaseline: TextBaseline.alphabetic, 39 | children: const [ 40 | // 41 | SizedBox(height: 10), 42 | Box.g( 43 | child: TextOneLine("Hello", style: TextStyle(fontSize: 28)), 44 | ), 45 | Box.y( 46 | width: 45, 47 | child: FitHorizontally( 48 | alignment: Alignment.centerLeft, 49 | child: TextOneLine("Hello", style: TextStyle(fontSize: 28)), 50 | ), 51 | ), 52 | Box.g( 53 | child: TextOneLine("Hello", style: TextStyle(fontSize: 60)), 54 | ), 55 | Box.y( 56 | width: 56, 57 | child: FitHorizontally( 58 | alignment: Alignment.centerLeft, 59 | child: TextOneLine("Hello", style: TextStyle(fontSize: 60)), 60 | ), 61 | ), 62 | ], 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/lib/main_global_keys.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp(const MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | const MyApp({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) => const MaterialApp( 13 | home: MyHomePage(), 14 | ); 15 | } 16 | 17 | class MyHomePage extends StatelessWidget { 18 | const MyHomePage({super.key}); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: const Text('Example'), 25 | ), 26 | body: Center( 27 | child: Column( 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | UserWidget(user: User('Bob')), 31 | UserWidget(user: User('Alice')), 32 | UserWidget(user: User('Marcelo')), 33 | const Divider(color: Colors.black), 34 | toggleUser(User('Bob')), 35 | toggleUser(User('Alice')), 36 | toggleUser(User('Marcelo')), 37 | ], 38 | ), 39 | ), 40 | // This trailing comma makes auto-formatting nicer for build methods. 41 | ); 42 | } 43 | 44 | Widget toggleUser(User user) => ElevatedButton( 45 | onPressed: () => UserWidget.toggleSelected(user), 46 | child: Text('Toggle $user'), 47 | ); 48 | } 49 | 50 | /////////////////////////////////////////////////////////////////////////////// 51 | 52 | class UserWidget extends StatefulWidget { 53 | final User user; 54 | 55 | static UserWidgetState? currentState(User user) => 56 | GlobalValueKey(user).currentState; 57 | 58 | static void toggleSelected(User user) => currentState(user)?.toggleSelected(); 59 | 60 | UserWidget({required this.user}) : super(key: GlobalValueKey(user)); 61 | 62 | @override 63 | State createState() => UserWidgetState(); 64 | } 65 | 66 | class UserWidgetState extends State { 67 | bool _selected = false; 68 | 69 | void toggleSelected() { 70 | setState(() { 71 | _selected = !_selected; 72 | }); 73 | } 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return Container( 78 | color: _selected ? Colors.red : Colors.white, 79 | width: 120, 80 | height: 50, 81 | margin: const EdgeInsets.all(8.0), 82 | child: Center( 83 | child: Text( 84 | widget.user.toString(), 85 | style: TextStyle( 86 | color: _selected ? Colors.white : Colors.grey, 87 | fontWeight: FontWeight.bold, 88 | fontSize: 20), 89 | ), 90 | )); 91 | } 92 | } 93 | 94 | /////////////////////////////////////////////////////////////////////////////// 95 | 96 | class User { 97 | final String name; 98 | 99 | User(this.name); 100 | 101 | @override 102 | String toString() => name; 103 | 104 | @override 105 | bool operator ==(Object other) => 106 | identical(this, other) || 107 | other is User && runtimeType == other.runtimeType && name == other.name; 108 | 109 | @override 110 | int get hashCode => name.hashCode; 111 | } 112 | 113 | /////////////////////////////////////////////////////////////////////////////// 114 | -------------------------------------------------------------------------------- /example/lib/main_non_uniform_outline_input_border.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | // 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: const Text( 16 | 'NonUniformOutlineInputBorder Example', 17 | style: TextStyle(fontSize: 18), 18 | ), 19 | ), 20 | body: SizedBox.expand( 21 | child: SingleChildScrollView( 22 | child: Padding( 23 | padding: const Pad(all: 10.0), 24 | child: Column( 25 | crossAxisAlignment: CrossAxisAlignment.start, 26 | children: _children(), 27 | ), 28 | ), 29 | ), 30 | ), 31 | ); 32 | } 33 | 34 | List _children() { 35 | return [ 36 | textfield('show all sides'), 37 | // 38 | textfield('hideRightSide', hideRightSide: true), 39 | textfield('hideBottomSide', hideBottomSide: true), 40 | textfield('hideLeftSide', hideLeftSide: true), 41 | textfield('hideTopSide', hideTopSide: true), 42 | // 43 | textfield('hideTopSide & hideRightSide', hideTopSide: true, hideRightSide: true), 44 | textfield('hideTopSide & hideBottomSide', hideTopSide: true, hideBottomSide: true), 45 | textfield('hideTopSide & hideLeftSide', hideTopSide: true, hideLeftSide: true), 46 | // 47 | textfield('hideRightSide & hideBottomSide', hideRightSide: true, hideBottomSide: true), 48 | textfield('hideRightSide & hideLeftSide', hideRightSide: true, hideLeftSide: true), 49 | // 50 | textfield('hideBottomSide & hideLeftSide', hideBottomSide: true, hideLeftSide: true), 51 | // 52 | textfield('show top only', hideRightSide: true, hideBottomSide: true, hideLeftSide: true), 53 | textfield('show right only', hideTopSide: true, hideBottomSide: true, hideLeftSide: true), 54 | textfield('show bottom only', hideTopSide: true, hideRightSide: true, hideLeftSide: true), 55 | textfield('show left only', hideTopSide: true, hideRightSide: true, hideBottomSide: true), 56 | ]; 57 | } 58 | 59 | Widget textfield( 60 | String label, { 61 | bool hideTopSide = false, 62 | bool hideBottomSide = false, 63 | bool hideRightSide = false, 64 | bool hideLeftSide = false, 65 | }) => 66 | Padding( 67 | padding: const Pad(bottom: 20.0), 68 | child: Box.g( 69 | child: TextField( 70 | style: const TextStyle(fontSize: 16), 71 | controller: TextEditingController(text: label), 72 | decoration: InputDecoration( 73 | contentPadding: const Pad(horizontal: 30, vertical: 40), 74 | fillColor: Colors.yellow, 75 | filled: true, 76 | enabledBorder: border(hideTopSide, hideBottomSide, hideRightSide, hideLeftSide), 77 | ), 78 | ), 79 | ), 80 | ); 81 | 82 | NonUniformOutlineInputBorder border( 83 | bool hideTopSide, 84 | bool hideBottomSide, 85 | bool hideRightSide, 86 | bool hideLeftSide, 87 | ) { 88 | return NonUniformOutlineInputBorder( 89 | hideTopSide: hideTopSide, 90 | hideBottomSide: hideBottomSide, 91 | hideRightSide: hideRightSide, 92 | hideLeftSide: hideLeftSide, 93 | borderSide: const BorderSide(width: 10), 94 | borderRadius: const BorderRadius.only( 95 | topLeft: Radius.circular(38), 96 | topRight: Radius.circular(38), 97 | bottomLeft: Radius.circular(38), 98 | bottomRight: Radius.circular(38), 99 | ), 100 | ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /example/lib/main_non_uniform_rounded_rectangle_border.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: const Text( 15 | 'NonUniformRoundedRectangleBorder Example', 16 | style: TextStyle(fontSize: 15), 17 | ), 18 | ), 19 | body: SizedBox.expand( 20 | child: SingleChildScrollView( 21 | child: Padding( 22 | padding: const Pad(all: 10.0), 23 | child: Column( 24 | crossAxisAlignment: CrossAxisAlignment.start, 25 | children: _children(), 26 | ), 27 | ), 28 | ), 29 | ), 30 | ); 31 | } 32 | 33 | List _children() { 34 | return [ 35 | button('show all sides'), 36 | // 37 | button('hideRightSide', hideRightSide: true), 38 | button('hideBottomSide', hideBottomSide: true), 39 | button('hideLeftSide', hideLeftSide: true), 40 | button('hideTopSide', hideTopSide: true), 41 | // 42 | button('hideTopSide & hideRightSide', hideTopSide: true, hideRightSide: true), 43 | button('hideTopSide & hideBottomSide', hideTopSide: true, hideBottomSide: true), 44 | button('hideTopSide & hideLeftSide', hideTopSide: true, hideLeftSide: true), 45 | // 46 | button('hideRightSide & hideBottomSide', hideRightSide: true, hideBottomSide: true), 47 | button('hideRightSide & hideLeftSide', hideRightSide: true, hideLeftSide: true), 48 | // 49 | button('hideBottomSide & hideLeftSide', hideBottomSide: true, hideLeftSide: true), 50 | // 51 | button('show top only', hideRightSide: true, hideBottomSide: true, hideLeftSide: true), 52 | button('show right only', hideTopSide: true, hideBottomSide: true, hideLeftSide: true), 53 | button('show bottom only', hideTopSide: true, hideRightSide: true, hideLeftSide: true), 54 | button('show left only', hideTopSide: true, hideRightSide: true, hideBottomSide: true), 55 | ]; 56 | } 57 | 58 | Widget button( 59 | String label, { 60 | bool hideTopSide = false, 61 | bool hideBottomSide = false, 62 | bool hideRightSide = false, 63 | bool hideLeftSide = false, 64 | }) => 65 | Padding( 66 | padding: const Pad(bottom: 20.0), 67 | child: Box( 68 | height: 70, 69 | child: ElevatedButton( 70 | style: ElevatedButton.styleFrom( 71 | elevation: 0, 72 | shadowColor: Colors.transparent, 73 | backgroundColor: Colors.lightGreen, 74 | foregroundColor: Colors.white, 75 | textStyle: const TextStyle(fontSize: 18), 76 | shape: shape(hideTopSide, hideBottomSide, hideRightSide, hideLeftSide), 77 | ), 78 | onPressed: () {}, 79 | child: Text(label), 80 | ), 81 | ), 82 | ); 83 | 84 | NonUniformRoundedRectangleBorder shape( 85 | bool hideTopSide, 86 | bool hideBottomSide, 87 | bool hideRightSide, 88 | bool hideLeftSide, 89 | ) { 90 | return NonUniformRoundedRectangleBorder( 91 | side: const BorderSide(color: Colors.black87, width: 15.0), 92 | borderRadius: const BorderRadius.only( 93 | topLeft: Radius.circular(30), 94 | topRight: Radius.circular(30), 95 | bottomLeft: Radius.circular(30), 96 | bottomRight: Radius.circular(30), 97 | ), 98 | hideTopSide: hideTopSide, 99 | hideBottomSide: hideBottomSide, 100 | hideRightSide: hideRightSide, 101 | hideLeftSide: hideLeftSide, 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /example/lib/main_normalized_overflow_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | static const text = Text("If you set your goals ridiculously high and it's a failure, " 10 | "you will fail above everyone else's success."); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(title: const Text('NormalizedOverflowBox Example')), 16 | body: const Center( 17 | child: Box( 18 | width: 300, 19 | child: Column( 20 | children: [ 21 | SizedBox(height: 10), 22 | Box( 23 | color: Colors.green, 24 | height: 105, 25 | width: 110, 26 | child: NormalizedOverflowBox(minWidth: 50, child: text), 27 | ), 28 | Box(height: 10), 29 | Box( 30 | color: Colors.blue, 31 | height: 105, 32 | width: 110, 33 | child: OverflowBox(minWidth: 100, child: text), 34 | ), 35 | Box(height: 10), 36 | Box( 37 | color: Colors.red, 38 | height: 105, 39 | width: 110, 40 | child: NormalizedOverflowBox(minWidth: 130, child: text), 41 | ), 42 | Box(height: 10), 43 | Box( 44 | color: Colors.purple, 45 | height: 105, 46 | width: 110, 47 | child: NormalizedOverflowBox(minWidth: 200, child: text), 48 | ), 49 | ], 50 | ), 51 | ), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example/lib/main_row_spacer.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('RowSpacer Example')), 14 | body: Column( 15 | children: [ 16 | // 17 | const SizedBox(height: 10), 18 | // 19 | Container( 20 | color: Colors.yellow, 21 | child: RowSuper( 22 | children: [ 23 | text1(), 24 | text2(), 25 | ], 26 | ), 27 | ), 28 | // 29 | const SizedBox(height: 10), 30 | // 31 | Container( 32 | color: Colors.yellow, 33 | child: RowSuper( 34 | children: [ 35 | text1(), 36 | text2(), 37 | RowSpacer(), 38 | ], 39 | ), 40 | ), 41 | // 42 | const SizedBox(height: 10), 43 | // 44 | Container( 45 | color: Colors.yellow, 46 | child: RowSuper( 47 | mainAxisSize: MainAxisSize.max, 48 | children: [ 49 | text1(), 50 | text2(), 51 | ], 52 | ), 53 | ), 54 | // 55 | const SizedBox(height: 10), 56 | // 57 | Container( 58 | width: 165.0, 59 | color: Colors.yellow, 60 | child: RowSuper( 61 | children: [ 62 | RowSpacer(), 63 | text1(), 64 | RowSpacer(), 65 | text2(), 66 | RowSpacer(), 67 | ], 68 | ), 69 | ), 70 | // 71 | const SizedBox(height: 10), 72 | // 73 | Container( 74 | width: 165.0, 75 | color: Colors.yellow, 76 | child: RowSuper( 77 | fitHorizontally: true, 78 | children: [ 79 | RowSpacer(), 80 | text1(), 81 | RowSpacer(), 82 | text2(), 83 | RowSpacer(), 84 | ], 85 | ), 86 | ), 87 | // 88 | const SizedBox(height: 10), 89 | Container(width: double.infinity, height: 2.0, color: Colors.black), 90 | const SizedBox(height: 10), 91 | // 92 | // ------------ 93 | // 94 | Container( 95 | color: Colors.yellow, 96 | child: RowSuper( 97 | alignment: Alignment.bottomRight, 98 | innerDistance: 5.0, 99 | children: [ 100 | Container( 101 | color: Colors.orange, 102 | child: RowSuper( 103 | alignment: Alignment.topRight, 104 | children: [ 105 | text1(), 106 | text2(), 107 | ], 108 | ), 109 | ), 110 | RowSpacer(), 111 | box1(), 112 | box2(), 113 | ], 114 | ), 115 | ), 116 | // 117 | ], 118 | ), 119 | ); 120 | } 121 | 122 | Container text1() => Container( 123 | color: Colors.red, 124 | child: const Text("Hello!", 125 | maxLines: 1, 126 | overflow: TextOverflow.fade, 127 | softWrap: false, 128 | style: TextStyle(fontSize: 27.0)), 129 | ); 130 | 131 | Container text2() => Container( 132 | color: Colors.blue, 133 | child: const Text("How are you doing?", 134 | maxLines: 1, 135 | overflow: TextOverflow.fade, 136 | softWrap: false, 137 | style: TextStyle(fontSize: 20.0)), 138 | ); 139 | 140 | Container box1() => Container(width: 30, height: 40, color: Colors.green); 141 | 142 | Container box2() => Container(width: 30, height: 50, color: Colors.purple); 143 | } 144 | -------------------------------------------------------------------------------- /example/lib/main_row_super.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('RowSuper Example')), 14 | body: SizedBox.expand( 15 | child: SingleChildScrollView( 16 | scrollDirection: Axis.horizontal, 17 | child: RowSuper( 18 | innerDistance: 8.0, 19 | outerDistance: 8.0, 20 | children: [ 21 | example1(), 22 | example2(), 23 | example3(), 24 | example4(), 25 | example5(), 26 | example6(), 27 | example7(), 28 | example8(), 29 | example9(), 30 | example10(), 31 | example11(), 32 | example12(), 33 | example13(), 34 | example14(), 35 | example15(), 36 | example16(), 37 | ], 38 | ), 39 | ), 40 | ), 41 | ); 42 | } 43 | 44 | Widget example1() => Container( 45 | color: Colors.yellow, 46 | child: RowSuper( 47 | alignment: Alignment.center, 48 | invert: false, 49 | children: [redBox(), blueBox()], 50 | ), 51 | ); 52 | 53 | Widget example2() => Container( 54 | color: Colors.yellow, 55 | child: RowSuper( 56 | outerDistance: -3, 57 | alignment: Alignment.center, 58 | invert: false, 59 | children: [redBox(), blueBox()], 60 | ), 61 | ); 62 | 63 | Widget example3() => Container( 64 | color: Colors.yellow, 65 | child: RowSuper( 66 | alignment: Alignment.center, 67 | invert: false, 68 | innerDistance: -15, 69 | children: [redBox(), blueBox()], 70 | ), 71 | ); 72 | 73 | Widget example4() => Container( 74 | color: Colors.yellow, 75 | child: RowSuper( 76 | alignment: Alignment.center, 77 | invert: true, 78 | innerDistance: -15, 79 | children: [redBox(), blueBox()], 80 | ), 81 | ); 82 | 83 | Widget example5() => Container( 84 | color: Colors.yellow, 85 | child: RowSuper( 86 | alignment: Alignment.center, 87 | invert: false, 88 | outerDistance: 5, 89 | innerDistance: -15, 90 | children: [null, redBox(), null, blueBox(), null], 91 | ), 92 | ); 93 | 94 | Widget example6() => Container( 95 | color: Colors.yellow, 96 | child: RowSuper( 97 | alignment: Alignment.bottomCenter, 98 | innerDistance: -15, 99 | children: [redBox(), blueBox()], 100 | ), 101 | ); 102 | 103 | Widget example7() => Container( 104 | color: Colors.yellow, 105 | child: RowSuper( 106 | alignment: Alignment.topCenter, 107 | innerDistance: -15, 108 | children: [redBox(), blueBox()], 109 | ), 110 | ); 111 | 112 | Widget example8() => Container( 113 | color: Colors.yellow, 114 | child: RowSuper( 115 | alignment: Alignment.topCenter, 116 | innerDistance: 20, 117 | separator: separator(), 118 | children: [redBox(), blueBox()], 119 | ), 120 | ); 121 | 122 | Widget example9() => Container( 123 | color: Colors.yellow, 124 | child: RowSuper( 125 | alignment: Alignment.center, 126 | innerDistance: 20, 127 | separator: separator(), 128 | children: [redBox(), blueBox()], 129 | ), 130 | ); 131 | 132 | Widget example10() => Container( 133 | color: Colors.yellow, 134 | child: RowSuper( 135 | alignment: Alignment.center, 136 | innerDistance: 0, 137 | separator: separator(), 138 | children: [redBox(), blueBox()], 139 | ), 140 | ); 141 | 142 | Widget example11() => Container( 143 | color: Colors.yellow, 144 | child: RowSuper( 145 | alignment: Alignment.center, 146 | innerDistance: 0, 147 | separator: separator(), 148 | separatorOnTop: false, 149 | children: [redBox(), blueBox()], 150 | ), 151 | ); 152 | 153 | Widget example12() => Container( 154 | color: Colors.yellow, 155 | child: RowSuper( 156 | alignment: Alignment.center, 157 | innerDistance: -45, 158 | separatorOnTop: false, 159 | children: const [ 160 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 161 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 162 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 163 | ], 164 | ), 165 | ); 166 | 167 | Widget example13() => Container( 168 | color: Colors.yellow, 169 | child: RowSuper( 170 | alignment: Alignment.center, 171 | innerDistance: -45, 172 | invert: true, 173 | separatorOnTop: false, 174 | children: const [ 175 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 176 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 177 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 178 | ], 179 | ), 180 | ); 181 | 182 | Widget example14() => Container( 183 | color: Colors.yellow, 184 | child: RowSuper( 185 | alignment: Alignment.center, 186 | innerDistance: 0, 187 | separator: Container( 188 | height: 200, 189 | width: 1, 190 | color: Colors.black, 191 | ), 192 | separatorOnTop: false, 193 | children: const [ 194 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 195 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 196 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 197 | ], 198 | ), 199 | ); 200 | 201 | Widget example15() => Container( 202 | color: Colors.yellow, 203 | child: RowSuper( 204 | alignment: Alignment.center, 205 | innerDistance: 0, 206 | separator: Container( 207 | height: 200, 208 | width: 40, 209 | color: Colors.black, 210 | ), 211 | separatorOnTop: false, 212 | children: const [ 213 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 214 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 215 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 216 | ], 217 | ), 218 | ); 219 | 220 | Widget example16() => Container( 221 | color: Colors.yellow, 222 | child: RowSuper( 223 | alignment: Alignment.center, 224 | innerDistance: 0, 225 | separator: Container( 226 | height: 200, 227 | width: 40, 228 | color: Colors.black, 229 | ), 230 | separatorOnTop: true, 231 | children: const [ 232 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.red)), 233 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.blue)), 234 | Text("Text", style: TextStyle(fontSize: 50, color: Colors.green)), 235 | ], 236 | ), 237 | ); 238 | 239 | Widget separator() => Container( 240 | width: 14, 241 | height: 70, 242 | color: Colors.black.withOpacity(0.5), 243 | ); 244 | 245 | Widget redBox() => Container( 246 | width: 50, 247 | height: 50, 248 | color: Colors.red, 249 | ); 250 | 251 | Widget blueBox() => Container( 252 | width: 30, 253 | height: 70, 254 | color: Colors.blue.withOpacity(0.80), 255 | ); 256 | } 257 | -------------------------------------------------------------------------------- /example/lib/main_row_super_alignment.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({super.key}); 9 | 10 | // 11 | static const List boxes = [ 12 | Box.r(width: 50, height: 20), 13 | Box.g(width: 50, height: 35), 14 | Box.b(width: 50, height: 50), 15 | ]; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | // 20 | return Scaffold( 21 | appBar: AppBar(title: const Text('RowSuper Alignment')), 22 | body: SizedBox.expand( 23 | child: Column( 24 | children: [ 25 | // 26 | const Text("topLeft"), 27 | Box( 28 | color: Colors.black, 29 | width: double.infinity, 30 | child: RowSuper( 31 | alignment: Alignment.topLeft, 32 | innerDistance: 6.0, 33 | outerDistance: 20.0, 34 | children: boxes, 35 | ), 36 | ), 37 | // 38 | const Box(height: 4.0), 39 | // 40 | const Text("topCenter"), 41 | Box( 42 | color: Colors.black, 43 | width: double.infinity, 44 | child: RowSuper( 45 | alignment: Alignment.topCenter, 46 | innerDistance: 6.0, 47 | outerDistance: 20.0, 48 | children: boxes, 49 | ), 50 | ), 51 | // 52 | const Box(height: 4.0), 53 | // 54 | const Text("topRight"), 55 | Box( 56 | color: Colors.black, 57 | width: double.infinity, 58 | child: RowSuper( 59 | alignment: Alignment.topRight, 60 | innerDistance: 6.0, 61 | outerDistance: 20.0, 62 | children: boxes, 63 | ), 64 | ), 65 | // 66 | const Box(height: 15.0), 67 | // 68 | const Text("centerLeft"), 69 | Box( 70 | color: Colors.black, 71 | width: double.infinity, 72 | child: RowSuper( 73 | alignment: Alignment.centerLeft, 74 | outerDistance: 20.0, 75 | children: boxes, 76 | ), 77 | ), 78 | // 79 | const Box(height: 4.0), 80 | // 81 | const Text("center"), 82 | Box( 83 | color: Colors.black, 84 | width: double.infinity, 85 | child: RowSuper( 86 | alignment: Alignment.center, 87 | outerDistance: 20.0, 88 | children: boxes, 89 | ), 90 | ), 91 | // 92 | const Box(height: 4.0), 93 | // 94 | const Text("centerRight"), 95 | Box( 96 | color: Colors.black, 97 | width: double.infinity, 98 | child: RowSuper( 99 | alignment: Alignment.centerRight, 100 | outerDistance: 20.0, 101 | children: boxes, 102 | ), 103 | ), 104 | // 105 | const Box(height: 15.0), 106 | // 107 | const Text("bottomLeft"), 108 | Box( 109 | color: Colors.black, 110 | width: double.infinity, 111 | child: RowSuper( 112 | alignment: Alignment.bottomLeft, 113 | children: boxes, 114 | ), 115 | ), 116 | // 117 | const Box(height: 4.0), 118 | // 119 | const Text("bottomCenter"), 120 | Box( 121 | color: Colors.black, 122 | width: double.infinity, 123 | child: RowSuper( 124 | alignment: Alignment.bottomCenter, 125 | children: boxes, 126 | ), 127 | ), 128 | // 129 | const Box(height: 4.0), 130 | // 131 | const Text("bottomRight"), 132 | Box( 133 | color: Colors.black, 134 | width: double.infinity, 135 | child: RowSuper( 136 | alignment: Alignment.bottomRight, 137 | children: boxes, 138 | ), 139 | ), 140 | ], 141 | ), 142 | ), 143 | ); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /example/lib/main_row_super_fill.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('RowSuper Fill Example')), 14 | body: Center( 15 | child: Column( 16 | children: [ 17 | // 18 | const SizedBox(height: 20.0), 19 | const Text("fill: false"), 20 | const SizedBox(height: 10.0), 21 | Container( 22 | color: Colors.yellow, 23 | child: RowSuper( 24 | mainAxisSize: MainAxisSize.max, 25 | children: [ 26 | Container( 27 | alignment: Alignment.center, 28 | color: Colors.red, 29 | child: const Text("MainAxisSize.max"), 30 | ), 31 | Container( 32 | alignment: Alignment.center, 33 | color: Colors.blue.withOpacity(0.80), 34 | child: const Text("MainAxisSize.max"), 35 | ) 36 | ], 37 | ), 38 | ), 39 | const SizedBox(height: 10.0), 40 | Container( 41 | color: Colors.yellow, 42 | child: RowSuper( 43 | mainAxisSize: MainAxisSize.min, 44 | children: [ 45 | Container( 46 | alignment: Alignment.center, 47 | color: Colors.red, 48 | child: const Text("MainAxisSize.min"), 49 | ), 50 | Container( 51 | alignment: Alignment.center, 52 | color: Colors.blue.withOpacity(0.80), 53 | child: const Text("MainAxisSize.min"), 54 | ) 55 | ], 56 | ), 57 | ), 58 | const SizedBox(height: 10.0), 59 | Container( 60 | color: Colors.yellow, 61 | child: RowSuper( 62 | children: [ 63 | Container( 64 | alignment: Alignment.center, 65 | color: Colors.red, 66 | child: const Text("Hello"), 67 | ), 68 | Container( 69 | alignment: Alignment.center, 70 | color: Colors.blue.withOpacity(0.80), 71 | child: const Text("This is some larger text"), 72 | ) 73 | ], 74 | ), 75 | ), 76 | const SizedBox(height: 10.0), 77 | Container( 78 | color: Colors.yellow, 79 | child: RowSuper( 80 | children: [ 81 | Container( 82 | alignment: Alignment.center, 83 | color: Colors.red, 84 | child: const Text("Hello"), 85 | ), 86 | Container( 87 | alignment: Alignment.center, 88 | color: Colors.blue.withOpacity(0.80), 89 | child: const Text("This is some really very, " 90 | "extremely large text " 91 | "that won't fit a single line at all"), 92 | ) 93 | ], 94 | ), 95 | ), 96 | // 97 | // ------------------- 98 | // 99 | const SizedBox(height: 40.0), 100 | Container(width: double.infinity, height: 1.0, color: Colors.black), 101 | const SizedBox(height: 40.0), 102 | const Text("fill: true"), 103 | const SizedBox(height: 10.0), 104 | Container( 105 | color: Colors.yellow, 106 | child: RowSuper( 107 | fill: true, 108 | mainAxisSize: MainAxisSize.max, 109 | children: [ 110 | Container( 111 | alignment: Alignment.center, 112 | color: Colors.red, 113 | child: const Text("MainAxisSize.max"), 114 | ), 115 | Container( 116 | alignment: Alignment.center, 117 | color: Colors.blue.withOpacity(0.80), 118 | child: const Text("MainAxisSize.max"), 119 | ) 120 | ], 121 | ), 122 | ), 123 | const SizedBox(height: 10.0), 124 | Container( 125 | color: Colors.yellow, 126 | child: RowSuper( 127 | fill: true, 128 | mainAxisSize: MainAxisSize.min, 129 | children: [ 130 | Container( 131 | alignment: Alignment.center, 132 | color: Colors.red, 133 | child: const Text("MainAxisSize.min"), 134 | ), 135 | Container( 136 | alignment: Alignment.center, 137 | color: Colors.blue.withOpacity(0.80), 138 | child: const Text("MainAxisSize.min"), 139 | ) 140 | ], 141 | ), 142 | ), 143 | const SizedBox(height: 10.0), 144 | Container( 145 | color: Colors.yellow, 146 | child: RowSuper( 147 | fill: true, 148 | children: [ 149 | Container( 150 | alignment: Alignment.center, 151 | color: Colors.red, 152 | child: const Text("Hello"), 153 | ), 154 | Container( 155 | alignment: Alignment.center, 156 | color: Colors.blue.withOpacity(0.80), 157 | child: const Text("This is some larger text"), 158 | ), 159 | ], 160 | ), 161 | ), 162 | const SizedBox(height: 10.0), 163 | Container( 164 | color: Colors.yellow, 165 | child: RowSuper( 166 | fill: true, 167 | children: [ 168 | Container( 169 | alignment: Alignment.center, 170 | color: Colors.red, 171 | child: const Text("Hello"), 172 | ), 173 | Container( 174 | alignment: Alignment.center, 175 | color: Colors.blue.withOpacity(0.80), 176 | child: const Text("This is some really very, " 177 | "extremely large text " 178 | "that won't fit a single line at all"), 179 | ) 180 | ], 181 | ), 182 | ), 183 | ], 184 | ), 185 | ), 186 | ); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /example/lib/main_row_super_playground.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatefulWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | State createState() => _DemoState(); 11 | } 12 | 13 | class _DemoState extends State { 14 | late int itemCount; 15 | late double height; 16 | late double width; 17 | late double outer; 18 | late double inner; 19 | late bool withSeparator; 20 | late Alignment alignment; 21 | late double separatorWidth; 22 | late double? parentHeight; 23 | late bool intrinsic; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | itemCount = 5; 29 | height = width = 10.0; 30 | inner = 8.0; 31 | outer = 16.0; 32 | withSeparator = true; 33 | alignment = Alignment.center; 34 | separatorWidth = 1.0; 35 | parentHeight = null; 36 | intrinsic = false; 37 | } 38 | 39 | void _reset() { 40 | itemCount = 0; 41 | height = width = 10.0; 42 | inner = 0.0; 43 | outer = 0.0; 44 | withSeparator = true; 45 | alignment = Alignment.center; 46 | separatorWidth = 1.0; 47 | parentHeight = null; 48 | intrinsic = false; 49 | } 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | print('---'); 54 | print('count = $itemCount'); 55 | print('width = $height'); 56 | print('height = $width'); 57 | print('inner = $inner'); 58 | print('outer = $outer'); 59 | print('withSeparator = $withSeparator'); 60 | print('separatorHeight = $separatorWidth'); 61 | print('parentHeight = $parentHeight'); 62 | 63 | return Scaffold( 64 | appBar: AppBar(title: const Text('RowSuper Playground')), 65 | body: Column( 66 | children: [ 67 | Expanded( 68 | child: Center( 69 | child: SingleChildScrollView( 70 | scrollDirection: Axis.horizontal, 71 | child: Row( 72 | children: [ 73 | blueBox(), 74 | if (intrinsic) 75 | IntrinsicWidth( 76 | child: IntrinsicHeight(child: _content()), 77 | ) 78 | else 79 | _content(), 80 | blueBox(), 81 | ], 82 | ), 83 | ), 84 | ), 85 | ), 86 | // 87 | Container( 88 | width: double.infinity, 89 | color: Colors.grey, 90 | padding: const EdgeInsets.symmetric(vertical: 6.0), 91 | child: Column( 92 | children: [ 93 | Row( 94 | mainAxisSize: MainAxisSize.min, 95 | children: [ 96 | button("Add Item", () => itemCount++, color: Colors.green), 97 | button("Reset", _reset, color: Colors.red), 98 | ], 99 | ), 100 | Row( 101 | mainAxisSize: MainAxisSize.min, 102 | children: [ 103 | button("- Width", () => width -= (width > 0.0) ? 1.0 : 0.0), 104 | button("+ Width", () => width += 1.0), 105 | const Box(width: 10.0), 106 | button("- Height", () => height -= (height > 0.0) ? 1.0 : 0.0), 107 | button("+ Height", () => height += 1.0), 108 | ], 109 | ), 110 | Row( 111 | mainAxisSize: MainAxisSize.min, 112 | children: [ 113 | button("- Inner", () => inner -= 1.0), 114 | button("+ Inner", () => inner += 1.0), 115 | Text(" $inner"), 116 | ], 117 | ), 118 | Row( 119 | mainAxisSize: MainAxisSize.min, 120 | children: [ 121 | button("- Outer", () => outer -= 1.0), 122 | button("+ Outer", () => outer += 1.0), 123 | Text(" $outer"), 124 | ], 125 | ), 126 | Row( 127 | mainAxisSize: MainAxisSize.min, 128 | children: [ 129 | button("Separator ${withSeparator ? 'On' : 'Off'}", 130 | () => withSeparator = !withSeparator), 131 | button( 132 | "- Sep", 133 | withSeparator 134 | ? () => separatorWidth -= (separatorWidth > 0.0) ? 1.0 : 0.0 135 | : null), 136 | button("+ Sep", withSeparator ? () => separatorWidth += 1.0 : null), 137 | Text(" $separatorWidth"), 138 | ], 139 | ), 140 | Row( 141 | mainAxisSize: MainAxisSize.min, 142 | children: [ 143 | button("Parent Height = $parentHeight", () { 144 | if (parentHeight == null) { 145 | parentHeight = 70.0; 146 | } else if (parentHeight == 70.0) { 147 | parentHeight = double.infinity; 148 | } else if (parentHeight == double.infinity) { 149 | parentHeight = null; 150 | } 151 | }), 152 | const Box(width: 10.0), 153 | button("Alignment = $alignment", () { 154 | if (alignment == Alignment.center) { 155 | alignment = Alignment.topLeft; 156 | } else if (alignment == Alignment.topLeft) { 157 | alignment = Alignment.bottomLeft; 158 | } else if (alignment == Alignment.bottomLeft) { 159 | alignment = Alignment.center; 160 | } 161 | }) 162 | ], 163 | ), 164 | button("Intrinsic Width/Height = $intrinsic", () => intrinsic = !intrinsic), 165 | ], 166 | ), 167 | ), 168 | ], 169 | ), 170 | ); 171 | } 172 | 173 | Container _content() { 174 | return Container( 175 | color: Colors.yellow, 176 | height: parentHeight, 177 | child: RowSuper( 178 | alignment: alignment, 179 | separator: withSeparator ? separator() : null, 180 | innerDistance: inner, 181 | outerDistance: outer, 182 | children: [ 183 | for (int i = 0; i < itemCount; i++) coloredBox(i), 184 | ], 185 | ), 186 | ); 187 | } 188 | 189 | Widget button(String label, VoidCallback? func, {Color color = Colors.blue}) => Padding( 190 | padding: const EdgeInsets.symmetric(vertical: 4.0), 191 | child: MaterialButton( 192 | visualDensity: const VisualDensity(vertical: -1.0, horizontal: -3.0), 193 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 194 | color: color, 195 | onPressed: (func == null) ? null : () => setState(func), 196 | child: Text(label), 197 | ), 198 | ); 199 | 200 | Widget separator() => Container( 201 | height: 100, 202 | width: separatorWidth, 203 | color: Colors.black.withOpacity(0.5), 204 | ); 205 | 206 | Widget coloredBox(int index) => Container( 207 | decoration: BoxDecoration( 208 | color: Colors.red.withOpacity(0.5), 209 | border: Border.all(width: 0.5, color: Colors.black), 210 | ), 211 | height: height + index * 10.0, 212 | width: width, 213 | ); 214 | 215 | Widget blueBox() => Container( 216 | height: 120, 217 | width: 15, 218 | color: Colors.blue.withOpacity(0.80), 219 | ); 220 | } 221 | -------------------------------------------------------------------------------- /example/lib/main_row_super_with_fit_horizontally.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('RowSuper with FitHorizontally Example')), 14 | body: Center( 15 | child: SingleChildScrollView( 16 | child: Column( 17 | mainAxisSize: MainAxisSize.min, 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | // 21 | const SizedBox(height: 10), 22 | // 23 | for (double width = 360; width >= 0.0; width -= 100) 24 | Column(children: [ 25 | const SizedBox(height: 8), 26 | // 27 | // fitHorizontally: false 28 | Container( 29 | alignment: Alignment.centerLeft, 30 | width: width, 31 | height: 55, 32 | color: Colors.yellow[600], 33 | child: RowSuper( 34 | separator: separator(), 35 | outerDistance: 6.0, 36 | innerDistance: 12.0, 37 | fitHorizontally: false, 38 | children: [ 39 | text1(), 40 | text2(), 41 | text3(), 42 | ], 43 | ), 44 | ), 45 | // 46 | // fitHorizontally: true 47 | // (shrinkLimit is the default: 67%) 48 | Container( 49 | alignment: Alignment.centerLeft, 50 | width: width, 51 | height: 55, 52 | color: Colors.yellow[500], 53 | child: RowSuper( 54 | separator: separator(), 55 | outerDistance: 6.0, 56 | innerDistance: 12.0, 57 | fitHorizontally: true, 58 | children: [ 59 | text1(), 60 | text2(), 61 | text3(), 62 | ], 63 | ), 64 | ), 65 | // fitHorizontally: true 66 | // shrinkLimit: 0.0 67 | Container( 68 | alignment: Alignment.centerLeft, 69 | width: width, 70 | height: 55, 71 | color: Colors.yellow[300], 72 | child: RowSuper( 73 | separator: separator(), 74 | outerDistance: 6.0, 75 | innerDistance: 12.0, 76 | fitHorizontally: true, 77 | shrinkLimit: 0.0, 78 | children: [ 79 | text1(), 80 | text2(), 81 | text3(), 82 | ], 83 | ), 84 | ), 85 | ]), 86 | // 87 | ], 88 | ), 89 | ), 90 | ), 91 | ); 92 | } 93 | 94 | Container separator() => Container(width: 2, height: 50, color: Colors.black26); 95 | 96 | Text text1() => const Text( 97 | "So long", 98 | overflow: TextOverflow.fade, 99 | style: TextStyle(fontSize: 20, color: Colors.blue), 100 | maxLines: 1, 101 | softWrap: false, 102 | ); 103 | 104 | Text text2() => const Text( 105 | "farewell", 106 | overflow: TextOverflow.fade, 107 | style: TextStyle(fontSize: 20, color: Colors.red), 108 | maxLines: 1, 109 | softWrap: false, 110 | ); 111 | 112 | Text text3() => const Text( 113 | "auf Wiedersehen", 114 | overflow: TextOverflow.fade, 115 | style: TextStyle(fontSize: 20, color: Colors.red), 116 | maxLines: 1, 117 | softWrap: false, 118 | ); 119 | } 120 | -------------------------------------------------------------------------------- /example/lib/main_row_with_row_super_comparison.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | // 13 | return Scaffold( 14 | appBar: AppBar(title: const Text('Row × RowSuper Comparison')), 15 | body: Box( 16 | width: double.infinity, 17 | child: SingleChildScrollView( 18 | child: Column( 19 | crossAxisAlignment: CrossAxisAlignment.stretch, 20 | children: [ 21 | // 22 | // ------------------ 23 | // 24 | explanation("Row where cells are SMALLER that the available width:"), 25 | Row(children: [ 26 | text("How"), 27 | text("are you all,"), 28 | text("my dearest friends?"), 29 | ]), 30 | // 31 | // 32 | explanation( 33 | "RowSuper with `fill:false` (the default) where cells are SMALLER that the available width. " 34 | "Similar to a Row:"), 35 | RowSuper(fill: false, children: [ 36 | text("How"), 37 | text("are you all,"), 38 | text("my dearest friends?"), 39 | ]), 40 | // 41 | // ------------------ 42 | // 43 | divider(), 44 | // 45 | explanation("Row where cells are SMALLER that the available width, but use Expanded. " 46 | "It fills the whole space, but cells have the same size:"), 47 | Row(children: [ 48 | Expanded(child: text("How")), 49 | Expanded(child: text("are you,")), 50 | Expanded(child: text("my dear friend?")), 51 | ]), 52 | // 53 | // 54 | explanation( 55 | "RowSuper with `fill:true` where cells are SMALLER that the available width. " 56 | "It fills the whole space, and cells are proportional to their content width:"), 57 | RowSuper(fill: true, children: [ 58 | text("How"), 59 | text("are you all,"), 60 | text("my dearest friends?"), 61 | ]), 62 | // 63 | // ------------------ 64 | // 65 | divider(), 66 | // 67 | explanation("Row where cells are LARGER that the available width. " 68 | "It will overflow (and show the overflow warning):"), 69 | Row(children: [ 70 | text("this is a very long text"), 71 | text("that surely won't fit the available space in a regular cell phone's screen."), 72 | ]), 73 | // 74 | explanation("RowSuper where cells are LARGER that the available width " 75 | "(it doesn't matter if `fill:false` or `true`). " 76 | "It fills the whole space, and cells are proportional to their content width:"), 77 | RowSuper(fill: false, children: [ 78 | text("this is a long text"), 79 | text("that surely won't fit the available space in a regular cell phone's screen."), 80 | ]), 81 | // 82 | // ------------------ 83 | // 84 | divider(), 85 | ], 86 | ), 87 | ), 88 | ), 89 | ); 90 | } 91 | 92 | Column divider() => Column( 93 | children: [ 94 | const SizedBox(height: 40), 95 | Container(color: Colors.black, height: 1, width: double.infinity), 96 | const SizedBox(height: 10), 97 | ], 98 | ); 99 | 100 | Widget explanation(String text) => Padding( 101 | padding: const EdgeInsets.only(top: 30, left: 8.0, right: 15.0, bottom: 10), 102 | child: Text(text), 103 | ); 104 | 105 | List texts() => [ 106 | text("How"), 107 | text("are you all,"), 108 | text("my dearest friends?"), 109 | ]; 110 | 111 | Widget text(String text) => Box.rand( 112 | padding: const Pad(top: 4.0, bottom: 4.0), 113 | child: Text( 114 | text, 115 | maxLines: 1, 116 | overflow: TextOverflow.ellipsis, 117 | style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), 118 | ), 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /example/lib/main_show_dialog_super.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Material( 13 | child: MaterialApp( 14 | home: Scaffold( 15 | appBar: AppBar(title: const Text('showDialogSuper Example')), 16 | body: const DemoApp(), 17 | ), 18 | ), 19 | ); 20 | } 21 | } 22 | 23 | class DemoApp extends StatefulWidget { 24 | const DemoApp({super.key}); 25 | 26 | @override 27 | State createState() => _DemoAppState(); 28 | } 29 | 30 | class _DemoAppState extends State { 31 | int count = 1; 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Center( 36 | child: Column( 37 | mainAxisAlignment: MainAxisAlignment.center, 38 | children: [ 39 | Expanded(child: Center(child: Text("The dialog has opened $count times."))), 40 | Expanded( 41 | child: Center( 42 | child: ElevatedButton( 43 | onPressed: () { 44 | showDialogSuper( 45 | context: context, 46 | builder: (context) { 47 | return AlertDialog( 48 | content: Text("This dialog has opened $count times." 49 | "\n\n" 50 | "The counter is incremented in the `onDismissed` callback."), 51 | actions: [ 52 | ElevatedButton( 53 | onPressed: () { 54 | Navigator.pop(context, 1); 55 | }, 56 | child: const Text("OK"), 57 | ), 58 | ElevatedButton( 59 | onPressed: () { 60 | Navigator.pop(context, 2); 61 | }, 62 | child: const Text("CANCEL"), 63 | ) 64 | ], 65 | ); 66 | }, 67 | onDismissed: (int? result) { 68 | if (result == 1) { 69 | print("Pressed the OK button."); 70 | } else if (result == 2) { 71 | print("Pressed the CANCEL button."); 72 | } else if (result == null) { 73 | print("Dismissed with BACK or tapping the barrier."); 74 | } else { 75 | throw AssertionError(); 76 | } 77 | setState(() { 78 | count++; 79 | }); 80 | }); 81 | }, 82 | child: const Text("Open Dialog"), 83 | ), 84 | ), 85 | ), 86 | const Expanded(child: Box()), 87 | ], 88 | ), 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /example/lib/main_text_one_line.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | // 12 | return Scaffold( 13 | appBar: AppBar(title: const Text('TextOneLine Example')), 14 | key: UniqueKey(), // Forces restart on hot reload. 15 | body: const SingleChildScrollView( 16 | child: Column( 17 | crossAxisAlignment: CrossAxisAlignment.start, 18 | children: [ 19 | // 20 | // ------------------- 21 | // 22 | SizedBox(height: 10), 23 | Text("Text with ELLIPSIS, maxLines: 1, softWrap: false", 24 | maxLines: 1, 25 | softWrap: false, 26 | overflow: TextOverflow.ellipsis, 27 | style: TextStyle(fontWeight: FontWeight.bold)), 28 | SizedBox(height: 5), 29 | Text("short: Lorem ipsum", 30 | maxLines: 1, softWrap: false, overflow: TextOverflow.ellipsis), 31 | SizedBox(height: 5), 32 | Text( 33 | "long: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 34 | maxLines: 1, 35 | softWrap: false, 36 | overflow: TextOverflow.ellipsis), 37 | SizedBox(height: 5), 38 | Text( 39 | "long without spaces: This is a verylongtextwithoutanyspacesthatdemonstratestheproblemwegetwhentryingtousethenativetextwidget.", 40 | maxLines: 1, 41 | softWrap: false, 42 | overflow: TextOverflow.ellipsis), 43 | SizedBox(height: 40), 44 | // 45 | // ------------------- 46 | // 47 | TextOneLine("TextOneLine with ELLIPSIS", style: TextStyle(fontWeight: FontWeight.bold)), 48 | SizedBox(height: 5), 49 | TextOneLine("short: Lorem ipsum"), 50 | SizedBox(height: 5), 51 | TextOneLine( 52 | "long: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."), 53 | SizedBox(height: 5), 54 | TextOneLine( 55 | "long without spaces: This is a verylongtextwithoutanyspacesthatdemonstratestheproblemwegetwhentryingtousethenativetextwidget.", 56 | overflow: TextOverflow.ellipsis), 57 | SizedBox(height: 40), 58 | // 59 | // ------------------- 60 | // 61 | TextOneLine("TextOneLine with FADE", 62 | overflow: TextOverflow.fade, style: TextStyle(fontWeight: FontWeight.bold)), 63 | SizedBox(height: 5), 64 | TextOneLine("short: Lorem ipsum", overflow: TextOverflow.fade), 65 | SizedBox(height: 5), 66 | TextOneLine( 67 | "long: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 68 | overflow: TextOverflow.fade, 69 | ), 70 | SizedBox(height: 5), 71 | TextOneLine( 72 | "long without spaces: This is a verylongtextwithoutanyspacesthatdemonstratestheproblemwegetwhentryingtousethenativetextwidget.", 73 | overflow: TextOverflow.fade), 74 | SizedBox(height: 40), 75 | // 76 | // ------------------- 77 | // 78 | TextOneLine("TextOneLine with CLIP", 79 | overflow: TextOverflow.clip, style: TextStyle(fontWeight: FontWeight.bold)), 80 | SizedBox(height: 5), 81 | TextOneLine("short: Lorem ipsum", overflow: TextOverflow.clip), 82 | SizedBox(height: 5), 83 | TextOneLine( 84 | "long: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 85 | overflow: TextOverflow.clip, 86 | ), 87 | SizedBox(height: 5), 88 | TextOneLine( 89 | "long without spaces: This is a verylongtextwithoutanyspacesthatdemonstratestheproblemwegetwhentryingtousethenativetextwidget.", 90 | overflow: TextOverflow.clip), 91 | // 92 | // ------------------- 93 | // 94 | SizedBox(height: 20), 95 | Divider(), 96 | SizedBox(height: 20), 97 | // 98 | Text("With letter-spacing: 0 - Text", 99 | maxLines: 1, 100 | softWrap: false, 101 | overflow: TextOverflow.clip, 102 | style: TextStyle(letterSpacing: 0)), 103 | TextOneLine("With letter-spacing: 0 - TextOneLine", 104 | overflow: TextOverflow.clip, style: TextStyle(letterSpacing: 0)), 105 | SizedBox(height: 10), 106 | // 107 | Text("With letter-spacing: 1.1 - Text", 108 | maxLines: 1, 109 | softWrap: false, 110 | overflow: TextOverflow.clip, 111 | style: TextStyle(letterSpacing: 1.1)), 112 | TextOneLine("With letter-spacing: 1.1 - TextOneLine", 113 | overflow: TextOverflow.clip, style: TextStyle(letterSpacing: 1.1)), 114 | SizedBox(height: 10), 115 | Text("With letter-spacing: 2 - Text", 116 | maxLines: 1, 117 | softWrap: false, 118 | overflow: TextOverflow.clip, 119 | style: TextStyle(letterSpacing: 2)), 120 | TextOneLine("With letter-spacing: 2 - TextOneLine", 121 | overflow: TextOverflow.clip, style: TextStyle(letterSpacing: 2)), 122 | ], 123 | ), 124 | ), 125 | ); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /example/lib/main_wrap_super.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(const MaterialApp(home: Demo())); 6 | 7 | class Demo extends StatelessWidget { 8 | const Demo({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) => Scaffold( 12 | appBar: AppBar(title: const Text('WrapSuper Example')), 13 | body: Container( 14 | color: Colors.grey[800], 15 | alignment: Alignment.center, 16 | child: Container( 17 | width: 200, 18 | color: Colors.grey[300], 19 | child: WrapSuper( 20 | alignment: WrapSuperAlignment.center, 21 | wrapType: WrapType.balanced, 22 | spacing: 5.0, 23 | lineSpacing: 2.0, 24 | children: [ 25 | const Box(color: Colors.black, width: 200, height: 2), 26 | const Box.r(width: 100 - 5.0, height: 20), 27 | const Box.g(width: 100, height: 20), 28 | const Box(color: Colors.black, width: 200, height: 2), 29 | const Box.r(width: 60, height: 20), 30 | const Box.g(width: 60, height: 20), 31 | const Box.b(width: 60, height: 20), 32 | const Box.y(width: 60, height: 20), 33 | const Box(color: Colors.black, width: 200, height: 2), 34 | const Box.r(width: 50, height: 30), 35 | const Box.g(width: 140, height: 50), 36 | const Box.b(width: 180, height: 70), 37 | const Box.y(width: 40, height: 25), 38 | const Box.r(width: 50, height: 25), 39 | const Box.g(width: 60, height: 25), 40 | const Box.b(width: 80, height: 25), 41 | const Box.y(width: 120, height: 30), 42 | const Box.r(width: 5, height: 40), 43 | const Box(color: Colors.black, width: 200, height: 2), 44 | ...List.filled(200 ~/ (4 + 5), const Box.g(width: 4, height: 5)), 45 | ], 46 | ), 47 | ), 48 | ), 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /example/lib/main_wrap_super_fit.dart: -------------------------------------------------------------------------------- 1 | import 'package:assorted_layout_widgets/assorted_layout_widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MaterialApp(home: Demo())); 5 | 6 | class Demo extends StatelessWidget { 7 | const Demo({super.key}); 8 | 9 | // 10 | static const divider = 11 | Box(color: Colors.black, width: double.infinity, height: 2.0); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar(title: const Text('WrapSuper WrapFit Example')), 17 | body: Container( 18 | color: const Color(0xFFEEEEEE), 19 | alignment: Alignment.center, 20 | child: SingleChildScrollView( 21 | child: ColumnSuper( 22 | innerDistance: 25.0, 23 | children: [ 24 | // 25 | divider, 26 | // 27 | _title('A bar of 400 pixels.'), 28 | _wrap(WrapFit.min, [box(400, 300)]), 29 | _wrap(WrapFit.divided, [box(400, 300)]), 30 | _wrap(WrapFit.proportional, [box(400, 300)]), 31 | _wrap(WrapFit.larger, [box(400, 300)]), 32 | // 33 | divider, 34 | // 35 | _title('A bar of 230 pixels.'), 36 | _wrap(WrapFit.min, [box(230, 230)]), 37 | _wrap(WrapFit.divided, [box(230, 300)]), 38 | _wrap(WrapFit.proportional, [box(230, 300)]), 39 | _wrap(WrapFit.larger, [box(230, 300)]), 40 | // 41 | divider, 42 | // 43 | _title('A bar of 140 pixels and another of 220.'), 44 | _wrap(WrapFit.min, [box(140, 140), box(220, 220)]), 45 | _wrap(WrapFit.divided, [box(140, 300), box(220, 300)]), 46 | _wrap(WrapFit.proportional, [box(140, 300), box(220, 300)]), 47 | _wrap(WrapFit.larger, [box(140, 300), box(220, 300)]), 48 | // 49 | divider, 50 | // 51 | _title('Four bars: 200, 120, 60 and 80 pixels.'), 52 | _wrap(WrapFit.min, 53 | [box(200, 200), box(120, 120), box(60, 60), box(80, 80)]), 54 | _wrap(WrapFit.divided, 55 | [box(200, 300), box(120, 100), box(60, 100), box(80, 100)]), 56 | _wrap(WrapFit.proportional, [ 57 | box(200, 300), 58 | box(120, (120 / (120 + 60 + 80) * 300).toInt()), 59 | box(60, (60 / (120 + 60 + 80) * 300).toInt()), 60 | box(80, (80 / (120 + 60 + 80) * 300).toInt()) 61 | ]), 62 | _wrap( 63 | WrapFit.larger, 64 | [box(200, 300), box(120, 120), box(60, 90), box(80, 90)], 65 | ), 66 | // 67 | divider, 68 | // 69 | ], 70 | ), 71 | ), 72 | ), 73 | ); 74 | } 75 | 76 | Widget _title(String text) => Text( 77 | '$text\nAvailable width is 300:', 78 | textAlign: TextAlign.center, 79 | ); 80 | 81 | Widget _wrap(WrapFit wrapFit, List children) { 82 | return Column( 83 | children: [ 84 | Text(wrapFit.toString()), 85 | const Box(height: 8.0), 86 | Box( 87 | color: Colors.purple, 88 | padding: const Pad(all: 3.0), 89 | child: Box( 90 | width: 300, 91 | color: Colors.purple, 92 | child: WrapSuper( 93 | wrapFit: wrapFit, 94 | spacing: 3.0, 95 | lineSpacing: 9.0, 96 | children: children, 97 | ), 98 | ), 99 | ), 100 | ], 101 | ); 102 | } 103 | 104 | Widget box(double width, int newWidth) => Box( 105 | color: Colors.lightGreen, 106 | width: width, 107 | height: 30, 108 | child: Center(child: Text("${width.toInt()} ➜ $newWidth")), 109 | ); 110 | } 111 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: Examples for assorted_layout_widgets 3 | publish_to: "none" 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: '>=3.2.0 <4.0.0' 8 | 9 | dependencies: 10 | assorted_layout_widgets: 11 | path: ../ 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | flutter_lints: ^3.0.1 19 | 20 | flutter: 21 | uses-material-design: true 22 | -------------------------------------------------------------------------------- /lib/assorted_layout_widgets.dart: -------------------------------------------------------------------------------- 1 | export "src/box.dart"; 2 | export "src/box_animating_width.dart"; 3 | export "src/button.dart"; 4 | export "src/button_bar_super.dart"; 5 | export "src/capture_gestures.dart"; 6 | export "src/circle_button.dart"; 7 | export "src/column_super.dart"; 8 | export "src/delayed.dart"; 9 | export "src/detect_scroll.dart"; 10 | export "src/fit_horizontally.dart"; 11 | export "src/global_keys.dart"; 12 | export "src/keyboard_dismiss.dart"; 13 | export "src/mask_function_text_input_formatter.dart"; 14 | export "src/non_uniform_outline_input_border.dart"; 15 | export "src/non_uniform_rounded_rectangle_border.dart"; 16 | export "src/normalized_overflow_box.dart"; 17 | export "src/pad.dart"; 18 | export "src/row_super.dart"; 19 | export "src/scroll_shadow.dart"; 20 | export "src/show_dialog_super.dart"; 21 | export "src/side_by_side.dart"; 22 | export "src/text_one_line.dart"; 23 | export "src/time_builder.dart"; 24 | export "src/wrap_super.dart"; 25 | -------------------------------------------------------------------------------- /lib/src/box_animating_width.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// This widget is meant only to be used for layout demonstrations of other widgets. 4 | /// 5 | /// The child widget will be wrapped in a container that animates its width, 6 | /// between [maxWidth] and [minWidth], with the given [border] around it. 7 | /// The animation will repeat indefinitely. It takes [moveDuration] to move from 8 | /// [maxWidth] to [minWidth] and vice versa. It will hold at [maxWidth] for 9 | /// [maxHoldDuration] and at [minWidth] for [minHoldDuration]. 10 | /// 11 | class BoxAnimatingWidth extends StatefulWidget { 12 | // 13 | final Widget child; 14 | final double minWidth; 15 | final double? maxWidth; 16 | final Duration moveDuration; 17 | final Duration maxHoldDuration; 18 | final Duration minHoldDuration; 19 | final Border? border; 20 | 21 | const BoxAnimatingWidth({ 22 | Key? key, 23 | required this.child, 24 | this.minWidth = 80.0, 25 | this.maxWidth, 26 | this.moveDuration = const Duration(milliseconds: 3500), 27 | this.maxHoldDuration = const Duration(seconds: 1), 28 | this.minHoldDuration = const Duration(seconds: 1), 29 | this.border, 30 | }) : super(key: key); 31 | 32 | @override 33 | State createState() => _BoxAnimatingWidthState(); 34 | } 35 | 36 | class _BoxAnimatingWidthState extends State 37 | with SingleTickerProviderStateMixin { 38 | late final AnimationController _controller; 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | 44 | // Total duration is the sum of all durations. 45 | final totalDuration = 46 | widget.moveDuration * 2 + widget.maxHoldDuration + widget.minHoldDuration; 47 | 48 | _controller = AnimationController( 49 | vsync: this, 50 | duration: totalDuration, 51 | ); 52 | 53 | _controller.repeat(); 54 | } 55 | 56 | @override 57 | void dispose() { 58 | _controller.dispose(); 59 | super.dispose(); 60 | } 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return LayoutBuilder( 65 | builder: (context, constraints) { 66 | double parentWidth = constraints.maxWidth; 67 | 68 | final Animation _widthAnimation = TweenSequence([ 69 | TweenSequenceItem( 70 | tween: 71 | Tween(begin: widget.maxWidth ?? parentWidth, end: widget.minWidth) 72 | .chain(CurveTween(curve: Curves.easeInOut)), 73 | weight: widget.moveDuration.inMilliseconds.toDouble(), 74 | ), 75 | TweenSequenceItem( 76 | tween: ConstantTween(widget.minWidth), 77 | weight: widget.minHoldDuration.inMilliseconds.toDouble(), 78 | ), 79 | TweenSequenceItem( 80 | tween: 81 | Tween(begin: widget.minWidth, end: widget.maxWidth ?? parentWidth) 82 | .chain(CurveTween(curve: Curves.easeInOut)), 83 | weight: widget.moveDuration.inMilliseconds.toDouble(), 84 | ), 85 | TweenSequenceItem( 86 | tween: ConstantTween(widget.maxWidth ?? parentWidth), 87 | weight: widget.maxHoldDuration.inMilliseconds.toDouble(), 88 | ), 89 | ]).animate(_controller); 90 | 91 | return AnimatedBuilder( 92 | animation: _widthAnimation, 93 | builder: (context, child) { 94 | return Container( 95 | width: _widthAnimation.value, 96 | constraints: const BoxConstraints(minHeight: 10), 97 | decoration: BoxDecoration( 98 | border: widget.border ?? Border.all(color: Colors.black, width: 1), 99 | ), 100 | child: widget.child, 101 | ); 102 | }, 103 | ); 104 | }, 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/src/button.dart: -------------------------------------------------------------------------------- 1 | import "dart:async"; 2 | 3 | import "package:flutter/cupertino.dart"; 4 | import "package:flutter/material.dart"; 5 | 6 | typedef ButtonBuilder = Widget Function({ 7 | /// True when the button is tapped-down. 8 | required bool isPressed, 9 | }); 10 | 11 | /// Transforms any widget in a button, with visual feedback in the onPointerDown. 12 | /// The widget must be created with a [builder] of type [ButtonBuilder], which provides an 13 | /// [isPressed] boolean to indicate whether the button is pressed or not. 14 | /// 15 | /// Thus, the widget can change its look according to these values. 16 | /// 17 | /// There are 3 possibilities to detect gestures: 18 | /// 19 | /// 1) Use the [onTap] parameter. 20 | /// 21 | /// 2) The widget itself can contain a [GestureDetector]. 22 | /// 23 | /// 3) The Button can be inside a parent that detects gestures. Even with a null [onTap], the look 24 | /// still changes when you touch the button. This allows the button to be used inside other widgets 25 | /// that detect gestures. Note that [isPressed] is changed immediately as soon as the user touches 26 | /// the button, through a listener, which is faster than GestureDetector (which has a delay to 27 | /// differentiate between the various types of gestures). 28 | /// 29 | class Button extends StatefulWidget { 30 | // 31 | static const delayMillis = 75; 32 | 33 | final ButtonBuilder builder; 34 | final VoidCallback? onTap; 35 | final VoidCallback? onDragUp; 36 | 37 | /// You should pass delay=true only when the widget is inside a scrollable. This makes the button 38 | /// color change wait a few milliseconds (for when the user actually wants to start a scroll and 39 | /// not press the button). 40 | final bool delay; 41 | 42 | /// The minimum duration you want the button to show it was tapped. 43 | final Duration? minVisualTapDuration; 44 | 45 | /// The button does not allow calling [onTap] more than once per [tapThrottle]. Note: Visually it 46 | /// may appear to respond, but [onTap] is not called. Note: If [tapThrottle] doesn't seem to be 47 | /// working, check that you're not accidentally calling initState. Obviously, initState resets 48 | /// the time count. 49 | final Duration? tapThrottle; 50 | 51 | /// If [disable] is true, the [onTap] and [onDragUp] won't work. 52 | final bool disable; 53 | 54 | final EdgeInsetsGeometry? clickAreaMargin; 55 | 56 | final Color colorOfClickableArea; 57 | 58 | const Button({ 59 | Key? key, 60 | required this.builder, 61 | required this.onTap, 62 | bool? disable, 63 | this.onDragUp, 64 | this.delay = false, 65 | this.minVisualTapDuration, 66 | this.tapThrottle, 67 | this.clickAreaMargin, 68 | bool debugShowClickableArea = false, 69 | }) : disable = disable ?? false, 70 | colorOfClickableArea = 71 | debugShowClickableArea ? const Color(0xBBFF0000) : const Color(0x00000000), 72 | super(key: key); 73 | 74 | @override 75 | _ButtonState createState() => _ButtonState(); 76 | } 77 | 78 | class _ButtonState extends State