├── _config.yml
├── example
├── devtools_options.yaml
├── ios
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ ├── AppDelegate.swift
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ └── Info.plist
│ ├── Runner.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── xcshareddata
│ │ │ └── xcschemes
│ │ │ │ └── Runner.xcscheme
│ │ └── project.pbxproj
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── .gitignore
├── android
│ ├── gradle.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── 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
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── values
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── net
│ │ │ │ │ │ └── rcprogrammer
│ │ │ │ │ │ └── flutter_bargraph_example
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── settings.gradle
│ └── build.gradle
├── .metadata
├── pubspec.yaml
├── analysis_options.yaml
├── .gitignore
├── lib
│ └── main.dart
├── pubspec.lock
└── README.md
├── .github
├── FUNDING.yml
└── workflows
│ └── flutter.yml
├── doc
└── media
│ ├── example.gif
│ ├── example.mp4
│ └── screenshot.png
├── .metadata
├── lib
├── flutter_expandable_table.dart
└── src
│ ├── class
│ ├── cell_details.dart
│ ├── cell.dart
│ ├── header.dart
│ ├── row.dart
│ └── controller.dart
│ ├── widget_internal
│ ├── cell.dart
│ └── table.dart
│ └── widget
│ └── table.dart
├── analysis_options.yaml
├── pubspec.yaml
├── LICENSE
├── CHANGELOG.md
├── .gitignore
├── test
├── widget_test.dart
└── my_app_test.dart
├── pubspec.lock
└── README.md
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
--------------------------------------------------------------------------------
/example/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | extensions:
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: rickypid
2 | custom: https://buymeacoffee.com/veweju
3 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/doc/media/example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/doc/media/example.gif
--------------------------------------------------------------------------------
/doc/media/example.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/doc/media/example.mp4
--------------------------------------------------------------------------------
/doc/media/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/doc/media/screenshot.png
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/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/rickypid/flutter_expandable_table/HEAD/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/rickypid/flutter_expandable_table/HEAD/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/rickypid/flutter_expandable_table/HEAD/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/rickypid/flutter_expandable_table/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickypid/flutter_expandable_table/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/net/rcprogrammer/flutter_bargraph_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package net.rcprogrammer.flutter_expandable_table_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.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: b2e05062b6d1d73024bbd42bf974509f9ddfb383
8 | channel: master
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/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: b2e05062b6d1d73024bbd42bf974509f9ddfb383
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/lib/flutter_expandable_table.dart:
--------------------------------------------------------------------------------
1 | /// A Flutter widget for create an expandable table with header and first column fixed.
2 | library flutter_expandable_table;
3 |
4 | export 'src/class/row.dart';
5 | export 'src/class/header.dart';
6 | export 'src/class/cell.dart';
7 | export 'src/class/controller.dart';
8 | export 'src/class/cell_details.dart';
9 | export 'src/widget/table.dart';
10 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_expandable_table_example
2 | description: A Flutter widget for create an expandable table with header and first column fixed.
3 | version: 2.1.0
4 |
5 | environment:
6 | sdk: ">=2.18.0 <4.0.0"
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 |
12 | dev_dependencies:
13 | flutter_expandable_table:
14 | path: ../
15 | flutter_lints: ^4.0.0
16 | flutter_test:
17 | sdk: flutter
18 | import_sorter: ^4.6.0
19 |
20 | flutter:
21 | uses-material-design: true
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/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/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 | - public_member_api_docs
6 | - recursive_getters
7 | - always_use_package_imports
8 | - prefer_expression_function_bodies
9 | - prefer_single_quotes
10 | - always_declare_return_types
11 | - avoid_unused_constructor_parameters
12 | - prefer_final_fields
13 | - prefer_final_locals
14 | - sort_pub_dependencies
15 | - type_annotate_public_apis
16 | - unawaited_futures
17 | - use_named_constants
18 | - use_super_parameters
19 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 | - public_member_api_docs
6 | - recursive_getters
7 | - always_use_package_imports
8 | - prefer_expression_function_bodies
9 | - prefer_single_quotes
10 | - always_declare_return_types
11 | - avoid_unused_constructor_parameters
12 | - prefer_final_fields
13 | - prefer_final_locals
14 | - sort_pub_dependencies
15 | - type_annotate_public_apis
16 | - unawaited_futures
17 | - use_named_constants
18 | - use_super_parameters
19 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/flutter.yml:
--------------------------------------------------------------------------------
1 | name: Flutter
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | - uses: subosito/flutter-action@v2
16 | with:
17 | channel: 'stable'
18 |
19 | - name: Install dependencies
20 | run: flutter pub get
21 |
22 | - name: Analyze project source
23 | run: dart analyze
24 |
25 | - name: Flutter test
26 | run: flutter test
27 |
28 | - name: Install pana
29 | run: dart pub global activate pana
30 |
31 | - name: Analyze project source with pana
32 | run: pana
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_expandable_table
2 | description: A Flutter widget for create an expandable table with header and first column fixed.
3 | version: 2.1.0
4 | repository: https://github.com/rickypid/flutter_expandable_table
5 | issue_tracker: https://github.com/rickypid/flutter_expandable_table/issues
6 |
7 | environment:
8 | sdk: ">=2.18.0 <4.0.0"
9 | flutter: ">=1.17.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | flutter_scroll_shadow: ^1.2.4
15 | linked_scroll_controller: ^0.2.0
16 | provider: ^6.1.2
17 |
18 | dev_dependencies:
19 | flutter_lints: ^4.0.0
20 | flutter_test:
21 | sdk: flutter
22 | import_sorter: ^4.6.0
23 |
24 | flutter:
25 | screenshots:
26 | - description: 'Expandable Table - screenshot 1'
27 | path: doc/media/screenshot.png
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/src/class/cell_details.dart:
--------------------------------------------------------------------------------
1 | // Project imports:
2 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
3 |
4 | /// [CellDetails] class.
5 | /// This class contains the details of a cell, such as the
6 | /// instance of the row and column it belongs to, furthermore
7 | /// if the cell is inside a nested row or column it is possible
8 | /// to access the instance of the parent row or column
9 | class CellDetails {
10 | /// [header] is the instance of the column it belongs to.
11 | final ExpandableTableHeader? header;
12 |
13 | /// [row] is the instance of the row it belongs to.
14 | final ExpandableTableRow? row;
15 |
16 | /// [headerParent] is the instance of the parent column it
17 | /// belongs to (Only if it is inside a nested column).
18 | final ExpandableTableHeader? headerParent;
19 |
20 | /// [rowParent] is the instance of the parent row it
21 | /// belongs to (Only if it is inside a nested row).
22 | final ExpandableTableRow? rowParent;
23 |
24 | /// [CellDetails] class constructor.
25 | /// This class contains the details of a cell, such as the
26 | /// instance of the row and column it belongs to, furthermore
27 | /// if the cell is inside a nested row or column it is possible
28 | /// to access the instance of the parent row or column
29 | CellDetails({
30 | required this.headerParent,
31 | required this.rowParent,
32 | required this.header,
33 | required this.row,
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright © 2021 Riccardo Cucia (https://www.rcprogrammer.net/) All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without modification,
4 | are permitted provided that the following conditions are met:
5 | * Redistributions of source code must retain the above copyright notice, this
6 | list of conditions and the following disclaimer.
7 | * Redistributions in binary form must reproduce the above copyright notice, this
8 | list of conditions and the following disclaimer in the documentation and/or
9 | other materials provided with the distribution.
10 | * Neither the name of Riccardo Cucia nor the names of its contributors may be used to
11 | endorse or promote products derived from this software without specific prior
12 | written permission.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/lib/src/class/cell.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:flutter_expandable_table/src/class/cell_details.dart';
6 |
7 | /// [ExpandableTableCell] class.
8 | /// This class defines a single table cell.
9 | /// You can define a child Widget or pass a builder function to build
10 | /// your widget in the cell. Using the builder it is possible to access
11 | /// the details of the cell itself.
12 | class ExpandableTableCell extends ChangeNotifier {
13 | /// [builder] By defining the builder function it is possible to return
14 | /// the Widget to be inserted inside the cell and access the details
15 | /// of the cell itself during the build..
16 | /// `optional`
17 | final CellBuilder? builder;
18 |
19 | /// [child] Widget to insert inside the cell
20 | /// `optional`
21 | final Widget? child;
22 |
23 | /// [ExpandableTableCell] class constructor.
24 | /// This class defines a single table cell.
25 | /// You can define a child Widget or pass a builder function to build
26 | /// your widget in the cell. Using the builder it is possible to access
27 | /// the details of the cell itself.
28 | ExpandableTableCell({
29 | this.builder,
30 | this.child,
31 | }) : assert((builder != null || child != null) &&
32 | (builder == null || child == null));
33 |
34 | /// [build] method for building the cell contents
35 | Widget build(BuildContext context, CellDetails details) =>
36 | child ?? builder!(context, details);
37 | }
38 |
39 | /// [CellBuilder] type definition.
40 | typedef CellBuilder = Widget Function(
41 | BuildContext context, CellDetails details);
42 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Flutter Expandable Table
2 |
3 | ## [2.1.0] - 2024-07-03
4 | #### [@RichiB20](https://github.com/RichiB20)
5 | - Fixed vertical Scrollbar and added horizontal Scrollbar.
6 | - Added `trackVisibilityScrollbar`,`thumbVisibilityScrollbar` and `expanded` parameters.
7 | - Fixed table size.
8 |
9 | ## [2.0.1] - 2023-09-04
10 | #### [@rickypid](https://github.com/rickypid)
11 | - Update flutter_scroll_shadow dependency, add GitHub Actions.
12 |
13 | ## [2.0.0] - 2023-06-01
14 | #### [@rickypid](https://github.com/rickypid)
15 | - Release 2.0.0, improved documentation and tests.
16 |
17 | ## [2.0.0-beta.2] - 2023-05-19
18 | #### [@rickypid](https://github.com/rickypid)
19 | - Release 2.0.0, improved functionality and structure.
20 |
21 | ## [2.0.0-beta.1] - 2023-05-13
22 | #### [@rickypid](https://github.com/rickypid)
23 | - Release 2.0.0, improved functionality and structure.
24 |
25 | ## [1.1.1] - 2022-06-07
26 | #### [@allato](https://github.com/allato)
27 | - Format code.
28 |
29 | ## [1.1.0] - 2022-06-07
30 | #### [@RichiB20](https://github.com/RichiB20)
31 | - implemented property `visibleScrollbar`.
32 |
33 | ## [1.0.2] - 2022-02-03
34 | #### [@rickypid](https://github.com/rickypid)
35 | - Remove unnecessary imports and unnecessary null check, upgraded dependency.
36 |
37 | ## [1.0.1] - 2022-01-25
38 | #### [@rickypid](https://github.com/rickypid)
39 | - Improved documentations.
40 |
41 | ## [1.0.0] - 2021-07-23
42 | #### [@rickypid](https://github.com/rickypid)
43 | - Stable release.
44 |
45 | ## [0.0.2-alpha] - 2021-07-20
46 | #### [@rickypid](https://github.com/rickypid)
47 | - Change README.md.
48 |
49 | ## [0.0.1-alpha] - 2021-07-20
50 | #### [@rickypid](https://github.com/rickypid)
51 | - Initial release.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_expandable_table_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | build/
32 |
33 | # Android related
34 | **/android/**/gradle-wrapper.jar
35 | **/android/.gradle
36 | **/android/captures/
37 | **/android/gradlew
38 | **/android/gradlew.bat
39 | **/android/local.properties
40 | **/android/**/GeneratedPluginRegistrant.java
41 |
42 | # iOS/XCode related
43 | **/ios/**/*.mode1v3
44 | **/ios/**/*.mode2v3
45 | **/ios/**/*.moved-aside
46 | **/ios/**/*.pbxuser
47 | **/ios/**/*.perspectivev3
48 | **/ios/**/*sync/
49 | **/ios/**/.sconsign.dblite
50 | **/ios/**/.tags*
51 | **/ios/**/.vagrant/
52 | **/ios/**/DerivedData/
53 | **/ios/**/Icon?
54 | **/ios/**/Pods/
55 | **/ios/**/.symlinks/
56 | **/ios/**/profile
57 | **/ios/**/xcuserdata
58 | **/ios/.generated/
59 | **/ios/Flutter/App.framework
60 | **/ios/Flutter/Flutter.framework
61 | **/ios/Flutter/Flutter.podspec
62 | **/ios/Flutter/Generated.xcconfig
63 | **/ios/Flutter/app.flx
64 | **/ios/Flutter/app.zip
65 | **/ios/Flutter/flutter_assets/
66 | **/ios/Flutter/flutter_export_environment.sh
67 | **/ios/ServiceDefinitions.json
68 | **/ios/Runner/GeneratedPluginRegistrant.*
69 |
70 | # Exceptions to above rules.
71 | !**/ios/**/default.mode1v3
72 | !**/ios/**/default.mode2v3
73 | !**/ios/**/default.pbxuser
74 | !**/ios/**/default.perspectivev3
75 |
--------------------------------------------------------------------------------
/lib/src/widget_internal/cell.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:provider/provider.dart';
6 |
7 | // Project imports:
8 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
9 |
10 | /// [ExpandableTableCellWidget] it is the widget that builds the table cell.
11 | class ExpandableTableCellWidget extends StatelessWidget {
12 | /// [builder] method for building cell content.
13 | final Function(BuildContext context, CellDetails details) builder;
14 |
15 | /// [height] cell height.
16 | final double height;
17 |
18 | /// [width] cell width.
19 | final double width;
20 |
21 | /// [onTap] tap event.
22 | final VoidCallback? onTap;
23 |
24 | /// [header] header of the table this cell belongs to.
25 | final ExpandableTableHeader? header;
26 |
27 | /// [row] row of the table this cell belongs to.
28 | final ExpandableTableRow? row;
29 |
30 | /// [ExpandableTableCellWidget] widget constructor.
31 | const ExpandableTableCellWidget({
32 | super.key,
33 | required this.builder,
34 | required this.height,
35 | required this.width,
36 | this.onTap,
37 | this.header,
38 | this.row,
39 | });
40 |
41 | @override
42 | Widget build(BuildContext context) => GestureDetector(
43 | onTap: onTap,
44 | child: AnimatedContainer(
45 | duration: context.watch().duration,
46 | curve: context.watch().curve,
47 | width: header?.visible == false ? 0 : width,
48 | height: row?.visible == false ? 0 : height,
49 | child: builder(
50 | context,
51 | CellDetails(
52 | headerParent: header?.parent,
53 | rowParent: row?.parent,
54 | header: header,
55 | row: row,
56 | ),
57 | ),
58 | ),
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 30
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | defaultConfig {
36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
37 | applicationId "net.rcprogrammer.flutter_expandable_table_example"
38 | minSdkVersion 16
39 | targetSdkVersion 30
40 | versionCode flutterVersionCode.toInteger()
41 | versionName flutterVersionName
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
59 | }
60 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/lib/src/class/header.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
6 |
7 | /// [ExpandableTableHeader] class.
8 | /// This class defines a single table header.
9 | class ExpandableTableHeader extends ChangeNotifier {
10 | /// [cell] Defines the contents of the column header cell.
11 | /// `required`
12 | final ExpandableTableCell cell;
13 | late List? _children;
14 |
15 | /// [children] returns nested columns to this one.
16 | List? get children => _children;
17 |
18 | /// [children] defines columns nested to this, populating
19 | /// this list will create an expandable column.
20 | set children(List? value) {
21 | _removeChildrenListener();
22 | _children = value;
23 | _addChildrenListener();
24 | notifyListeners();
25 | }
26 |
27 | /// [width] defines the width of the column, if not specified
28 | /// the default width defined in the table will be used.
29 | /// `optional`
30 | final double? width;
31 |
32 | /// [hideWhenExpanded] Defines whether this column should be
33 | /// hidden when nested columns are expanded. Attention, by setting
34 | /// this property to true it will be necessary to implement manual
35 | /// management of column expansion.
36 | /// `Default: false`
37 | final bool hideWhenExpanded;
38 |
39 | /// [disableDefaultOnTapExpansion] Defines whether to disable the
40 | /// standard expand interaction, setting to true will require
41 | /// manually implementing an expand logic.
42 | /// `Default: false`
43 | final bool disableDefaultOnTapExpansion;
44 |
45 | late bool _childrenExpanded;
46 |
47 | /// [childrenExpanded] returns true if the children nested to this column have been expanded.
48 | bool get childrenExpanded =>
49 | children?.isNotEmpty == true && _childrenExpanded;
50 |
51 | /// [childrenExpanded] allows you to expand or not the columns nested within this one.
52 | set childrenExpanded(bool value) {
53 | if (children != null) {
54 | _childrenExpanded = value;
55 | if (!_childrenExpanded) {
56 | for (var child in children!) {
57 | child.childrenExpanded = false;
58 | }
59 | }
60 | notifyListeners();
61 | }
62 | }
63 |
64 | ExpandableTableHeader? _parent;
65 |
66 | /// [parent] if this column is nested within another,
67 | /// the instance of the parent column is returned
68 | ExpandableTableHeader? get parent => _parent;
69 |
70 | /// [index] indicates the current index of this column, referring to the parent.
71 | int? index;
72 |
73 | /// [ExpandableTableHeader] class constructor.
74 | /// This class defines a single table header.
75 | ExpandableTableHeader({
76 | required this.cell,
77 | List? children,
78 | this.width,
79 | this.hideWhenExpanded = false,
80 | bool childrenExpanded = false,
81 | this.disableDefaultOnTapExpansion = false,
82 | }) {
83 | _childrenExpanded = childrenExpanded;
84 | _children = children;
85 | _addChildrenListener();
86 | }
87 |
88 | void _addChildrenListener() {
89 | if (_children != null) {
90 | for (var i = 0; i < _children!.length; i++) {
91 | children![i]._parent = this;
92 | _children![i].addListener(_listener);
93 | _children![i].index = i;
94 | }
95 | }
96 | }
97 |
98 | void _removeChildrenListener() {
99 | if (_children != null) {
100 | for (var child in _children!) {
101 | child.removeListener(_listener);
102 | }
103 | }
104 | }
105 |
106 | @override
107 | void dispose() {
108 | _removeChildrenListener();
109 | super.dispose();
110 | }
111 |
112 | void _listener() => notifyListeners();
113 |
114 | /// [columnsCount] returns the number of columns, this one and
115 | /// all those nested within it.
116 | int get columnsCount {
117 | int count = 1;
118 | if (children != null) {
119 | for (var e in children!) {
120 | count += e.columnsCount;
121 | }
122 | }
123 | return count;
124 | }
125 |
126 | /// [visibleColumnsCount] returns the number of columns currently visible,
127 | /// this one and all those nested within it.
128 | int get visibleColumnsCount {
129 | int count = childrenExpanded && hideWhenExpanded ? 0 : 1;
130 | if (children != null) {
131 | for (var e in children!) {
132 | count += e.visibleColumnsCount;
133 | }
134 | }
135 | return count;
136 | }
137 |
138 | /// [visible] returns true if this column is currently visible.
139 | bool get visible =>
140 | (!childrenExpanded || !hideWhenExpanded) &&
141 | (parent == null || parent?.childrenExpanded == true);
142 |
143 | /// [address] returns a list of integers, each of which the position
144 | /// referred to the parent column, each nesting adds an element to the
145 | /// list, this element will be the address of the column with respect to the parent.
146 | List get address => (parent?.address ?? [])..add(index ?? -1);
147 |
148 | /// [toggleExpand] this method allows you to reverse the
149 | /// expansion or not of the child columns.
150 | void toggleExpand() => childrenExpanded = !childrenExpanded;
151 | }
152 |
--------------------------------------------------------------------------------
/lib/src/class/row.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
6 |
7 | /// [ExpandableTableRow] class.
8 | /// This class defines a single table row.
9 | class ExpandableTableRow extends ChangeNotifier {
10 | /// [firstCell] defines the contents of the first cell, this cell
11 | /// is the cell that remains fixed during horizontal scrolling..
12 | /// `required`
13 | final ExpandableTableCell firstCell;
14 |
15 | /// [cells] defines the cells in the row, excluding the first one on the left.
16 | /// The length of this list must be identical to the total headers, including nested ones.
17 | /// `optional, if it is not defined, the legend must be defined`
18 | final List? cells;
19 |
20 | late List? _children;
21 |
22 | /// [children] returns nested rows to this one.
23 | List? get children => _children;
24 |
25 | /// [children] defines rows nested to this, populating
26 | /// this list will create an expandable row.
27 | set children(List? value) {
28 | _removeChildrenListener();
29 | _children = value;
30 | _addChildrenListener();
31 | notifyListeners();
32 | }
33 |
34 | /// [legend] defines the object to insert in place of the cells of the row, used to
35 | /// create separation or display of totals for example.
36 | /// `optional, if it is not defined, the [cells] must be defined`
37 | final Widget? legend;
38 |
39 | /// [height] defines the height of the row, if not specified
40 | /// the default height defined in the table will be used.
41 | /// `optional`
42 | final double? height;
43 |
44 | /// [hideWhenExpanded] Defines whether this row should be
45 | /// hidden when nested rows are expanded. Attention, by setting
46 | /// this property to true it will be necessary to implement manual
47 | /// management of column expansion.
48 | /// `Default: false`
49 | final bool hideWhenExpanded;
50 |
51 | /// [disableDefaultOnTapExpansion] Defines whether to disable the
52 | /// standard expand interaction, setting to true will require
53 | /// manually implementing an expand logic.
54 | /// `Default: false`
55 | final bool disableDefaultOnTapExpansion;
56 |
57 | late bool _childrenExpanded;
58 |
59 | /// [childrenExpanded] returns true if the children nested to this row have been expanded.
60 | bool get childrenExpanded =>
61 | children?.isNotEmpty == true && _childrenExpanded;
62 |
63 | /// [childrenExpanded] allows you to expand or not the rows nested within this one.
64 | set childrenExpanded(bool value) {
65 | if (children != null) {
66 | _childrenExpanded = value;
67 | if (!_childrenExpanded) {
68 | for (var child in children!) {
69 | child.childrenExpanded = false;
70 | }
71 | }
72 | notifyListeners();
73 | }
74 | }
75 |
76 | ExpandableTableRow? _parent;
77 |
78 | /// [parent] if this row is nested within another,
79 | /// the instance of the parent row is returned
80 | ExpandableTableRow? get parent => _parent;
81 |
82 | /// [index] indicates the current index of this row, referring to the parent.
83 | int? index;
84 |
85 | /// [ExpandableTableRow] class constructor.
86 | /// This class defines a single table row.
87 | ExpandableTableRow({
88 | required this.firstCell,
89 | this.cells,
90 | this.legend,
91 | List? children,
92 | this.height,
93 | this.hideWhenExpanded = false,
94 | bool childrenExpanded = false,
95 | this.disableDefaultOnTapExpansion = false,
96 | }) : assert((cells != null || legend != null) &&
97 | (cells == null || legend == null)) {
98 | _childrenExpanded = childrenExpanded;
99 | _children = children;
100 | _addChildrenListener();
101 | }
102 |
103 | void _addChildrenListener() {
104 | if (_children != null) {
105 | for (var i = 0; i < _children!.length; i++) {
106 | children![i]._parent = this;
107 | _children![i].addListener(_listener);
108 | _children![i].index = i;
109 | }
110 | }
111 | }
112 |
113 | void _removeChildrenListener() {
114 | if (_children != null) {
115 | for (var child in _children!) {
116 | child.removeListener(_listener);
117 | }
118 | }
119 | }
120 |
121 | @override
122 | void dispose() {
123 | _removeChildrenListener();
124 | super.dispose();
125 | }
126 |
127 | void _listener() => notifyListeners();
128 |
129 | /// [rowsCount] returns the number of rows, this one and
130 | /// all those nested within it.
131 | int get rowsCount {
132 | int count = 1;
133 | if (children != null) {
134 | for (var e in children!) {
135 | count += e.visibleRowsCount;
136 | }
137 | }
138 | return count;
139 | }
140 |
141 | /// [visibleRowsCount] returns the number of rows currently visible,
142 | /// this one and all those nested within it.
143 | int get visibleRowsCount {
144 | int count = childrenExpanded && hideWhenExpanded ? 0 : 1;
145 | if (children != null) {
146 | for (var e in children!) {
147 | count += e.visibleRowsCount;
148 | }
149 | }
150 | return count;
151 | }
152 |
153 | /// [cellsCount] returns the number of cells in the row, excluding the first.
154 | int? get cellsCount => cells?.length;
155 |
156 | /// [visible] returns true if this row is currently visible.
157 | bool get visible =>
158 | (!childrenExpanded || !hideWhenExpanded) &&
159 | (parent == null || parent?.childrenExpanded == true);
160 |
161 | /// [address] returns a list of integers, each of which the position
162 | /// referred to the parent row, each nesting adds an element to the
163 | /// list, this element will be the address of the row with respect to the parent.
164 | List get address => (parent?.address ?? [])..add(index ?? 0);
165 |
166 | /// [toggleExpand] this method allows you to reverse the
167 | /// expansion or not of the child rows.
168 | void toggleExpand() => childrenExpanded = !childrenExpanded;
169 | }
170 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_test/flutter_test.dart';
6 |
7 | // Project imports:
8 | import 'my_app_test.dart';
9 |
10 | void main() {
11 | const widget = MyApp();
12 | group('Simple table', () {
13 | testWidgets('First header table cell', (tester) async {
14 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
15 | await tester.pumpWidget(widget);
16 | expect(find.text('Simple\nTable'), findsOneWidget);
17 | });
18 | testWidgets('Visible columns and rows limits', (tester) async {
19 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
20 | await tester.pumpWidget(widget);
21 | expect(find.text('_Column 0').hitTestable(), findsOneWidget);
22 | expect(find.text('_Column 3').hitTestable(), findsOneWidget);
23 | expect(find.text('_Column 4').hitTestable(), findsNothing);
24 | expect(find.text('_Row 0').hitTestable(), findsOneWidget);
25 | expect(find.text('_Row 12').hitTestable(), findsOneWidget);
26 | expect(find.text('_Row 13').hitTestable(), findsNothing);
27 | expect(find.text('_Cell 0:0').hitTestable(), findsOneWidget);
28 | expect(find.text('_Cell 0:3').hitTestable(), findsOneWidget);
29 | expect(find.text('_Cell 0:4').hitTestable(), findsNothing);
30 | expect(find.text('_Cell 12:0').hitTestable(), findsOneWidget);
31 | expect(find.text('_Cell 12:3').hitTestable(), findsOneWidget);
32 | expect(find.text('_Cell 12:4').hitTestable(), findsNothing);
33 | });
34 | testWidgets('First column vertical scroll', (tester) async {
35 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
36 | await tester.pumpWidget(widget);
37 | expect(find.text('_Row 0').hitTestable(), findsOneWidget);
38 | expect(find.text('_Cell 0:0').hitTestable(), findsOneWidget);
39 | expect(find.text('_Row 18').hitTestable(), findsNothing);
40 | expect(find.text('_Cell 18:0').hitTestable(), findsNothing);
41 | await tester.dragFrom(
42 | tester.getCenter(find.text('_Row 12')), const Offset(0, -500));
43 | await tester.pump();
44 | expect(find.text('_Row 18').hitTestable(), findsOneWidget);
45 | expect(find.text('_Cell 18:0').hitTestable(), findsOneWidget);
46 | expect(find.text('_Row 0').hitTestable(), findsNothing);
47 | expect(find.text('_Cell 0:0').hitTestable(), findsNothing);
48 | });
49 | testWidgets('Header horizontal scroll', (tester) async {
50 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
51 | await tester.pumpWidget(widget);
52 | expect(find.text('_Column 0').hitTestable(), findsOneWidget);
53 | expect(find.text('_Cell 0:0').hitTestable(), findsOneWidget);
54 | expect(find.text('_Column 7').hitTestable(), findsNothing);
55 | expect(find.text('_Cell 0:7').hitTestable(), findsNothing);
56 | await tester.dragFrom(
57 | tester.getCenter(find.text('_Column 3')), const Offset(-730, 0));
58 | await tester.pump();
59 | expect(find.text('_Column 0').hitTestable(), findsNothing);
60 | expect(find.text('_Cell 0:0').hitTestable(), findsNothing);
61 | expect(find.text('_Column 7').hitTestable(), findsOneWidget);
62 | expect(find.text('_Cell 0:7').hitTestable(), findsOneWidget);
63 | });
64 | testWidgets('Body vertical scroll', (tester) async {
65 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
66 | await tester.pumpWidget(widget);
67 | expect(find.text('_Row 0').hitTestable(), findsOneWidget);
68 | expect(find.text('_Cell 0:0').hitTestable(), findsOneWidget);
69 | expect(find.text('_Row 18').hitTestable(), findsNothing);
70 | expect(find.text('_Cell 18:0').hitTestable(), findsNothing);
71 | await tester.dragFrom(
72 | tester.getCenter(find.text('_Cell 12:0')), const Offset(0, -500));
73 | await tester.pump();
74 | expect(find.text('_Row 18').hitTestable(), findsOneWidget);
75 | expect(find.text('_Cell 18:0').hitTestable(), findsOneWidget);
76 | expect(find.text('_Row 0').hitTestable(), findsNothing);
77 | expect(find.text('_Cell 0:0').hitTestable(), findsNothing);
78 | });
79 | testWidgets('Body horizontal scroll', (tester) async {
80 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
81 | await tester.pumpWidget(widget);
82 | expect(find.text('_Column 0').hitTestable(), findsOneWidget);
83 | expect(find.text('_Cell 0:0').hitTestable(), findsOneWidget);
84 | expect(find.text('_Column 7').hitTestable(), findsNothing);
85 | expect(find.text('_Cell 0:7').hitTestable(), findsNothing);
86 | await tester.dragFrom(
87 | tester.getCenter(find.text('_Cell 0:3')), const Offset(-730, 0));
88 | await tester.pump();
89 | expect(find.text('_Column 0').hitTestable(), findsNothing);
90 | expect(find.text('_Cell 0:0').hitTestable(), findsNothing);
91 | expect(find.text('_Column 7').hitTestable(), findsOneWidget);
92 | expect(find.text('_Cell 0:7').hitTestable(), findsOneWidget);
93 | });
94 | });
95 | group('Expandable table', () {
96 | testWidgets('First header table cell', (tester) async {
97 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
98 | await tester.pumpWidget(widget);
99 | expect(find.text('Expandable\nTable'), findsOneWidget);
100 | });
101 | testWidgets('Visible columns and rows limits', (tester) async {
102 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
103 | await tester.pumpWidget(widget);
104 | expect(find.text('&Column 0').hitTestable(), findsOneWidget);
105 | expect(find.text('&Column 3').hitTestable(), findsOneWidget);
106 | expect(find.text('&Column 4').hitTestable(), findsNothing);
107 | expect(find.text('&Row 0').hitTestable(), findsOneWidget);
108 | expect(find.text('&Row 5').hitTestable(), findsOneWidget);
109 | expect(find.text('&Cell 0:0').hitTestable(), findsOneWidget);
110 | expect(find.text('&Cell 0:5').hitTestable(), findsOneWidget);
111 | expect(find.text('&Cell 0:6').hitTestable(), findsNothing);
112 | expect(find.text('&Cell 5:0').hitTestable(), findsOneWidget);
113 | expect(find.text('&Cell 5:5').hitTestable(), findsOneWidget);
114 | expect(find.text('&Cell 5:6').hitTestable(), findsNothing);
115 | }); /*
116 | testWidgets('Rows expansion', (tester) async {
117 | await tester.binding.setSurfaceSize(const Size(1920, 1080));
118 | await tester.pumpWidget(widget);
119 | expect(find.text('&Row 2').hitTestable(), findsOneWidget);
120 | expect(find.text('&Sub &Row 0').hitTestable(), findsNothing);
121 | expect(find.text('&Cell 0:0').hitTestable(), findsOneWidget);
122 | await tester.tap(find.text('&Row 2'));
123 | await tester.pump(const Duration(seconds: 1));
124 | expect(find.text('&Row 2').hitTestable(), findsOneWidget);
125 | expect(find.text('&Cell 0:0').hitTestable(), findsNWidgets(2));
126 | expect(find.textContaining('&Sub &Row 0').hitTestable(), findsOneWidget);
127 | });*/
128 | });
129 | }
130 |
--------------------------------------------------------------------------------
/lib/src/widget/table.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:provider/provider.dart';
6 |
7 | // Project imports:
8 | import 'package:flutter_expandable_table/src/class/cell.dart';
9 | import 'package:flutter_expandable_table/src/class/controller.dart';
10 | import 'package:flutter_expandable_table/src/class/header.dart';
11 | import 'package:flutter_expandable_table/src/class/row.dart';
12 | import 'package:flutter_expandable_table/src/widget_internal/table.dart';
13 |
14 | /// [ExpandableTable] class.
15 | class ExpandableTable extends StatefulWidget {
16 | /// [firstHeaderCell] is the top left cell, i.e. the first header cell.
17 | /// Not to be used if the [controller] is used.
18 | /// `optional`
19 | final ExpandableTableCell? firstHeaderCell;
20 |
21 | /// [headers] contains the list of all column headers,
22 | /// each one of these can contain a list of further headers,
23 | /// this allows you to create nested and expandable columns.
24 | /// Not to be used if the [controller] is used.
25 | /// `optional`
26 | final List? headers;
27 |
28 | /// [rows] contains the list of all the rows of the table,
29 | /// each of these can contain a list of further rows,
30 | /// this allows you to create nested and expandable rows.
31 | /// Not to be used if the [controller] is used.
32 | /// `optional`
33 | final List? rows;
34 |
35 | /// [headerHeight] is the height of each column header, i.e. the first row.
36 | /// `Default: 188`
37 | final double headerHeight;
38 |
39 | /// [firstColumnWidth] determines first Column width size.
40 | ///
41 | /// Default: [200]
42 | final double firstColumnWidth;
43 |
44 | /// [defaultsColumnWidth] defines the default width of all columns,
45 | /// it is possible to redefine it for each individual column.
46 | /// Default: [120]
47 | final double defaultsColumnWidth;
48 |
49 | /// [defaultsRowHeight] defines the default height of all rows,
50 | /// it is possible to redefine it for every single row.
51 | /// Default: [50]
52 | final double defaultsRowHeight;
53 |
54 | /// [duration] determines duration rendered animation of Rows/Columns expansion.
55 | ///
56 | /// Default: [500ms]
57 | final Duration duration;
58 |
59 | /// [curve] determines rendered curve animation of Rows/Columns expansion.
60 | ///
61 | /// Default: [Curves.fastOutSlowIn]
62 | final Curve curve;
63 |
64 | /// [scrollShadowDuration] determines duration rendered animation of shadows.
65 | ///
66 | /// Default: [500ms]
67 | final Duration scrollShadowDuration;
68 |
69 | /// [scrollShadowCurve] determines rendered curve animation of shadows.
70 | ///
71 | /// Default: [Curves.fastOutSlowIn]
72 | final Curve scrollShadowCurve;
73 |
74 | /// [scrollShadowColor] determines rendered color of shadows.
75 | ///
76 | /// Default: [Colors.transparent]
77 | final Color scrollShadowColor;
78 |
79 | /// [scrollShadowSize] determines size of shadows.
80 | ///
81 | /// Default: [10]
82 | final double scrollShadowSize;
83 |
84 | /// [visibleScrollbar] determines visibility of horizontal and vertical scrollbars.
85 | ///
86 | /// Default: [false]
87 | final bool visibleScrollbar;
88 |
89 | /// [trackVisibilityScrollbar] indicates that the scrollbar track should be visible.
90 | ///
91 | /// 'optional'
92 | final bool? trackVisibilityScrollbar;
93 |
94 | /// [thumbVisibilityScrollbar] indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
95 | ///
96 | /// 'optional'
97 | final bool? thumbVisibilityScrollbar;
98 |
99 | /// [expanded] indicates that the table expands, so it fills the available space along the horizontal and vertical axes.
100 | ///
101 | /// Default: [true]
102 | final bool expanded;
103 |
104 | /// [controller] specifies the external controller of the table, allows
105 | /// you to dynamically manage the data in the table externally.
106 | /// Do not use if [firstHeaderCell], [headers] and [rows] are passed
107 | /// 'optional'
108 | final ExpandableTableController? controller;
109 |
110 | /// [ExpandableTable] class constructor.
111 | /// Required:
112 | /// - [firstHeaderCell]
113 | /// - [rows]
114 | /// - [headers]
115 | /// ```dart
116 | /// return ExpandableTable(
117 | /// firstHeaderCell: ExpandableTableCell(
118 | /// child: Text('Simple\nTable'),
119 | /// ),
120 | /// headers: headers,
121 | /// rows: rows,
122 | /// );
123 | /// ```
124 | const ExpandableTable({
125 | super.key,
126 | this.firstHeaderCell,
127 | this.headers,
128 | this.rows,
129 | this.controller,
130 | this.headerHeight = 188,
131 | this.firstColumnWidth = 200,
132 | this.defaultsColumnWidth = 120,
133 | this.defaultsRowHeight = 50,
134 | this.duration = const Duration(milliseconds: 500),
135 | this.curve = Curves.fastOutSlowIn,
136 | this.scrollShadowDuration = const Duration(milliseconds: 500),
137 | this.scrollShadowCurve = Curves.fastOutSlowIn,
138 | this.scrollShadowColor = Colors.transparent,
139 | this.scrollShadowSize = 10,
140 | this.visibleScrollbar = false,
141 | this.trackVisibilityScrollbar,
142 | this.thumbVisibilityScrollbar,
143 | this.expanded = true,
144 | }) : assert(((firstHeaderCell != null && rows != null && headers != null) ||
145 | controller != null) &&
146 | !(thumbVisibilityScrollbar == false &&
147 | (trackVisibilityScrollbar ?? false)));
148 |
149 | @override
150 | State createState() => _ExpandableTableState();
151 | }
152 |
153 | class _ExpandableTableState extends State {
154 | @override
155 | void initState() {
156 | if (widget.controller == null) {
157 | final int totalColumns =
158 | widget.headers!.map((e) => e.columnsCount).fold(0, (a, b) => a + b);
159 | for (int i = 0; i < widget.rows!.length; i++) {
160 | if (widget.rows![i].cellsCount != null &&
161 | widget.rows![i].cellsCount != totalColumns) {
162 | throw FormatException(
163 | 'Row $i cells count ${widget.rows![i].cellsCount} <> $totalColumns header cell count.');
164 | }
165 | }
166 | }
167 | super.initState();
168 | }
169 |
170 | @override
171 | Widget build(BuildContext context) => widget.controller != null
172 | ? ChangeNotifierProvider.value(
173 | value: widget.controller!,
174 | builder: (context, child) => const InternalTable(),
175 | )
176 | : ChangeNotifierProvider(
177 | create: (context) => ExpandableTableController(
178 | firstHeaderCell: widget.firstHeaderCell!,
179 | headers: widget.headers!,
180 | rows: widget.rows!,
181 | duration: widget.duration,
182 | curve: widget.curve,
183 | scrollShadowDuration: widget.scrollShadowDuration,
184 | scrollShadowFadeInCurve: widget.scrollShadowCurve,
185 | scrollShadowFadeOutCurve: widget.scrollShadowCurve,
186 | scrollShadowColor: widget.scrollShadowColor,
187 | scrollShadowSize: widget.scrollShadowSize,
188 | firstColumnWidth: widget.firstColumnWidth,
189 | defaultsColumnWidth: widget.defaultsColumnWidth,
190 | defaultsRowHeight: widget.defaultsRowHeight,
191 | headerHeight: widget.headerHeight,
192 | visibleScrollbar: widget.visibleScrollbar,
193 | trackVisibilityScrollbar: widget.trackVisibilityScrollbar,
194 | thumbVisibilityScrollbar: widget.thumbVisibilityScrollbar,
195 | expanded: widget.expanded,
196 | ),
197 | builder: (context, child) => const InternalTable(),
198 | );
199 | }
200 |
--------------------------------------------------------------------------------
/test/my_app_test.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/gestures.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | // Project imports:
6 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
7 |
8 | // ignore: depend_on_referenced_packages
9 |
10 | const Color primaryColor = Color(0xFF1e2f36); //corner
11 | const Color accentColor = Color(0xFF0d2026); //background
12 | const TextStyle textStyle = TextStyle(color: Colors.white);
13 | const TextStyle textStyleSubItems = TextStyle(color: Colors.grey);
14 |
15 | void main() => runApp(const MyApp());
16 |
17 | class MyApp extends StatelessWidget {
18 | const MyApp({super.key});
19 |
20 | @override
21 | Widget build(BuildContext context) => MaterialApp(
22 | title: 'ExpandableTable Example',
23 | theme: ThemeData(primarySwatch: Colors.grey),
24 | home: const MyHomePage(),
25 | scrollBehavior: AppCustomScrollBehavior(),
26 | );
27 | }
28 |
29 | class MyHomePage extends StatefulWidget {
30 | const MyHomePage({super.key});
31 |
32 | @override
33 | State createState() => _MyHomePageState();
34 | }
35 |
36 | class DefaultCellCard extends StatelessWidget {
37 | final Widget child;
38 |
39 | const DefaultCellCard({
40 | super.key,
41 | required this.child,
42 | });
43 |
44 | @override
45 | Widget build(BuildContext context) => Container(
46 | color: primaryColor,
47 | margin: const EdgeInsets.all(1),
48 | child: child,
49 | );
50 | }
51 |
52 | class _MyHomePageState extends State {
53 | ExpandableTableCell _buildCell(String content, {CellBuilder? builder}) =>
54 | ExpandableTableCell(
55 | child: builder != null
56 | ? null
57 | : DefaultCellCard(
58 | child: Center(
59 | child: Text(
60 | content,
61 | style: textStyle,
62 | ),
63 | ),
64 | ),
65 | builder: builder,
66 | );
67 |
68 | ExpandableTableCell _buildFirstRowCell() => ExpandableTableCell(
69 | builder: (context, details) => DefaultCellCard(
70 | child: Padding(
71 | padding: const EdgeInsets.only(left: 16.0),
72 | child: Row(
73 | children: [
74 | SizedBox(
75 | width: 24 * details.row!.address.length.toDouble(),
76 | child: details.row?.children != null
77 | ? Align(
78 | alignment: Alignment.centerRight,
79 | child: AnimatedRotation(
80 | duration: const Duration(milliseconds: 500),
81 | turns: details.row?.childrenExpanded == true
82 | ? 0.25
83 | : 0,
84 | child: const Icon(
85 | Icons.keyboard_arrow_right,
86 | color: Colors.white,
87 | ),
88 | ),
89 | )
90 | : null,
91 | ),
92 | Text(
93 | '${details.row!.address.length > 1 ? details.row!.address.skip(1).map((e) => '&Sub ').join() : ''}&Row ${details.row!.address.last}',
94 | style: textStyle,
95 | ),
96 | ],
97 | ),
98 | ),
99 | ),
100 | );
101 |
102 | ExpandableTable _buildSimpleTable() {
103 | const int columnsCount = 20;
104 | const int rowsCount = 20;
105 | //Creation header
106 | final List headers = List.generate(
107 | columnsCount - 1,
108 | (index) => ExpandableTableHeader(
109 | width: index % 2 == 0 ? 200 : 150,
110 | cell: _buildCell('_Column $index'),
111 | ),
112 | );
113 | //Creation rows
114 | final List rows = List.generate(
115 | rowsCount,
116 | (rowIndex) => ExpandableTableRow(
117 | height: rowIndex % 2 == 0 ? 50 : 70,
118 | firstCell: _buildCell('_Row $rowIndex'),
119 | cells: List.generate(
120 | columnsCount - 1,
121 | (columnIndex) => _buildCell('_Cell $rowIndex:$columnIndex'),
122 | ),
123 | ),
124 | );
125 |
126 | return ExpandableTable(
127 | firstHeaderCell: _buildCell('Simple\nTable'),
128 | headers: headers,
129 | scrollShadowColor: accentColor,
130 | rows: rows,
131 | );
132 | }
133 |
134 | static const int columnsCount = 20;
135 | static const int subColumnsCount = 2;
136 | static const int rowsCount = 6;
137 | static const int subRowsCount = 3;
138 | static const int totalColumns = columnsCount + subColumnsCount;
139 |
140 | List _generateRows(int quantity, {int depth = 0}) {
141 | final bool generateLegendRow = (depth == 0 || depth == 2);
142 | return List.generate(
143 | quantity,
144 | (rowIndex) => ExpandableTableRow(
145 | firstCell: _buildFirstRowCell(),
146 | children: ((rowIndex == 3 || rowIndex == 2) && depth < 3)
147 | ? _generateRows(subRowsCount, depth: depth + 1)
148 | : null,
149 | cells: !(generateLegendRow && (rowIndex == 3 || rowIndex == 2))
150 | ? List.generate(
151 | totalColumns,
152 | (columnIndex) => _buildCell('&Cell $rowIndex:$columnIndex'),
153 | )
154 | : null,
155 | legend: generateLegendRow && (rowIndex == 3 || rowIndex == 2)
156 | ? const DefaultCellCard(
157 | child: Align(
158 | alignment: FractionalOffset.centerLeft,
159 | child: Padding(
160 | padding: EdgeInsets.only(left: 24.0),
161 | child: Text(
162 | 'This is row legend',
163 | style: textStyle,
164 | ),
165 | ),
166 | ),
167 | )
168 | : null,
169 | ),
170 | );
171 | }
172 |
173 | ExpandableTable _buildExpandableTable() {
174 | //Creation header
175 | final List subHeader = List.generate(
176 | subColumnsCount,
177 | (index) => ExpandableTableHeader(
178 | cell: _buildCell('&Sub Column $index'),
179 | ),
180 | );
181 |
182 | //Creation header
183 | final List headers = List.generate(
184 | columnsCount,
185 | (index) => ExpandableTableHeader(
186 | cell: _buildCell(
187 | '${index == 1 ? '&Expandable\nColumn' : '&Column'} $index'),
188 | children: index == 1 ? subHeader : null),
189 | );
190 |
191 | return ExpandableTable(
192 | firstHeaderCell: _buildCell('Expandable\nTable'),
193 | rows: _generateRows(rowsCount),
194 | headers: headers,
195 | defaultsRowHeight: 60,
196 | defaultsColumnWidth: 150,
197 | firstColumnWidth: 250,
198 | scrollShadowColor: accentColor,
199 | );
200 | }
201 |
202 | @override
203 | Widget build(BuildContext context) => Scaffold(
204 | appBar: AppBar(
205 | title: const Text(
206 | ' Simple Table | Expandable Table'),
207 | centerTitle: true,
208 | ),
209 | body: Container(
210 | color: accentColor,
211 | child: Row(
212 | children: [
213 | Expanded(
214 | child: Padding(
215 | padding: const EdgeInsets.all(20.0),
216 | child: _buildSimpleTable(),
217 | ),
218 | ),
219 | Expanded(
220 | child: Padding(
221 | padding: const EdgeInsets.all(20.0),
222 | child: _buildExpandableTable(),
223 | ),
224 | ),
225 | ],
226 | ),
227 | ),
228 | );
229 | }
230 |
231 | class AppCustomScrollBehavior extends MaterialScrollBehavior {
232 | @override
233 | Set get dragDevices => {
234 | PointerDeviceKind.touch,
235 | PointerDeviceKind.mouse,
236 | PointerDeviceKind.trackpad,
237 | };
238 | }
239 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | // ignore: depend_on_referenced_packages
5 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
6 |
7 | const Color _primaryColor = Color(0xFF1e2f36); //corner
8 | const Color _accentColor = Color(0xFF0d2026); //background
9 | const TextStyle _textStyle = TextStyle(color: Colors.white);
10 | // const TextStyle _textStyleSubItems = TextStyle(color: Colors.grey);
11 |
12 | void main() => runApp(const _MyApp());
13 |
14 | class _MyApp extends StatelessWidget {
15 | const _MyApp();
16 |
17 | @override
18 | Widget build(BuildContext context) => MaterialApp(
19 | title: 'ExpandableTable Example',
20 | theme: ThemeData(primarySwatch: Colors.grey),
21 | home: const _MyHomePage(),
22 | scrollBehavior: _AppCustomScrollBehavior(),
23 | );
24 | }
25 |
26 | class _MyHomePage extends StatefulWidget {
27 | const _MyHomePage();
28 |
29 | @override
30 | State<_MyHomePage> createState() => _MyHomePageState();
31 | }
32 |
33 | class _DefaultCellCard extends StatelessWidget {
34 | final Widget child;
35 |
36 | const _DefaultCellCard({
37 | required this.child,
38 | });
39 |
40 | @override
41 | Widget build(BuildContext context) => Container(
42 | color: _primaryColor,
43 | margin: const EdgeInsets.all(1),
44 | child: child,
45 | );
46 | }
47 |
48 | class _MyHomePageState extends State<_MyHomePage> {
49 | ExpandableTableCell _buildCell(String content, {CellBuilder? builder}) =>
50 | ExpandableTableCell(
51 | child: builder != null
52 | ? null
53 | : _DefaultCellCard(
54 | child: Center(
55 | child: Text(
56 | content,
57 | style: _textStyle,
58 | ),
59 | ),
60 | ),
61 | builder: builder,
62 | );
63 |
64 | ExpandableTableCell _buildFirstRowCell() => ExpandableTableCell(
65 | builder: (context, details) => _DefaultCellCard(
66 | child: Padding(
67 | padding: const EdgeInsets.only(left: 16.0),
68 | child: Row(
69 | children: [
70 | SizedBox(
71 | width: 24 * details.row!.address.length.toDouble(),
72 | child: details.row?.children != null
73 | ? Align(
74 | alignment: Alignment.centerRight,
75 | child: AnimatedRotation(
76 | duration: const Duration(milliseconds: 500),
77 | turns: details.row?.childrenExpanded == true
78 | ? 0.25
79 | : 0,
80 | child: const Icon(
81 | Icons.keyboard_arrow_right,
82 | color: Colors.white,
83 | ),
84 | ),
85 | )
86 | : null,
87 | ),
88 | Text(
89 | '${details.row!.address.length > 1 ? details.row!.address.skip(1).map((e) => 'Sub ').join() : ''}Row ${details.row!.address.last}',
90 | style: _textStyle,
91 | ),
92 | ],
93 | ),
94 | ),
95 | ),
96 | );
97 |
98 | ExpandableTable _buildSimpleTable() {
99 | const int columnsCount = 20;
100 | const int rowsCount = 20;
101 | //Creation header
102 | final List headers = List.generate(
103 | columnsCount - 1,
104 | (index) => ExpandableTableHeader(
105 | width: index % 2 == 0 ? 200 : 150,
106 | cell: _buildCell('Column $index'),
107 | ),
108 | );
109 | //Creation rows
110 | final List rows = List.generate(
111 | rowsCount,
112 | (rowIndex) => ExpandableTableRow(
113 | height: rowIndex % 2 == 0 ? 50 : 70,
114 | firstCell: _buildCell('Row $rowIndex'),
115 | cells: List.generate(
116 | columnsCount - 1,
117 | (columnIndex) => _buildCell('Cell $rowIndex:$columnIndex'),
118 | ),
119 | ),
120 | );
121 |
122 | return ExpandableTable(
123 | firstHeaderCell: _buildCell('Simple\nTable'),
124 | headers: headers,
125 | scrollShadowColor: _accentColor,
126 | rows: rows,
127 | visibleScrollbar: true,
128 | trackVisibilityScrollbar: true,
129 | thumbVisibilityScrollbar: true,
130 | );
131 | }
132 |
133 | static const int columnsCount = 20;
134 | static const int subColumnsCount = 2;
135 | static const int rowsCount = 6;
136 | static const int subRowsCount = 3;
137 | static const int totalColumns = columnsCount + subColumnsCount;
138 |
139 | List _generateRows(int quantity, {int depth = 0}) {
140 | final bool generateLegendRow = (depth == 0 || depth == 2);
141 | return List.generate(
142 | quantity,
143 | (rowIndex) => ExpandableTableRow(
144 | firstCell: _buildFirstRowCell(),
145 | children: ((rowIndex == 3 || rowIndex == 2) && depth < 3)
146 | ? _generateRows(subRowsCount, depth: depth + 1)
147 | : null,
148 | cells: !(generateLegendRow && (rowIndex == 3 || rowIndex == 2))
149 | ? List.generate(
150 | totalColumns,
151 | (columnIndex) => _buildCell('Cell $rowIndex:$columnIndex'),
152 | )
153 | : null,
154 | legend: generateLegendRow && (rowIndex == 3 || rowIndex == 2)
155 | ? const _DefaultCellCard(
156 | child: Align(
157 | alignment: FractionalOffset.centerLeft,
158 | child: Padding(
159 | padding: EdgeInsets.only(left: 24.0),
160 | child: Text(
161 | 'This is row legend',
162 | style: _textStyle,
163 | ),
164 | ),
165 | ),
166 | )
167 | : null,
168 | ),
169 | );
170 | }
171 |
172 | ExpandableTable _buildExpandableTable() {
173 | //Creation header
174 | final List subHeader = List.generate(
175 | subColumnsCount,
176 | (index) => ExpandableTableHeader(
177 | cell: _buildCell('Sub Column $index'),
178 | ),
179 | );
180 |
181 | //Creation header
182 | final List headers = List.generate(
183 | columnsCount,
184 | (index) => ExpandableTableHeader(
185 | cell: _buildCell(
186 | '${index == 1 ? 'Expandable\nColumn' : 'Column'} $index'),
187 | children: index == 1 ? subHeader : null),
188 | );
189 |
190 | return ExpandableTable(
191 | firstHeaderCell: _buildCell('Expandable\nTable'),
192 | rows: _generateRows(rowsCount),
193 | headers: headers,
194 | defaultsRowHeight: 60,
195 | defaultsColumnWidth: 150,
196 | firstColumnWidth: 250,
197 | scrollShadowColor: _accentColor,
198 | visibleScrollbar: true,
199 | expanded: false,
200 | );
201 | }
202 |
203 | @override
204 | Widget build(BuildContext context) => Scaffold(
205 | appBar: AppBar(
206 | title: const Text(
207 | ' Simple Table | Expandable Table'),
208 | centerTitle: true,
209 | ),
210 | body: Container(
211 | color: _accentColor,
212 | child: Row(
213 | crossAxisAlignment: CrossAxisAlignment.start,
214 | children: [
215 | Expanded(
216 | child: Padding(
217 | padding: const EdgeInsets.all(20.0),
218 | child: _buildSimpleTable(),
219 | ),
220 | ),
221 | Expanded(
222 | child: Padding(
223 | padding: const EdgeInsets.all(20.0),
224 | child: _buildExpandableTable(),
225 | ),
226 | ),
227 | ],
228 | ),
229 | ),
230 | );
231 | }
232 |
233 | class _AppCustomScrollBehavior extends MaterialScrollBehavior {
234 | @override
235 | Set get dragDevices => {
236 | PointerDeviceKind.touch,
237 | PointerDeviceKind.mouse,
238 | PointerDeviceKind.trackpad,
239 | };
240 | }
241 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | args:
5 | dependency: transitive
6 | description:
7 | name: args
8 | sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.5.0"
12 | async:
13 | dependency: transitive
14 | description:
15 | name: async
16 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.11.0"
20 | boolean_selector:
21 | dependency: transitive
22 | description:
23 | name: boolean_selector
24 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "2.1.1"
28 | characters:
29 | dependency: transitive
30 | description:
31 | name: characters
32 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.3.0"
36 | clock:
37 | dependency: transitive
38 | description:
39 | name: clock
40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.1.1"
44 | collection:
45 | dependency: transitive
46 | description:
47 | name: collection
48 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.18.0"
52 | fake_async:
53 | dependency: transitive
54 | description:
55 | name: fake_async
56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "1.3.1"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_lints:
66 | dependency: "direct dev"
67 | description:
68 | name: flutter_lints
69 | sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
70 | url: "https://pub.dev"
71 | source: hosted
72 | version: "4.0.0"
73 | flutter_scroll_shadow:
74 | dependency: "direct main"
75 | description:
76 | name: flutter_scroll_shadow
77 | sha256: c0509c642c5077654301fab1fb2260adc94c82a407c60e64162974b4366e7874
78 | url: "https://pub.dev"
79 | source: hosted
80 | version: "1.2.4"
81 | flutter_test:
82 | dependency: "direct dev"
83 | description: flutter
84 | source: sdk
85 | version: "0.0.0"
86 | import_sorter:
87 | dependency: "direct dev"
88 | description:
89 | name: import_sorter
90 | sha256: eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836
91 | url: "https://pub.dev"
92 | source: hosted
93 | version: "4.6.0"
94 | leak_tracker:
95 | dependency: transitive
96 | description:
97 | name: leak_tracker
98 | sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
99 | url: "https://pub.dev"
100 | source: hosted
101 | version: "10.0.4"
102 | leak_tracker_flutter_testing:
103 | dependency: transitive
104 | description:
105 | name: leak_tracker_flutter_testing
106 | sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
107 | url: "https://pub.dev"
108 | source: hosted
109 | version: "3.0.3"
110 | leak_tracker_testing:
111 | dependency: transitive
112 | description:
113 | name: leak_tracker_testing
114 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
115 | url: "https://pub.dev"
116 | source: hosted
117 | version: "3.0.1"
118 | linked_scroll_controller:
119 | dependency: "direct main"
120 | description:
121 | name: linked_scroll_controller
122 | sha256: e6020062bcf4ffc907ee7fd090fa971e65d8dfaac3c62baf601a3ced0b37986a
123 | url: "https://pub.dev"
124 | source: hosted
125 | version: "0.2.0"
126 | lints:
127 | dependency: transitive
128 | description:
129 | name: lints
130 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
131 | url: "https://pub.dev"
132 | source: hosted
133 | version: "4.0.0"
134 | matcher:
135 | dependency: transitive
136 | description:
137 | name: matcher
138 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
139 | url: "https://pub.dev"
140 | source: hosted
141 | version: "0.12.16+1"
142 | material_color_utilities:
143 | dependency: transitive
144 | description:
145 | name: material_color_utilities
146 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
147 | url: "https://pub.dev"
148 | source: hosted
149 | version: "0.8.0"
150 | meta:
151 | dependency: transitive
152 | description:
153 | name: meta
154 | sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
155 | url: "https://pub.dev"
156 | source: hosted
157 | version: "1.12.0"
158 | nested:
159 | dependency: transitive
160 | description:
161 | name: nested
162 | sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
163 | url: "https://pub.dev"
164 | source: hosted
165 | version: "1.0.0"
166 | path:
167 | dependency: transitive
168 | description:
169 | name: path
170 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
171 | url: "https://pub.dev"
172 | source: hosted
173 | version: "1.9.0"
174 | provider:
175 | dependency: "direct main"
176 | description:
177 | name: provider
178 | sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
179 | url: "https://pub.dev"
180 | source: hosted
181 | version: "6.1.2"
182 | sky_engine:
183 | dependency: transitive
184 | description: flutter
185 | source: sdk
186 | version: "0.0.99"
187 | source_span:
188 | dependency: transitive
189 | description:
190 | name: source_span
191 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
192 | url: "https://pub.dev"
193 | source: hosted
194 | version: "1.10.0"
195 | stack_trace:
196 | dependency: transitive
197 | description:
198 | name: stack_trace
199 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
200 | url: "https://pub.dev"
201 | source: hosted
202 | version: "1.11.1"
203 | stream_channel:
204 | dependency: transitive
205 | description:
206 | name: stream_channel
207 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
208 | url: "https://pub.dev"
209 | source: hosted
210 | version: "2.1.2"
211 | string_scanner:
212 | dependency: transitive
213 | description:
214 | name: string_scanner
215 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
216 | url: "https://pub.dev"
217 | source: hosted
218 | version: "1.2.0"
219 | term_glyph:
220 | dependency: transitive
221 | description:
222 | name: term_glyph
223 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
224 | url: "https://pub.dev"
225 | source: hosted
226 | version: "1.2.1"
227 | test_api:
228 | dependency: transitive
229 | description:
230 | name: test_api
231 | sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
232 | url: "https://pub.dev"
233 | source: hosted
234 | version: "0.7.0"
235 | tint:
236 | dependency: transitive
237 | description:
238 | name: tint
239 | sha256: "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46"
240 | url: "https://pub.dev"
241 | source: hosted
242 | version: "2.0.1"
243 | vector_math:
244 | dependency: transitive
245 | description:
246 | name: vector_math
247 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
248 | url: "https://pub.dev"
249 | source: hosted
250 | version: "2.1.4"
251 | vm_service:
252 | dependency: transitive
253 | description:
254 | name: vm_service
255 | sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
256 | url: "https://pub.dev"
257 | source: hosted
258 | version: "14.2.1"
259 | yaml:
260 | dependency: transitive
261 | description:
262 | name: yaml
263 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
264 | url: "https://pub.dev"
265 | source: hosted
266 | version: "3.1.2"
267 | sdks:
268 | dart: ">=3.3.0 <4.0.0"
269 | flutter: ">=3.18.0-18.0.pre.54"
270 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | args:
5 | dependency: transitive
6 | description:
7 | name: args
8 | sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.5.0"
12 | async:
13 | dependency: transitive
14 | description:
15 | name: async
16 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.11.0"
20 | boolean_selector:
21 | dependency: transitive
22 | description:
23 | name: boolean_selector
24 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "2.1.1"
28 | characters:
29 | dependency: transitive
30 | description:
31 | name: characters
32 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.3.0"
36 | clock:
37 | dependency: transitive
38 | description:
39 | name: clock
40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.1.1"
44 | collection:
45 | dependency: transitive
46 | description:
47 | name: collection
48 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.18.0"
52 | fake_async:
53 | dependency: transitive
54 | description:
55 | name: fake_async
56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "1.3.1"
60 | flutter:
61 | dependency: "direct main"
62 | description: flutter
63 | source: sdk
64 | version: "0.0.0"
65 | flutter_expandable_table:
66 | dependency: "direct dev"
67 | description:
68 | path: ".."
69 | relative: true
70 | source: path
71 | version: "2.1.0"
72 | flutter_lints:
73 | dependency: "direct dev"
74 | description:
75 | name: flutter_lints
76 | sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
77 | url: "https://pub.dev"
78 | source: hosted
79 | version: "4.0.0"
80 | flutter_scroll_shadow:
81 | dependency: transitive
82 | description:
83 | name: flutter_scroll_shadow
84 | sha256: c0509c642c5077654301fab1fb2260adc94c82a407c60e64162974b4366e7874
85 | url: "https://pub.dev"
86 | source: hosted
87 | version: "1.2.4"
88 | flutter_test:
89 | dependency: "direct dev"
90 | description: flutter
91 | source: sdk
92 | version: "0.0.0"
93 | import_sorter:
94 | dependency: "direct dev"
95 | description:
96 | name: import_sorter
97 | sha256: eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836
98 | url: "https://pub.dev"
99 | source: hosted
100 | version: "4.6.0"
101 | leak_tracker:
102 | dependency: transitive
103 | description:
104 | name: leak_tracker
105 | sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
106 | url: "https://pub.dev"
107 | source: hosted
108 | version: "10.0.4"
109 | leak_tracker_flutter_testing:
110 | dependency: transitive
111 | description:
112 | name: leak_tracker_flutter_testing
113 | sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
114 | url: "https://pub.dev"
115 | source: hosted
116 | version: "3.0.3"
117 | leak_tracker_testing:
118 | dependency: transitive
119 | description:
120 | name: leak_tracker_testing
121 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
122 | url: "https://pub.dev"
123 | source: hosted
124 | version: "3.0.1"
125 | linked_scroll_controller:
126 | dependency: transitive
127 | description:
128 | name: linked_scroll_controller
129 | sha256: e6020062bcf4ffc907ee7fd090fa971e65d8dfaac3c62baf601a3ced0b37986a
130 | url: "https://pub.dev"
131 | source: hosted
132 | version: "0.2.0"
133 | lints:
134 | dependency: transitive
135 | description:
136 | name: lints
137 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
138 | url: "https://pub.dev"
139 | source: hosted
140 | version: "4.0.0"
141 | matcher:
142 | dependency: transitive
143 | description:
144 | name: matcher
145 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
146 | url: "https://pub.dev"
147 | source: hosted
148 | version: "0.12.16+1"
149 | material_color_utilities:
150 | dependency: transitive
151 | description:
152 | name: material_color_utilities
153 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
154 | url: "https://pub.dev"
155 | source: hosted
156 | version: "0.8.0"
157 | meta:
158 | dependency: transitive
159 | description:
160 | name: meta
161 | sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
162 | url: "https://pub.dev"
163 | source: hosted
164 | version: "1.12.0"
165 | nested:
166 | dependency: transitive
167 | description:
168 | name: nested
169 | sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
170 | url: "https://pub.dev"
171 | source: hosted
172 | version: "1.0.0"
173 | path:
174 | dependency: transitive
175 | description:
176 | name: path
177 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
178 | url: "https://pub.dev"
179 | source: hosted
180 | version: "1.9.0"
181 | provider:
182 | dependency: transitive
183 | description:
184 | name: provider
185 | sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
186 | url: "https://pub.dev"
187 | source: hosted
188 | version: "6.1.2"
189 | sky_engine:
190 | dependency: transitive
191 | description: flutter
192 | source: sdk
193 | version: "0.0.99"
194 | source_span:
195 | dependency: transitive
196 | description:
197 | name: source_span
198 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
199 | url: "https://pub.dev"
200 | source: hosted
201 | version: "1.10.0"
202 | stack_trace:
203 | dependency: transitive
204 | description:
205 | name: stack_trace
206 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
207 | url: "https://pub.dev"
208 | source: hosted
209 | version: "1.11.1"
210 | stream_channel:
211 | dependency: transitive
212 | description:
213 | name: stream_channel
214 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
215 | url: "https://pub.dev"
216 | source: hosted
217 | version: "2.1.2"
218 | string_scanner:
219 | dependency: transitive
220 | description:
221 | name: string_scanner
222 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
223 | url: "https://pub.dev"
224 | source: hosted
225 | version: "1.2.0"
226 | term_glyph:
227 | dependency: transitive
228 | description:
229 | name: term_glyph
230 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
231 | url: "https://pub.dev"
232 | source: hosted
233 | version: "1.2.1"
234 | test_api:
235 | dependency: transitive
236 | description:
237 | name: test_api
238 | sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
239 | url: "https://pub.dev"
240 | source: hosted
241 | version: "0.7.0"
242 | tint:
243 | dependency: transitive
244 | description:
245 | name: tint
246 | sha256: "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46"
247 | url: "https://pub.dev"
248 | source: hosted
249 | version: "2.0.1"
250 | vector_math:
251 | dependency: transitive
252 | description:
253 | name: vector_math
254 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
255 | url: "https://pub.dev"
256 | source: hosted
257 | version: "2.1.4"
258 | vm_service:
259 | dependency: transitive
260 | description:
261 | name: vm_service
262 | sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
263 | url: "https://pub.dev"
264 | source: hosted
265 | version: "14.2.1"
266 | yaml:
267 | dependency: transitive
268 | description:
269 | name: yaml
270 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
271 | url: "https://pub.dev"
272 | source: hosted
273 | version: "3.1.2"
274 | sdks:
275 | dart: ">=3.3.0 <4.0.0"
276 | flutter: ">=3.18.0-18.0.pre.54"
277 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | #### flutter_expandable_table
2 | # Expandable Table
3 |
4 | [](https://github.com/rickypid/flutter_expandable_table)
5 | [](https://pub.dartlang.org/packages/flutter_expandable_table)
6 | [](https://pub.dev/packages/flutter_expandable_table/score)
7 | [](https://pub.dev/packages/flutter_expandable_table/score)
8 |
9 | [](https://github.com/rickypid/flutter_expandable_table/issues)
10 | 
11 |
12 | `ExpandableTable` is a widget for Flutter that create a Table with header and first column fixed. You can create a nested Rows/Columns grouped in expandable Row/Column
13 |
14 | |  |
15 | | :------------: |
16 | | **ExpandableTable** |
17 |
18 | ## Features
19 |
20 | * Header and first column fixed
21 | * Supports vertical and horizontal scroll
22 | * Customizable animation Duration and Curve
23 | * Specific height definition for each single row
24 | * Specific width definition for each single column
25 | * Access to cell address when building cell content
26 | * Access to the parent rows and columns of the cell while building the contents of a cell
27 |
28 |
29 |
30 | ## Usage
31 | Make sure to check out the [examples on GitHub](https://github.com/rickypid/flutter_expandable_table/tree/master/example).
32 |
33 | ### Installation
34 |
35 | Add the following line to `pubspec.yaml`:
36 |
37 | ```yaml
38 | dependencies:
39 | flutter_expandable_table:
40 | ```
41 |
42 | ### Basic setup
43 |
44 | *Complete example [available here](https://github.com/rickypid/flutter_expandable_table/blob/master/example/lib/main.dart).*
45 |
46 | ```dart
47 | return ExpandableTable(
48 | firstHeaderCell: ExpandableTableCell(
49 | child: Text('Simple\nTable'),
50 | ),
51 | headers: headers,
52 | rows: rows,
53 | );
54 | ```
55 |
56 | ### Use with the controller
57 |
58 | You can create an external controller to be able to dynamically manage the table, for example to add or remove rows within it.
59 |
60 | Here is an example:
61 |
62 | ```dart
63 | //... Inside Widget State
64 | late ExpandableTableController controller;
65 | //....
66 | @override
67 | void initState() {
68 | controller = ExpandableTableController(
69 | firstHeaderCell: ExpandableTableCell(child: Container()),
70 | headers: [],
71 | rows: [],
72 | headerHeight: 263,
73 | defaultsColumnWidth: 200,
74 | firstColumnWidth: 300,
75 | scrollShadowColor: AppColors.black,
76 | );
77 | super.initState();
78 | }
79 | void _onEvent(){
80 | controller.rows.add(...your code...);
81 | }
82 | @override
83 | Widget build(BuildContext context) {
84 | return ExpandableTable(
85 | controller: controller,
86 | );
87 | }
88 | //....
89 | ```
90 |
91 | ### ExpandableTable Properties
92 | * `firstHeaderCell`: Is the top left cell, i.e. the first header cell.
93 | * `headers`: contains the list of all column headers, each one of these can contain a list of further headers, this allows you to create nested and expandable columns.
94 | * `rows`: contains the list of all the rows of the table, each of these can contain a list of further rows, this allows you to create nested and expandable rows.
95 | * `headerHeight`: is the height of each column header, i.e. the first row.
96 | * `firstColumnWidth`: determines first Column width size.
97 | * `defaultsColumnWidth`: defines the default width of all columns, it is possible to redefine it for each individual column.
98 | * `defaultsRowHeight`: defines the default height of all rows, it is possible to redefine it for every single row.
99 | * `duration`: determines duration rendered animation of Rows/Columns expansion.
100 | * `curve`: determines rendered curve animation of Rows/Columns expansion.
101 | * `scrollShadowDuration`: determines duration rendered animation of shadows.
102 | * `scrollShadowFadeInCurve`: determines rendered curve animation of shadows appearance.
103 | * `scrollShadowFadeOutCurve`: determines rendered curve animation of shadows disappearance.
104 | * `scrollShadowColor`: determines rendered color of shadows.
105 | * `scrollShadowSize`: determines size of shadows.
106 | * `visibleScrollbar`: determines visibility of horizontal and vertical scrollbars.
107 | * `trackVisibilityScrollbar`: indicates that the scrollbar track should be visible.
108 | * `thumbVisibilityScrollbar`: indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
109 | * `expanded`: indicates that the table expands, so it fills the available space along the horizontal and vertical axes.
110 |
111 |
112 |
113 | ## 📚 My open source projects
114 |
115 | ### Flutter
116 |
117 | | Package | Verison | Score | Likes | Test | Coverage |
118 | |--|--|--|--|--|--|
119 | | [](https://github.com/rickypid/flutter_expandable_table) | [](https://pub.dartlang.org/packages/flutter_expandable_table) | [](https://pub.dev/packages/flutter_expandable_table/score) | [](https://pub.dev/packages/flutter_expandable_table/score) | | |
120 | | [](https://github.com/rickypid/widget_tree_depth_counter) | [](https://pub.dartlang.org/packages/widget_tree_depth_counter) | [](https://pub.dev/packages/widget_tree_depth_counter/score) | [](https://pub.dev/packages/widget_tree_depth_counter/score) | | |
121 | | [](https://github.com/rickypid/flutter_scroll_shadow) | [](https://pub.dartlang.org/packages/flutter_scroll_shadow) | [](https://pub.dev/packages/flutter_scroll_shadow/score) | [](https://pub.dev/packages/flutter_scroll_shadow/score) | | |
122 | | [](https://github.com/rickypid/flutter_bargraph) | [](https://pub.dartlang.org/packages/flutter_bargraph) | [](https://pub.dev/packages/flutter_bargraph/score) | [](https://pub.dev/packages/flutter_bargraph/score) | | |
123 |
124 |
125 | ### Dart
126 |
127 | | Package | Verison | Score | Likes | Test | Coverage |
128 | |--|--|--|--|--|--|
129 | | [](https://github.com/rickypid/cowsay) | [](https://pub.dartlang.org/packages/cowsay) | [](https://pub.dev/packages/cowsay/score) | [](https://pub.dev/packages/cowsay/score) | [](https://github.com/rickypid/cowsay/actions/workflows/test.yml) | [](https://codecov.io/gh/rickypid/cowsay) |
130 | | [](https://github.com/rickypid/telegram_link) | [](https://pub.dartlang.org/packages/telegram_link) | [](https://pub.dev/packages/telegram_link/score) | [](https://pub.dev/packages/telegram_link/score) | [](https://github.com/rickypid/telegram_link/actions/workflows/test.yml) | [](https://codecov.io/gh/rickypid/telegram_link) |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #### flutter_expandable_table
2 | # Expandable Table
3 |
4 | [](https://github.com/rickypid/flutter_expandable_table)
5 | [](https://pub.dartlang.org/packages/flutter_expandable_table)
6 | [](https://pub.dev/packages/flutter_expandable_table/score)
7 | [](https://pub.dev/packages/flutter_expandable_table/score)
8 |
9 | [](https://github.com/rickypid/flutter_expandable_table/issues)
10 | 
11 |
12 | `ExpandableTable` is a widget for Flutter that create a Table with header and first column fixed. You can create a nested Rows/Columns grouped in expandable Row/Column
13 |
14 | |  |
15 | | :------------: |
16 | | **ExpandableTable** |
17 |
18 | ## Features
19 |
20 | * Header and first column fixed
21 | * Supports vertical and horizontal scroll
22 | * Customizable animation Duration and Curve
23 | * Specific height definition for each single row
24 | * Specific width definition for each single column
25 | * Access to cell address when building cell content
26 | * Access to the parent rows and columns of the cell while building the contents of a cell
27 |
28 |
29 |
30 | ## Usage
31 | Make sure to check out the [examples on GitHub](https://github.com/rickypid/flutter_expandable_table/tree/master/example).
32 |
33 | ### Installation
34 |
35 | Add the following line to `pubspec.yaml`:
36 |
37 | ```yaml
38 | dependencies:
39 | flutter_expandable_table:
40 | ```
41 |
42 | ### Basic setup
43 |
44 | *Complete example [available here](https://github.com/rickypid/flutter_expandable_table/blob/master/example/lib/main.dart).*
45 |
46 | ```dart
47 | return ExpandableTable(
48 | firstHeaderCell: ExpandableTableCell(
49 | child: Text('Simple\nTable'),
50 | ),
51 | headers: headers,
52 | rows: rows,
53 | );
54 | ```
55 |
56 | ### Use with the controller
57 |
58 | You can create an external controller to be able to dynamically manage the table, for example to add or remove rows within it.
59 |
60 | Here is an example:
61 |
62 | ```dart
63 | //... Inside Widget State
64 | late ExpandableTableController controller;
65 | //....
66 | @override
67 | void initState() {
68 | controller = ExpandableTableController(
69 | firstHeaderCell: ExpandableTableCell(child: Container()),
70 | headers: [],
71 | rows: [],
72 | headerHeight: 263,
73 | defaultsColumnWidth: 200,
74 | firstColumnWidth: 300,
75 | scrollShadowColor: AppColors.black,
76 | );
77 | super.initState();
78 | }
79 | void _onEvent(){
80 | controller.rows.add(...your code...);
81 | }
82 | @override
83 | Widget build(BuildContext context) {
84 | return ExpandableTable(
85 | controller: controller,
86 | );
87 | }
88 | //....
89 | ```
90 |
91 | ### ExpandableTable Properties
92 | * `firstHeaderCell`: Is the top left cell, i.e. the first header cell.
93 | * `headers`: contains the list of all column headers, each one of these can contain a list of further headers, this allows you to create nested and expandable columns.
94 | * `rows`: contains the list of all the rows of the table, each of these can contain a list of further rows, this allows you to create nested and expandable rows.
95 | * `headerHeight`: is the height of each column header, i.e. the first row.
96 | * `firstColumnWidth`: determines first Column width size.
97 | * `defaultsColumnWidth`: defines the default width of all columns, it is possible to redefine it for each individual column.
98 | * `defaultsRowHeight`: defines the default height of all rows, it is possible to redefine it for every single row.
99 | * `duration`: determines duration rendered animation of Rows/Columns expansion.
100 | * `curve`: determines rendered curve animation of Rows/Columns expansion.
101 | * `scrollShadowDuration`: determines duration rendered animation of shadows.
102 | * `scrollShadowFadeInCurve`: determines rendered curve animation of shadows appearance.
103 | * `scrollShadowFadeOutCurve`: determines rendered curve animation of shadows disappearance.
104 | * `scrollShadowColor`: determines rendered color of shadows.
105 | * `scrollShadowSize`: determines size of shadows.
106 | * `visibleScrollbar`: determines visibility of horizontal and vertical scrollbars.
107 | * `trackVisibilityScrollbar`: indicates that the scrollbar track should be visible.
108 | * `thumbVisibilityScrollbar`: indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
109 | * `expanded`: indicates that the table expands, so it fills the available space along the horizontal and vertical axes.
110 |
111 |
112 |
113 | ## 📚 My open source projects
114 |
115 | ### Flutter
116 |
117 | | Package | Verison | Score | Likes | Test | Coverage |
118 | |--|--|--|--|--|--|
119 | | [](https://github.com/rickypid/flutter_expandable_table) | [](https://pub.dartlang.org/packages/flutter_expandable_table) | [](https://pub.dev/packages/flutter_expandable_table/score) | [](https://pub.dev/packages/flutter_expandable_table/score) | | |
120 | | [](https://github.com/rickypid/widget_tree_depth_counter) | [](https://pub.dartlang.org/packages/widget_tree_depth_counter) | [](https://pub.dev/packages/widget_tree_depth_counter/score) | [](https://pub.dev/packages/widget_tree_depth_counter/score) | | |
121 | | [](https://github.com/rickypid/flutter_scroll_shadow) | [](https://pub.dartlang.org/packages/flutter_scroll_shadow) | [](https://pub.dev/packages/flutter_scroll_shadow/score) | [](https://pub.dev/packages/flutter_scroll_shadow/score) | | |
122 | | [](https://github.com/rickypid/flutter_bargraph) | [](https://pub.dartlang.org/packages/flutter_bargraph) | [](https://pub.dev/packages/flutter_bargraph/score) | [](https://pub.dev/packages/flutter_bargraph/score) | | |
123 |
124 |
125 | ### Dart
126 |
127 | | Package | Verison | Score | Likes | Test | Coverage |
128 | |--|--|--|--|--|--|
129 | | [](https://github.com/rickypid/cowsay) | [](https://pub.dartlang.org/packages/cowsay) | [](https://pub.dev/packages/cowsay/score) | [](https://pub.dev/packages/cowsay/score) | [](https://github.com/rickypid/cowsay/actions/workflows/test.yml) | [](https://codecov.io/gh/rickypid/cowsay) |
130 | | [](https://github.com/rickypid/telegram_link) | [](https://pub.dartlang.org/packages/telegram_link) | [](https://pub.dev/packages/telegram_link/score) | [](https://pub.dev/packages/telegram_link/score) | [](https://github.com/rickypid/telegram_link/actions/workflows/test.yml) | [](https://codecov.io/gh/rickypid/telegram_link) |
--------------------------------------------------------------------------------
/lib/src/class/controller.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
6 |
7 | /// [ExpandableTableController] class.
8 | class ExpandableTableController extends ChangeNotifier {
9 | late ExpandableTableCell _firstHeaderCell;
10 |
11 | /// [firstHeaderCell] is the top left cell, i.e. the first header cell.
12 | /// `required`
13 | ExpandableTableCell get firstHeaderCell => _firstHeaderCell;
14 |
15 | set firstHeaderCell(ExpandableTableCell value) {
16 | _firstHeaderCell = value;
17 | notifyListeners();
18 | }
19 |
20 | late List _headers;
21 |
22 | /// [headers] contains the list of all column headers,
23 | /// each one of these can contain a list of further headers,
24 | /// this allows you to create nested and expandable columns.
25 | /// Not to be used if the [controller] is used.
26 | /// `required`
27 | List get headers => _headers;
28 |
29 | set headers(List value) {
30 | _removeHeadersListener();
31 | _headers = value;
32 | _addHeadersListener();
33 | notifyListeners();
34 | }
35 |
36 | late List _rows;
37 |
38 | /// [rows] contains the list of all the rows of the table,
39 | /// each of these can contain a list of further rows,
40 | /// this allows you to create nested and expandable rows.
41 | /// Not to be used if the [controller] is used.
42 | /// `required`
43 | List get rows => _rows;
44 |
45 | late double _headerHeight;
46 |
47 | /// [headerHeight] is the height of each column header, i.e. the first row.
48 | /// `Default: 188`
49 | double get headerHeight => _headerHeight;
50 |
51 | set headerHeight(double value) {
52 | _headerHeight = value;
53 | notifyListeners();
54 | }
55 |
56 | late double _firstColumnWidth;
57 |
58 | /// [firstColumnWidth] determines first Column width size.
59 | ///
60 | /// Default: [200]
61 | double get firstColumnWidth => _firstColumnWidth;
62 |
63 | set firstColumnWidth(double value) {
64 | _firstColumnWidth = value;
65 | notifyListeners();
66 | }
67 |
68 | late double _defaultsColumnWidth;
69 |
70 | /// [defaultsColumnWidth] defines the default width of all columns,
71 | /// it is possible to redefine it for each individual column.
72 | /// Default: [120]
73 | double get defaultsColumnWidth => _defaultsColumnWidth;
74 |
75 | set defaultsColumnWidth(double value) {
76 | _defaultsColumnWidth = value;
77 | notifyListeners();
78 | }
79 |
80 | late double _defaultsRowHeight;
81 |
82 | /// [defaultsRowHeight] defines the default height of all rows,
83 | /// it is possible to redefine it for every single row.
84 | /// Default: [50]
85 | double get defaultsRowHeight => _defaultsRowHeight;
86 |
87 | set defaultsRowHeight(double value) {
88 | _defaultsRowHeight = value;
89 | notifyListeners();
90 | }
91 |
92 | bool _visibleScrollbar = false;
93 |
94 | /// [visibleScrollbar] determines visibility of horizontal and vertical scrollbars.
95 | ///
96 | /// Default: [false]
97 | bool get visibleScrollbar => _visibleScrollbar;
98 |
99 | set visibleScrollbar(bool value) {
100 | _visibleScrollbar = value;
101 | notifyListeners();
102 | }
103 |
104 | bool? _trackVisibilityScrollbar;
105 |
106 | /// [trackVisibilityScrollbar] indicates that the scrollbar track should be visible.
107 | ///
108 | /// 'optional'
109 | bool? get trackVisibilityScrollbar => _trackVisibilityScrollbar;
110 |
111 | set trackVisibilityScrollbar(bool? value) {
112 | _trackVisibilityScrollbar = value;
113 | notifyListeners();
114 | }
115 |
116 | bool? _thumbVisibilityScrollbar;
117 |
118 | /// [thumbVisibilityScrollbar] indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
119 | ///
120 | /// 'optional'
121 | bool? get thumbVisibilityScrollbar => _thumbVisibilityScrollbar;
122 |
123 | set thumbVisibilityScrollbar(bool? value) {
124 | _thumbVisibilityScrollbar = value;
125 | notifyListeners();
126 | }
127 |
128 | bool _expanded = true;
129 |
130 | /// [expanded] indicates that the table expands, so it fills the available space along the horizontal and vertical axes.
131 | ///
132 | /// Default: [true]
133 | bool get expanded => _expanded;
134 |
135 | set expanded(bool value) {
136 | _expanded = value;
137 | notifyListeners();
138 | }
139 |
140 | /// [duration] determines duration rendered animation of Rows/Columns expansion.
141 | ///
142 | /// Default: [500ms]
143 | final Duration duration;
144 |
145 | /// [curve] determines rendered curve animation of Rows/Columns expansion.
146 | ///
147 | /// Default: [Curves.fastOutSlowIn]
148 | final Curve curve;
149 |
150 | /// [scrollShadowDuration] determines duration rendered animation of shadows.
151 | ///
152 | /// Default: [500ms]
153 | final Duration scrollShadowDuration;
154 |
155 | /// [scrollShadowFadeInCurve] determines rendered curve animation of shadows appearance.
156 | ///
157 | /// Default: [Curves.easeIn]
158 | final Curve scrollShadowFadeInCurve;
159 |
160 | /// [scrollShadowFadeOutCurve] determines rendered curve animation of shadows disappearance.
161 | ///
162 | /// Default: [Curves.easeOut]
163 | final Curve scrollShadowFadeOutCurve;
164 |
165 | /// [scrollShadowColor] determines rendered color of shadows.
166 | ///
167 | /// Default: [Colors.transparent]
168 | final Color scrollShadowColor;
169 |
170 | /// [scrollShadowSize] determines size of shadows.
171 | ///
172 | /// Default: [10]
173 | final double scrollShadowSize;
174 |
175 | set rows(List value) {
176 | _removeRowsListener();
177 | _rows = value;
178 | _addRowsListener();
179 | notifyListeners();
180 | }
181 |
182 | /// [ExpandableTableController] class constructor.
183 | ExpandableTableController({
184 | required ExpandableTableCell firstHeaderCell,
185 | required List headers,
186 | required List rows,
187 | bool visibleScrollbar = false,
188 | bool? trackVisibilityScrollbar,
189 | bool? thumbVisibilityScrollbar,
190 | bool expanded = true,
191 | this.duration = const Duration(milliseconds: 500),
192 | this.curve = Curves.fastOutSlowIn,
193 | this.scrollShadowDuration = const Duration(milliseconds: 500),
194 | this.scrollShadowFadeInCurve = Curves.easeIn,
195 | this.scrollShadowFadeOutCurve = Curves.easeOut,
196 | this.scrollShadowColor = Colors.transparent,
197 | this.scrollShadowSize = 10,
198 | double headerHeight = 188,
199 | double firstColumnWidth = 200,
200 | double defaultsColumnWidth = 120,
201 | double defaultsRowHeight = 50,
202 | }) {
203 | _firstHeaderCell = firstHeaderCell;
204 | _headerHeight = headerHeight;
205 | _firstColumnWidth = firstColumnWidth;
206 | _defaultsColumnWidth = defaultsColumnWidth;
207 | _defaultsRowHeight = defaultsRowHeight;
208 | _headers = headers;
209 | _rows = rows;
210 | _visibleScrollbar = visibleScrollbar;
211 | _trackVisibilityScrollbar = trackVisibilityScrollbar;
212 | _thumbVisibilityScrollbar = thumbVisibilityScrollbar;
213 | _expanded = expanded;
214 | _addHeadersListener();
215 | _addRowsListener();
216 | }
217 |
218 | void _addHeadersListener() {
219 | for (var i = 0; i < _headers.length; i++) {
220 | _headers[i].addListener(_listener);
221 | _headers[i].index = i;
222 | }
223 | }
224 |
225 | void _removeHeadersListener() {
226 | for (var header in _headers) {
227 | header.removeListener(_listener);
228 | }
229 | }
230 |
231 | void _addRowsListener() {
232 | for (var i = 0; i < _rows.length; i++) {
233 | _rows[i].addListener(_listener);
234 | _rows[i].index = i;
235 | }
236 | }
237 |
238 | void _removeRowsListener() {
239 | for (var row in _rows) {
240 | row.removeListener(_listener);
241 | }
242 | }
243 |
244 | @override
245 | void dispose() {
246 | _removeHeadersListener();
247 | _removeRowsListener();
248 | super.dispose();
249 | }
250 |
251 | void _listener() => notifyListeners();
252 |
253 | /// [allHeaders] returns all table headers, visible and not, including nested ones.
254 | List get allHeaders => _getAllHeaders(headers);
255 |
256 | /// [visibleHeaders] returns all visible table headers, including nested ones.
257 | List get visibleHeaders =>
258 | allHeaders.where((element) => element.visible).toList();
259 |
260 | /// [visibleHeadersWidth] returns the overall width of all visible table headers, including nested ones
261 | double get visibleHeadersWidth => visibleHeaders
262 | .map((e) => e.width ?? defaultsColumnWidth)
263 | .fold(0, (a, b) => a + b);
264 |
265 | List _getAllHeaders(
266 | List headers) {
267 | final List cells = [];
268 | for (var header in headers) {
269 | cells.add(header);
270 | if (header.children != null) {
271 | cells.addAll(_getAllHeaders(header.children!));
272 | }
273 | }
274 | return cells;
275 | }
276 |
277 | /// [allRows] returns all table rows, visible and not, including nested ones.
278 | List get allRows => _getAllRows(rows);
279 |
280 | /// [visibleRows] returns all visible table rows, including nested ones.
281 | List get visibleRows =>
282 | allRows.where((element) => element.visible).toList();
283 |
284 | /// [visibleHeadersWidth] returns the overall width of all visible table rows, including nested ones
285 | double get visibleRowsHeight => visibleRows
286 | .map((e) => e.height ?? defaultsRowHeight)
287 | .fold(0, (a, b) => a + b);
288 |
289 | List _getAllRows(List rows) {
290 | final List rowsTmp = [];
291 | for (var row in rows) {
292 | rowsTmp.add(row);
293 | if (row.children != null) {
294 | rowsTmp.addAll(_getAllRows(row.children!));
295 | }
296 | }
297 | return rowsTmp;
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/lib/src/widget_internal/table.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_scroll_shadow/flutter_scroll_shadow.dart';
6 | import 'package:linked_scroll_controller/linked_scroll_controller.dart';
7 | import 'package:provider/provider.dart';
8 |
9 | // Project imports:
10 | import 'package:flutter_expandable_table/flutter_expandable_table.dart';
11 | import 'package:flutter_expandable_table/src/widget_internal/cell.dart';
12 |
13 | /// [InternalTable] it is the widget that builds the table.
14 | class InternalTable extends StatefulWidget {
15 | /// [InternalTable] constructor.
16 | const InternalTable({
17 | super.key,
18 | });
19 |
20 | @override
21 | InternalTableState createState() => InternalTableState();
22 | }
23 |
24 | /// [InternalTable] state.
25 | class InternalTableState extends State {
26 | late LinkedScrollControllerGroup _horizontalLinkedControllers;
27 | late ScrollController _headController;
28 | late ScrollController _horizontalBodyController;
29 | late LinkedScrollControllerGroup _verticalLinkedControllers;
30 | late ScrollController _firstColumnController;
31 | late ScrollController _restColumnsController;
32 |
33 | @override
34 | void initState() {
35 | super.initState();
36 | _horizontalLinkedControllers = LinkedScrollControllerGroup();
37 | _headController = _horizontalLinkedControllers.addAndGet();
38 | _horizontalBodyController = _horizontalLinkedControllers.addAndGet();
39 | _verticalLinkedControllers = LinkedScrollControllerGroup();
40 | _firstColumnController = _verticalLinkedControllers.addAndGet();
41 | _restColumnsController = _verticalLinkedControllers.addAndGet();
42 | }
43 |
44 | @override
45 | void dispose() {
46 | _headController.dispose();
47 | _horizontalBodyController.dispose();
48 | _restColumnsController.dispose();
49 | _firstColumnController.dispose();
50 | super.dispose();
51 | }
52 |
53 | List _buildHeaderCells(ExpandableTableController data) =>
54 | data.allHeaders
55 | .map(
56 | (e) => ExpandableTableCellWidget(
57 | height: data.headerHeight,
58 | width: e.width ?? data.defaultsColumnWidth,
59 | header: e,
60 | onTap: () {
61 | if (!e.disableDefaultOnTapExpansion) {
62 | e.toggleExpand();
63 | }
64 | },
65 | builder: e.cell.build,
66 | ),
67 | )
68 | .toList();
69 |
70 | Widget _buildRowCells(
71 | ExpandableTableController data, ExpandableTableRow row) {
72 | if (row.cells != null) {
73 | return Row(
74 | children: row.cells!
75 | .map(
76 | (cell) => ExpandableTableCellWidget(
77 | header: data.allHeaders[row.cells!.indexOf(cell)],
78 | row: row,
79 | height: row.height ?? data.defaultsRowHeight,
80 | width: data.allHeaders[row.cells!.indexOf(cell)].width ??
81 | data.defaultsColumnWidth,
82 | builder: cell.build,
83 | ),
84 | )
85 | .toList(),
86 | );
87 | } else {
88 | return ExpandableTableCellWidget(
89 | height: row.height ?? data.defaultsRowHeight,
90 | width: double.infinity,
91 | row: row,
92 | builder: (context, details) => row.legend!,
93 | );
94 | }
95 | }
96 |
97 | Widget _buildBody(ExpandableTableController data) => Row(
98 | children: [
99 | Builder(
100 | builder: (context) {
101 | final Widget child = ListView(
102 | controller: _firstColumnController,
103 | physics: const ClampingScrollPhysics(),
104 | children: data.allRows
105 | .map(
106 | (e) => ChangeNotifierProvider.value(
107 | value: e,
108 | builder: (context, child) => ExpandableTableCellWidget(
109 | row: context.watch(),
110 | height: context.watch().height ??
111 | data.defaultsRowHeight,
112 | width: data.firstColumnWidth,
113 | builder: context
114 | .watch()
115 | .firstCell
116 | .build,
117 | onTap: () {
118 | if (!e.disableDefaultOnTapExpansion) {
119 | e.toggleExpand();
120 | }
121 | },
122 | ),
123 | ),
124 | )
125 | .toList(),
126 | );
127 | return SizedBox(
128 | width: data.firstColumnWidth,
129 | child: ScrollConfiguration(
130 | behavior: ScrollConfiguration.of(context)
131 | .copyWith(scrollbars: false),
132 | child: ScrollShadow(
133 | size: data.scrollShadowSize,
134 | color: data.scrollShadowColor,
135 | fadeInCurve: data.scrollShadowFadeInCurve,
136 | fadeOutCurve: data.scrollShadowFadeOutCurve,
137 | duration: data.scrollShadowDuration,
138 | child: data.visibleScrollbar
139 | ? Scrollbar(
140 | controller: _firstColumnController,
141 | thumbVisibility: data.thumbVisibilityScrollbar,
142 | trackVisibility: data.trackVisibilityScrollbar,
143 | scrollbarOrientation: ScrollbarOrientation.left,
144 | child: child,
145 | )
146 | : child,
147 | ),
148 | ),
149 | );
150 | },
151 | ),
152 | Builder(
153 | builder: (context) {
154 | final Widget child = SingleChildScrollView(
155 | controller: _horizontalBodyController,
156 | scrollDirection: Axis.horizontal,
157 | physics: const ClampingScrollPhysics(),
158 | child: AnimatedContainer(
159 | width: data.visibleHeadersWidth,
160 | duration: data.duration,
161 | curve: data.curve,
162 | child: ScrollShadow(
163 | size: data.scrollShadowSize,
164 | color: data.scrollShadowColor,
165 | fadeInCurve: data.scrollShadowFadeInCurve,
166 | fadeOutCurve: data.scrollShadowFadeOutCurve,
167 | duration: data.scrollShadowDuration,
168 | child: ListView(
169 | controller: _restColumnsController,
170 | physics: const ClampingScrollPhysics(),
171 | children: data.allRows
172 | .map(
173 | (e) => _buildRowCells(data, e),
174 | )
175 | .toList(),
176 | ),
177 | ),
178 | ),
179 | );
180 |
181 | return Expanded(
182 | child: ScrollConfiguration(
183 | behavior: ScrollConfiguration.of(context)
184 | .copyWith(scrollbars: false),
185 | child: ScrollShadow(
186 | size: data.scrollShadowSize,
187 | color: data.scrollShadowColor,
188 | fadeInCurve: data.scrollShadowFadeInCurve,
189 | fadeOutCurve: data.scrollShadowFadeOutCurve,
190 | duration: data.scrollShadowDuration,
191 | child: data.visibleScrollbar
192 | ? Scrollbar(
193 | controller: _horizontalBodyController,
194 | thumbVisibility: data.thumbVisibilityScrollbar,
195 | trackVisibility: data.trackVisibilityScrollbar,
196 | child: child,
197 | )
198 | : child,
199 | ),
200 | ),
201 | );
202 | },
203 | ),
204 | ],
205 | );
206 |
207 | double _computeTableWidth({required ExpandableTableController data}) =>
208 | data.firstColumnWidth +
209 | (data.headers
210 | .map((e) =>
211 | (e.width ?? data.defaultsColumnWidth) +
212 | _computeChildrenWidth(
213 | expandableTableHeader: e,
214 | defaultsColumnWidth: data.defaultsColumnWidth))
215 | .reduce((value, element) => value + element));
216 |
217 | double _computeTableHeight({required ExpandableTableController data}) =>
218 | data.headerHeight +
219 | (data.rows
220 | .map((e) =>
221 | (e.height ?? data.defaultsRowHeight) +
222 | _computeChildrenHeight(
223 | expandableTableRow: e,
224 | defaultsRowHeight: data.defaultsRowHeight))
225 | .reduce((value, element) => value + element));
226 |
227 | double _computeChildrenHeight({
228 | required ExpandableTableRow expandableTableRow,
229 | required double defaultsRowHeight,
230 | }) =>
231 | expandableTableRow.childrenExpanded
232 | ? expandableTableRow.children!
233 | .map((e) =>
234 | (e.height ?? defaultsRowHeight) +
235 | _computeChildrenHeight(
236 | expandableTableRow: e,
237 | defaultsRowHeight: defaultsRowHeight))
238 | .reduce((value, element) => value + element)
239 | : 0;
240 |
241 | double _computeChildrenWidth({
242 | required ExpandableTableHeader expandableTableHeader,
243 | required double defaultsColumnWidth,
244 | }) =>
245 | expandableTableHeader.childrenExpanded
246 | ? expandableTableHeader.children!
247 | .map((e) =>
248 | (e.width ?? defaultsColumnWidth) +
249 | _computeChildrenWidth(
250 | expandableTableHeader: e,
251 | defaultsColumnWidth: defaultsColumnWidth))
252 | .reduce((value, element) => value + element)
253 | : 0;
254 |
255 | @override
256 | Widget build(BuildContext context) {
257 | final ExpandableTableController data =
258 | context.watch();
259 | return SizedBox(
260 | width: data.expanded ? null : _computeTableWidth(data: data),
261 | height: data.expanded ? null : _computeTableHeight(data: data),
262 | child: Column(
263 | children: [
264 | SizedBox(
265 | height: data.headerHeight,
266 | child: Row(
267 | children: [
268 | ExpandableTableCellWidget(
269 | height: data.headerHeight,
270 | width: data.firstColumnWidth,
271 | builder: data.firstHeaderCell.build,
272 | ),
273 | Expanded(
274 | child: ScrollShadow(
275 | size: data.scrollShadowSize,
276 | color: data.scrollShadowColor,
277 | fadeInCurve: data.scrollShadowFadeInCurve,
278 | fadeOutCurve: data.scrollShadowFadeOutCurve,
279 | duration: data.scrollShadowDuration,
280 | child: ListView(
281 | controller: _headController,
282 | physics: const ClampingScrollPhysics(),
283 | scrollDirection: Axis.horizontal,
284 | children: _buildHeaderCells(data),
285 | ),
286 | ),
287 | ),
288 | ],
289 | ),
290 | ),
291 | Expanded(
292 | child: _buildBody(data),
293 | ),
294 | ],
295 | ),
296 | );
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1020;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | );
177 | inputPaths = (
178 | );
179 | name = "Thin Binary";
180 | outputPaths = (
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | shellPath = /bin/sh;
184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
185 | };
186 | 9740EEB61CF901F6004384FC /* Run Script */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | inputPaths = (
192 | );
193 | name = "Run Script";
194 | outputPaths = (
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | shellPath = /bin/sh;
198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
199 | };
200 | /* End PBXShellScriptBuildPhase section */
201 |
202 | /* Begin PBXSourcesBuildPhase section */
203 | 97C146EA1CF9000F007C117D /* Sources */ = {
204 | isa = PBXSourcesBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | };
212 | /* End PBXSourcesBuildPhase section */
213 |
214 | /* Begin PBXVariantGroup section */
215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
216 | isa = PBXVariantGroup;
217 | children = (
218 | 97C146FB1CF9000F007C117D /* Base */,
219 | );
220 | name = Main.storyboard;
221 | sourceTree = "";
222 | };
223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
224 | isa = PBXVariantGroup;
225 | children = (
226 | 97C147001CF9000F007C117D /* Base */,
227 | );
228 | name = LaunchScreen.storyboard;
229 | sourceTree = "";
230 | };
231 | /* End PBXVariantGroup section */
232 |
233 | /* Begin XCBuildConfiguration section */
234 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_ANALYZER_NONNULL = YES;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
244 | CLANG_WARN_BOOL_CONVERSION = YES;
245 | CLANG_WARN_COMMA = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
249 | CLANG_WARN_EMPTY_BODY = YES;
250 | CLANG_WARN_ENUM_CONVERSION = YES;
251 | CLANG_WARN_INFINITE_RECURSION = YES;
252 | CLANG_WARN_INT_CONVERSION = YES;
253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
258 | CLANG_WARN_STRICT_PROTOTYPES = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNREACHABLE_CODE = YES;
261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu99;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | SDKROOT = iphoneos;
278 | SUPPORTED_PLATFORMS = iphoneos;
279 | TARGETED_DEVICE_FAMILY = "1,2";
280 | VALIDATE_PRODUCT = YES;
281 | };
282 | name = Profile;
283 | };
284 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
285 | isa = XCBuildConfiguration;
286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | CLANG_ENABLE_MODULES = YES;
290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
291 | ENABLE_BITCODE = NO;
292 | INFOPLIST_FILE = Runner/Info.plist;
293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
294 | PRODUCT_BUNDLE_IDENTIFIER = net.rcprogrammer.flutterBargraphExample;
295 | PRODUCT_NAME = "$(TARGET_NAME)";
296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
297 | SWIFT_VERSION = 5.0;
298 | VERSIONING_SYSTEM = "apple-generic";
299 | };
300 | name = Profile;
301 | };
302 | 97C147031CF9000F007C117D /* Debug */ = {
303 | isa = XCBuildConfiguration;
304 | buildSettings = {
305 | ALWAYS_SEARCH_USER_PATHS = NO;
306 | CLANG_ANALYZER_NONNULL = YES;
307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
308 | CLANG_CXX_LIBRARY = "libc++";
309 | CLANG_ENABLE_MODULES = YES;
310 | CLANG_ENABLE_OBJC_ARC = YES;
311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
312 | CLANG_WARN_BOOL_CONVERSION = YES;
313 | CLANG_WARN_COMMA = YES;
314 | CLANG_WARN_CONSTANT_CONVERSION = YES;
315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
317 | CLANG_WARN_EMPTY_BODY = YES;
318 | CLANG_WARN_ENUM_CONVERSION = YES;
319 | CLANG_WARN_INFINITE_RECURSION = YES;
320 | CLANG_WARN_INT_CONVERSION = YES;
321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
326 | CLANG_WARN_STRICT_PROTOTYPES = YES;
327 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
328 | CLANG_WARN_UNREACHABLE_CODE = YES;
329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
331 | COPY_PHASE_STRIP = NO;
332 | DEBUG_INFORMATION_FORMAT = dwarf;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | ENABLE_TESTABILITY = YES;
335 | GCC_C_LANGUAGE_STANDARD = gnu99;
336 | GCC_DYNAMIC_NO_PIC = NO;
337 | GCC_NO_COMMON_BLOCKS = YES;
338 | GCC_OPTIMIZATION_LEVEL = 0;
339 | GCC_PREPROCESSOR_DEFINITIONS = (
340 | "DEBUG=1",
341 | "$(inherited)",
342 | );
343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
345 | GCC_WARN_UNDECLARED_SELECTOR = YES;
346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
347 | GCC_WARN_UNUSED_FUNCTION = YES;
348 | GCC_WARN_UNUSED_VARIABLE = YES;
349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
350 | MTL_ENABLE_DEBUG_INFO = YES;
351 | ONLY_ACTIVE_ARCH = YES;
352 | SDKROOT = iphoneos;
353 | TARGETED_DEVICE_FAMILY = "1,2";
354 | };
355 | name = Debug;
356 | };
357 | 97C147041CF9000F007C117D /* Release */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | ALWAYS_SEARCH_USER_PATHS = NO;
361 | CLANG_ANALYZER_NONNULL = YES;
362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
363 | CLANG_CXX_LIBRARY = "libc++";
364 | CLANG_ENABLE_MODULES = YES;
365 | CLANG_ENABLE_OBJC_ARC = YES;
366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
367 | CLANG_WARN_BOOL_CONVERSION = YES;
368 | CLANG_WARN_COMMA = YES;
369 | CLANG_WARN_CONSTANT_CONVERSION = YES;
370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
372 | CLANG_WARN_EMPTY_BODY = YES;
373 | CLANG_WARN_ENUM_CONVERSION = YES;
374 | CLANG_WARN_INFINITE_RECURSION = YES;
375 | CLANG_WARN_INT_CONVERSION = YES;
376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
381 | CLANG_WARN_STRICT_PROTOTYPES = YES;
382 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
383 | CLANG_WARN_UNREACHABLE_CODE = YES;
384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
386 | COPY_PHASE_STRIP = NO;
387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
388 | ENABLE_NS_ASSERTIONS = NO;
389 | ENABLE_STRICT_OBJC_MSGSEND = YES;
390 | GCC_C_LANGUAGE_STANDARD = gnu99;
391 | GCC_NO_COMMON_BLOCKS = YES;
392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
394 | GCC_WARN_UNDECLARED_SELECTOR = YES;
395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
396 | GCC_WARN_UNUSED_FUNCTION = YES;
397 | GCC_WARN_UNUSED_VARIABLE = YES;
398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
399 | MTL_ENABLE_DEBUG_INFO = NO;
400 | SDKROOT = iphoneos;
401 | SUPPORTED_PLATFORMS = iphoneos;
402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
403 | TARGETED_DEVICE_FAMILY = "1,2";
404 | VALIDATE_PRODUCT = YES;
405 | };
406 | name = Release;
407 | };
408 | 97C147061CF9000F007C117D /* Debug */ = {
409 | isa = XCBuildConfiguration;
410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
411 | buildSettings = {
412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
413 | CLANG_ENABLE_MODULES = YES;
414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
415 | ENABLE_BITCODE = NO;
416 | INFOPLIST_FILE = Runner/Info.plist;
417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
418 | PRODUCT_BUNDLE_IDENTIFIER = net.rcprogrammer.flutterBargraphExample;
419 | PRODUCT_NAME = "$(TARGET_NAME)";
420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
422 | SWIFT_VERSION = 5.0;
423 | VERSIONING_SYSTEM = "apple-generic";
424 | };
425 | name = Debug;
426 | };
427 | 97C147071CF9000F007C117D /* Release */ = {
428 | isa = XCBuildConfiguration;
429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
430 | buildSettings = {
431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
432 | CLANG_ENABLE_MODULES = YES;
433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
434 | ENABLE_BITCODE = NO;
435 | INFOPLIST_FILE = Runner/Info.plist;
436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
437 | PRODUCT_BUNDLE_IDENTIFIER = net.rcprogrammer.flutterBargraphExample;
438 | PRODUCT_NAME = "$(TARGET_NAME)";
439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
440 | SWIFT_VERSION = 5.0;
441 | VERSIONING_SYSTEM = "apple-generic";
442 | };
443 | name = Release;
444 | };
445 | /* End XCBuildConfiguration section */
446 |
447 | /* Begin XCConfigurationList section */
448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
449 | isa = XCConfigurationList;
450 | buildConfigurations = (
451 | 97C147031CF9000F007C117D /* Debug */,
452 | 97C147041CF9000F007C117D /* Release */,
453 | 249021D3217E4FDB00AE95B9 /* Profile */,
454 | );
455 | defaultConfigurationIsVisible = 0;
456 | defaultConfigurationName = Release;
457 | };
458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
459 | isa = XCConfigurationList;
460 | buildConfigurations = (
461 | 97C147061CF9000F007C117D /* Debug */,
462 | 97C147071CF9000F007C117D /* Release */,
463 | 249021D4217E4FDB00AE95B9 /* Profile */,
464 | );
465 | defaultConfigurationIsVisible = 0;
466 | defaultConfigurationName = Release;
467 | };
468 | /* End XCConfigurationList section */
469 | };
470 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
471 | }
472 |
--------------------------------------------------------------------------------