diff --git a/.vscode/settings.json b/.vscode/settings.json index e575498..36bafc3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "dart.flutterSdkPath": "D:\\zmt\\flutter\\dev" + "dart.flutterSdkPath": "D:\\Flutter\\flutter_source\\stable" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dcc8b46..35cadaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [1.0.0] + +* Merge code from 1.17.0 +* Fix analysis_options + ## [0.4.1] * add demo to show how to change pinned header height dynamically. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..4b0da0b --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,207 @@ +# Specify analysis options. +# +# Until there are meta linter rules, each desired lint must be explicitly enabled. +# See: https://github.com/dart-lang/linter/issues/288 +# +# For a list of lints, see: http://dart-lang.github.io/linter/lints/ +# See the configuration guide for more +# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer +# +# There are other similar analysis options files in the flutter repos, +# which should be kept in sync with this file: +# +# - analysis_options.yaml (this file) +# - packages/flutter/lib/analysis_options_user.yaml +# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml +# - https://github.com/flutter/engine/blob/master/analysis_options.yaml +# +# This file contains the analysis options used by Flutter tools, such as IntelliJ, +# Android Studio, and the `flutter analyze` command. + +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: warning + # treat missing returns as a warning (not a hint) + missing_return: warning + # allow having TODOs in the code + todo: ignore + # Ignore analyzer hints for updating pubspecs when using Future or + # Stream and not importing dart:async + # Please see https://github.com/flutter/flutter/pull/24528 for details. + sdk_version_async_exported_from_core: ignore + # exclude: + # - "bin/cache/**" + # # the following two are relative to the stocks example and the flutter package respectively + # # see https://github.com/dart-lang/sdk/issues/28463 + # - "lib/i18n/messages_*.dart" + # - "lib/src/http/**" + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + - always_declare_return_types + - always_put_control_body_on_new_line + # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 + - always_require_non_null_named_parameters + - always_specify_types + - annotate_overrides + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + # - avoid_as # required for implicit-casts: true + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # we do this commonly + # - avoid_catching_errors # we do this commonly + - avoid_classes_with_only_static_members + # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_empty_else + # - avoid_equals_and_hash_code_on_mutable_classes # not yet tested + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + # - avoid_implementing_value_types # not yet tested + - avoid_init_to_null + # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters # not yet tested + # - avoid_print # not yet tested + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + # - avoid_redundant_argument_values # not yet tested + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # there are plenty of valid reasons to return null + # - avoid_returning_null_for_future # not yet tested + - avoid_returning_null_for_void + # - avoid_returning_this # there are plenty of valid reasons to return this + # - avoid_setters_without_getters # not yet tested + # - avoid_shadowing_type_parameters # not yet tested + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + # - avoid_unnecessary_containers # not yet tested + - avoid_unused_constructor_parameters + - avoid_void_async + # - avoid_web_libraries_in_flutter # not yet tested + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # not yet tested + # - close_sinks # not reliable enough + # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 + # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + # - curly_braces_in_flow_control_structures # not yet tested + # - diagnostic_describe_all_properties # not yet tested + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + # - file_names # not yet tested + - flutter_style_todos + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - iterable_contains_unrelated_type + # - join_return_with_assignment # not yet tested + - library_names + - library_prefixes + # - lines_longer_than_80_chars # not yet tested + - list_remove_unrelated_type + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 + # - missing_whitespace_between_adjacent_strings # not yet tested + - no_adjacent_strings_in_list + - no_duplicate_case_values + # - no_logic_in_create_state # not yet tested + # - no_runtimeType_toString # not yet tested + - non_constant_identifier_names + # - null_closures # not yet tested + # - omit_local_variable_types # opposite of always_specify_types + # - one_member_abstracts # too many false positives + # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + # - parameter_assignments # we do this commonly + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + # - prefer_asserts_with_message # not yet tested + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + # - prefer_constructors_over_static_methods # not yet tested + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + - prefer_equal_for_default_values + # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + # - prefer_function_declarations_over_variables # not yet tested + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # not yet tested + # - prefer_interpolation_to_compose_strings # not yet tested + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 + # - prefer_relative_imports # not yet tested + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + # - provide_deprecation_message # not yet tested + # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + - slash_for_doc_comments + # - sort_child_properties_last # not yet tested + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures # too many false positives + # - unnecessary_await_in_return # not yet tested + - unnecessary_brace_in_string_interps + - unnecessary_const + # - unnecessary_final # conflicts with prefer_final_locals + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_in_if_null_operators + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_statements + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + # - unsafe_html # not yet tested + - use_full_hex_values_for_flutter_colors + # - use_function_type_syntax_for_parameters # not yet tested + # - use_key_in_widget_constructors # not yet tested + - use_rethrow_when_possible + # - use_setters_to_change_properties # not yet tested + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + - void_checks diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 7c1cb8c..582885a 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"C:\\\\Users\\\\hll\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"url_launcher","path":"C:\\\\Users\\\\hll\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-5.3.0\\\\","dependencies":[]}],"android":[{"name":"path_provider","path":"C:\\\\Users\\\\hll\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"url_launcher","path":"C:\\\\Users\\\\hll\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-5.3.0\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"url_launcher_web","path":"C:\\\\Users\\\\hll\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_web-0.1.0+2\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"path_provider","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web"]},{"name":"url_launcher_web","dependencies":[]}],"date_created":"2020-02-02 21:56:46.456099","version":"1.14.6"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-1.6.9\\\\","dependencies":[]},{"name":"url_launcher","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-5.3.0\\\\","dependencies":[]}],"android":[{"name":"path_provider","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-1.6.9\\\\","dependencies":[]},{"name":"url_launcher","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-5.3.0\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_macos-0.0.4+3\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"url_launcher_web","path":"C:\\\\Users\\\\eastmoney\\\\AppData\\\\Roaming\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_web-0.1.1+6\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web"]},{"name":"url_launcher_web","dependencies":[]}],"date_created":"2020-06-01 17:06:40.544750","version":"1.17.0"} \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 4e92ca0..320be22 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -22,23 +22,27 @@ if (flutterVersionName == null) { } apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 28 + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + lintOptions { disable 'InvalidPackage' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.zmtzawqlp.example" + applicationId "com.example.example" minSdkVersion 16 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -55,7 +59,5 @@ flutter { } dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 055d06b..c208884 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.example.example"> diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 5789ba9..55ca830 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,12 +1,5 @@ - - - - + package="com.example.example"> + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> + + + + diff --git a/example/android/app/src/main/java/com/zmtzawqlp/example/MainActivity.java b/example/android/app/src/main/java/com/zmtzawqlp/example/MainActivity.java deleted file mode 100644 index 5798398..0000000 --- a/example/android/app/src/main/java/com/zmtzawqlp/example/MainActivity.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.zmtzawqlp.example; - -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; - -public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } -} diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..e793a00 --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/example/android/app/src/main/kotlin/com/zmtzawqlp/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/zmtzawqlp/example/MainActivity.kt deleted file mode 100644 index 47059f9..0000000 --- a/example/android/app/src/main/kotlin/com/zmtzawqlp/example/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.zmtzawqlp.example - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa441..1f83a33 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index 055d06b..c208884 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.example.example"> diff --git a/example/android/build.gradle b/example/android/build.gradle index 854b216..3100ad2 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,14 +1,13 @@ buildscript { + ext.kotlin_version = '1.3.50' repositories { google() jcenter() -// maven { url 'https://maven.aliyun.com/repository/google' } -// maven { url 'https://maven.aliyun.com/repository/jcenter' } -// maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.3.1' + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -16,9 +15,6 @@ allprojects { repositories { google() jcenter() -// maven { url 'https://maven.aliyun.com/repository/google' } -// maven { url 'https://maven.aliyun.com/repository/jcenter' } -// maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 5f17537..38c8d45 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536M android.enableR8=true +android.useAndroidX=true android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 9b6616c..296b146 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/example/android/settings_aar.gradle b/example/android/settings_aar.gradle deleted file mode 100644 index e7b4def..0000000 --- a/example/android/settings_aar.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/example/ff_annotation_route_commands b/example/ff_annotation_route_commands index 6f626d8..2e8656d 100644 --- a/example/ff_annotation_route_commands +++ b/example/ff_annotation_route_commands @@ -1 +1 @@ --rn, -rh \ No newline at end of file +--route-constants --route-names --route-helper --no-is-initial-route \ No newline at end of file diff --git a/example/fvm b/example/fvm deleted file mode 120000 index e9e8888..0000000 --- a/example/fvm +++ /dev/null @@ -1 +0,0 @@ -D:/zmt/flutter/dev/bin/flutter.bat \ No newline at end of file diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9367d48..6b4c0f7 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index eab726d..204df29 100644 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -1,10 +1,11 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=D:\zmt\flutter\dev" -export "FLUTTER_APPLICATION_PATH=D:\zmt\FlutterCandies\dev\extended_nested_scroll_view\example" +export "FLUTTER_ROOT=D:\Flutter\flutter_source\stable" +export "FLUTTER_APPLICATION_PATH=D:\Flutter\github\FlutterCandies\dev\extended_nested_scroll_view\example" export "FLUTTER_TARGET=lib\main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build\ios" -export "FLUTTER_FRAMEWORK_DIR=D:\zmt\flutter\dev\bin\cache\artifacts\engine\ios" +export "OTHER_LDFLAGS=$(inherited) -framework Flutter" +export "FLUTTER_FRAMEWORK_DIR=D:\Flutter\flutter_source\stable\bin\cache\artifacts\engine\ios" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 21e6152..5f1bf4c 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,15 +8,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -29,8 +22,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,17 +31,13 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -62,8 +49,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -73,10 +58,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -90,7 +72,6 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, ); sourceTree = ""; }; @@ -105,8 +86,6 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -114,6 +93,8 @@ 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; @@ -121,7 +102,6 @@ 97C146F11CF9000F007C117D /* Supporting Files */ = { isa = PBXGroup; children = ( - 97C146F21CF9000F007C117D /* main.m */, ); name = "Supporting Files"; sourceTree = ""; @@ -155,17 +135,18 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; - ORGANIZATIONNAME = "The Chromium Authors"; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -188,9 +169,7 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -210,7 +189,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -233,8 +212,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -261,6 +239,83 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; @@ -275,12 +330,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -329,12 +386,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -358,6 +417,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -368,6 +429,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -380,8 +442,11 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.zmtzawqlp.example; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -391,6 +456,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -403,8 +469,10 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.zmtzawqlp.example; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -417,6 +485,7 @@ buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -426,6 +495,7 @@ buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1263ac8..a28140c 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -67,7 +65,7 @@ + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 36e21bb..0000000 --- a/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m deleted file mode 100644 index 59a72e9..0000000 --- a/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,13 +0,0 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 3d43d11..dc9ada4 100644 Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 0513117..a060db6 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m deleted file mode 100644 index dff6597..0000000 --- a/example/ios/Runner/main.m +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/example/lib/common/common.dart b/example/lib/common/common.dart index b692e7a..f59ef32 100644 --- a/example/lib/common/common.dart +++ b/example/lib/common/common.dart @@ -5,10 +5,10 @@ import 'package:flutter/material.dart'; import 'package:loading_more_list/loading_more_list.dart'; class SecondaryTabView extends StatefulWidget { + const SecondaryTabView(this.tabKey, this.tc, this.oldDemo); final String tabKey; final TabController tc; final bool oldDemo; - SecondaryTabView(this.tabKey, this.tc, this.oldDemo); @override _SecondaryTabViewState createState() => _SecondaryTabViewState(); } @@ -23,7 +23,7 @@ class _SecondaryTabViewState extends State @override Widget build(BuildContext context) { super.build(context); - var secondaryTabBar = new TabBar( + final TabBar secondaryTabBar = TabBar( controller: widget.tc, labelColor: Colors.blue, indicatorColor: Colors.blue, @@ -31,11 +31,11 @@ class _SecondaryTabViewState extends State indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: widget.tabKey + "0"), - Tab(text: widget.tabKey + "1"), - Tab(text: widget.tabKey + "2"), - Tab(text: widget.tabKey + "3"), + tabs: [ + Tab(text: widget.tabKey + '0'), + Tab(text: widget.tabKey + '1'), + Tab(text: widget.tabKey + '2'), + Tab(text: widget.tabKey + '3'), ], ); return Column( @@ -45,10 +45,10 @@ class _SecondaryTabViewState extends State child: TabBarView( controller: widget.tc, children: [ - TabViewItem(Key(widget.tabKey + "0"), widget.oldDemo), - TabViewItem(Key(widget.tabKey + "1"), widget.oldDemo), - TabViewItem(Key(widget.tabKey + "2"), widget.oldDemo), - TabViewItem(Key(widget.tabKey + "3"), widget.oldDemo), + TabViewItem(Key(widget.tabKey + '0'), widget.oldDemo), + TabViewItem(Key(widget.tabKey + '1'), widget.oldDemo), + TabViewItem(Key(widget.tabKey + '2'), widget.oldDemo), + TabViewItem(Key(widget.tabKey + '3'), widget.oldDemo), ], ), ) @@ -61,9 +61,9 @@ class _SecondaryTabViewState extends State } class TabViewItem extends StatefulWidget { + const TabViewItem(this.tabKey, this.oldDemo); final Key tabKey; final bool oldDemo; - TabViewItem(this.tabKey, this.oldDemo); @override _TabViewItemState createState() => _TabViewItemState(); } @@ -73,22 +73,22 @@ class _TabViewItemState extends State @override Widget build(BuildContext context) { super.build(context); - var child = GlowNotificationWidget( + final GlowNotificationWidget child = GlowNotificationWidget( //margin: EdgeInsets.only(left: 190.0), ListView.builder( - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( //decoration: BoxDecoration(border: Border.all(color: Colors.orange,width: 1.0)), alignment: Alignment.center, height: 60.0, width: double.infinity, //color: Colors.blue, - child: Text(widget.tabKey.toString() + ": List$i"), + child: Text(widget.tabKey.toString() + ': List$i'), ); }, itemCount: 100, - padding: EdgeInsets.all(0.0)), + padding: const EdgeInsets.all(0.0)), showGlowLeading: false, ); @@ -108,11 +108,10 @@ class _TabViewItemState extends State class CommonSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { + CommonSliverPersistentHeaderDelegate(this.child, this.height); final Widget child; final double height; - CommonSliverPersistentHeaderDelegate(this.child, this.height); - @override double get minExtent => height; @@ -127,42 +126,44 @@ class CommonSliverPersistentHeaderDelegate @override bool shouldRebuild(CommonSliverPersistentHeaderDelegate oldDelegate) { - //print("shouldRebuild---------------"); + //print('shouldRebuild---------------'); return oldDelegate != this; } } -Future onRefresh() { - return Future.delayed(const Duration(seconds: 1)); +Future onRefresh() { + return Future.delayed(const Duration(seconds: 1), () { + return true; + }); } List buildSliverHeader() { - var widgets = []; + final List widgets = []; widgets.add(SliverAppBar( pinned: true, expandedHeight: 200.0, - //title: Text(old ? "old demo" : "new demo"), + //title: Text(old ? 'old demo' : 'new demo'), flexibleSpace: FlexibleSpaceBar( //centerTitle: true, collapseMode: CollapseMode.pin, background: Image.asset( - "assets/467141054.jpg", + 'assets/467141054.jpg', fit: BoxFit.fill, )))); widgets.add(SliverGrid( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, crossAxisSpacing: 0.0, mainAxisSpacing: 0.0, ), - delegate: new SliverChildBuilderDelegate( + delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Container( alignment: Alignment.center, height: 60.0, - child: Text("Gird$index"), + child: Text('Gird$index'), decoration: BoxDecoration( border: Border.all(color: Colors.orange, width: 1.0)), ); @@ -172,11 +173,11 @@ List buildSliverHeader() { )); widgets.add(SliverList( - delegate: SliverChildBuilderDelegate((c, i) { + delegate: SliverChildBuilderDelegate((BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, - child: Text("SliverList$i"), + child: Text('SliverList$i'), ); }, childCount: 3))); diff --git a/example/lib/common/push_to_refresh_header.dart b/example/lib/common/push_to_refresh_header.dart index faf8d0b..676085f 100644 --- a/example/lib/common/push_to_refresh_header.dart +++ b/example/lib/common/push_to_refresh_header.dart @@ -1,9 +1,9 @@ import 'dart:math'; - +import 'dart:ui' as ui show Image; import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; import 'package:pull_to_refresh_notification/pull_to_refresh_notification.dart'; -import 'dart:ui' as ui show Image; + import 'package:intl/intl.dart'; double get maxDragOffset => 100; @@ -11,36 +11,38 @@ double hideHeight = maxDragOffset / 2.3; double refreshHeight = maxDragOffset / 1.5; class PullToRefreshHeader extends StatelessWidget { + + const PullToRefreshHeader(this.info, this.lastRefreshTime, {this.color}); final PullToRefreshScrollNotificationInfo info; final DateTime lastRefreshTime; final Color color; - PullToRefreshHeader(this.info, this.lastRefreshTime, {this.color}); - @override Widget build(BuildContext context) { - if (info == null) return Container(); - String text = ""; + if (info == null) { + return Container(); + } + String text = ''; if (info.mode == RefreshIndicatorMode.armed) { - text = "Release to refresh"; + text = 'Release to refresh'; } else if (info.mode == RefreshIndicatorMode.refresh || info.mode == RefreshIndicatorMode.snap) { - text = "Loading..."; + text = 'Loading...'; } else if (info.mode == RefreshIndicatorMode.done) { - text = "Refresh completed."; + text = 'Refresh completed.'; } else if (info.mode == RefreshIndicatorMode.drag) { - text = "Pull to refresh"; + text = 'Pull to refresh'; } else if (info.mode == RefreshIndicatorMode.canceled) { - text = "Cancel refresh"; + text = 'Cancel refresh'; } final TextStyle ts = TextStyle( color: Colors.grey, ).copyWith(fontSize: 14); - double dragOffset = info?.dragOffset ?? 0.0; + final double dragOffset = info?.dragOffset ?? 0.0; - DateTime time = lastRefreshTime ?? DateTime.now(); - final top = -hideHeight + dragOffset; + final DateTime time = lastRefreshTime ?? DateTime.now(); + final double top = -hideHeight + dragOffset; return Container( height: dragOffset, color: color ?? Colors.transparent, @@ -60,7 +62,7 @@ class PullToRefreshHeader extends StatelessWidget { child: Container( alignment: Alignment.centerRight, child: RefreshImage(top), - margin: EdgeInsets.only(right: 12.0), + margin: const EdgeInsets.only(right: 12.0), ), ), Column( @@ -70,8 +72,8 @@ class PullToRefreshHeader extends StatelessWidget { style: ts, ), Text( - "Last updated:" + - DateFormat("yyyy-MM-dd hh:mm").format(time), + 'Last updated:' + + DateFormat('yyyy-MM-dd hh:mm').format(time), style: ts.copyWith(fontSize: 14), ) ], @@ -89,13 +91,14 @@ class PullToRefreshHeader extends StatelessWidget { } class RefreshImage extends StatelessWidget { + + const RefreshImage(this.top); final double top; - RefreshImage(this.top); @override Widget build(BuildContext context) { - final double imageSize = 30; + const double imageSize = 30; return ExtendedImage.asset( - "assets/flutterCandies_grey.png", + 'assets/flutterCandies_grey.png', width: imageSize, height: imageSize, afterPaintImage: (Canvas canvas, Rect rect, ui.Image image, Paint paint) { @@ -103,7 +106,7 @@ class RefreshImage extends StatelessWidget { final double imageWidth = image.width.toDouble(); final Size size = rect.size; final double y = - (1 - min(top / (refreshHeight - hideHeight), 1)) * imageHeight; + (1 - min(top / (refreshHeight - hideHeight), 1)) * imageHeight as double; canvas.drawImageRect( image, @@ -112,7 +115,7 @@ class RefreshImage extends StatelessWidget { size.width, (imageHeight - y) / imageHeight * size.height), Paint() ..colorFilter = - ColorFilter.mode(Color(0xFFea5504), BlendMode.srcIn) + const ColorFilter.mode( Color(0xFFea5504), BlendMode.srcIn) ..isAntiAlias = false ..filterQuality = FilterQuality.low); diff --git a/example/lib/example_route.dart b/example/lib/example_route.dart index b093cd6..506a59d 100644 --- a/example/lib/example_route.dart +++ b/example/lib/example_route.dart @@ -13,74 +13,99 @@ import 'pages/main_page.dart'; import 'pages/pull_to_refresh.dart'; import 'pages/scroll_to_top.dart'; +// ignore_for_file: argument_type_not_assignable RouteResult getRouteResult({String name, Map arguments}) { switch (name) { - case "fluttercandies://PingLunDemo": + case 'fluttercandies://PingLunDemo': return RouteResult( + name: name, widget: PingLunDemo(), - routeName: "pingLundemo", + routeName: 'pingLundemo', pageRouteType: PageRouteType.transparent, - description: "Tik Tok Comment", + description: 'Tik Tok Comment', ); - case "fluttercandies://TextFieldPage": + case 'fluttercandies://TextFieldPage': return RouteResult( + name: name, widget: TextFieldPage( text: arguments['text'], ), - routeName: "TextFieldPage", + routeName: 'TextFieldPage', pageRouteType: PageRouteType.transparent, - description: "Tik Tok Comment", + description: 'Tik Tok Comment', ); - case "fluttercandies://Tik Tok Comment": + case 'fluttercandies://Tik Tok Comment': return RouteResult( + name: name, widget: DouYinPingLunDemo(), - routeName: "tiktokcomment", - description: "Demo for Tik Tok Comment", + routeName: 'tiktokcomment', + description: 'Demo for Tik Tok Comment', ); - case "fluttercandies://loadmore": + case 'fluttercandies://loadmore': return RouteResult( + name: name, widget: LoadMoreDemo(), - routeName: "load more demo", + routeName: 'load more demo', description: "show how to support load more list in NestedScrollView's body without ScrollController", ); - case "fluttercandies://mainpage": + case 'fluttercandies://mainpage': return RouteResult( + name: name, widget: MainPage(), - routeName: "MainPage", + routeName: 'MainPage', ); - case "fluttercandies://nestedscrollview": + case 'fluttercandies://nestedscrollview': return RouteResult( + name: name, widget: OldExtendedNestedScrollViewDemo(), - routeName: "NestedScrollview", - description: "fix pinned header and inner scrollables sync issues.", + routeName: 'NestedScrollview', + description: 'fix pinned header and inner scrollables sync issues.', ); - case "fluttercandies://pinned header height": + case 'fluttercandies://pinned header height': return RouteResult( + name: name, widget: DynamicPinnedHeaderHeightDemo(), - routeName: "pinned header height", - description: "how to change pinned header height dynamically", + routeName: 'pinned header height', + description: 'how to change pinned header height dynamically', ); - case "fluttercandies://pulltorefresh": + case 'fluttercandies://pulltorefresh': return RouteResult( + name: name, widget: PullToRefreshDemo(), - routeName: "pull to refresh", + routeName: 'pull to refresh', description: "how to pull to refresh for list in NestedScrollView's body without ScrollController", ); - case "fluttercandies://scroll to top": + case 'fluttercandies://scroll to top': return RouteResult( + name: name, widget: ScrollToTopDemo(), - routeName: "scroll to top", + routeName: 'scroll to top', description: "how to scroll list to top in NestedScrollView's body without ScrollController", ); default: - return RouteResult(); + return const RouteResult(name: 'flutterCandies://notfound'); } } class RouteResult { + const RouteResult({ + @required this.name, + this.widget, + this.showStatusBar = true, + this.routeName = '', + this.pageRouteType, + this.description = '', + this.exts, + }); + + /// The name of the route (e.g., "/settings"). + /// + /// If null, the route is anonymous. + final String name; + /// The Widget return base on route final Widget widget; @@ -96,25 +121,12 @@ class RouteResult { /// The description of route final String description; - const RouteResult({ - this.widget, - this.showStatusBar = true, - this.routeName = '', - this.pageRouteType, - this.description = '', - }); + /// The extend arguments + final Map exts; } -enum PageRouteType { material, cupertino, transparent } - -List routeNames = [ - "fluttercandies://PingLunDemo", - "fluttercandies://TextFieldPage", - "fluttercandies://Tik Tok Comment", - "fluttercandies://loadmore", - "fluttercandies://mainpage", - "fluttercandies://nestedscrollview", - "fluttercandies://pinned header height", - "fluttercandies://pulltorefresh", - "fluttercandies://scroll to top" -]; +enum PageRouteType { + material, + cupertino, + transparent, +} diff --git a/example/lib/example_route_helper.dart b/example/lib/example_route_helper.dart index e62f583..24919ed 100644 --- a/example/lib/example_route_helper.dart +++ b/example/lib/example_route_helper.dart @@ -12,44 +12,42 @@ import 'package:flutter/widgets.dart'; import 'example_route.dart'; class FFNavigatorObserver extends NavigatorObserver { - final RouteChange routeChange; - FFNavigatorObserver({this.routeChange}); + final RouteChange routeChange; + @override - void didPop(Route route, Route previousRoute) { + void didPop(Route route, Route previousRoute) { super.didPop(route, previousRoute); _didRouteChange(previousRoute, route); } @override - void didPush(Route route, Route previousRoute) { + void didPush(Route route, Route previousRoute) { super.didPush(route, previousRoute); _didRouteChange(route, previousRoute); } @override - void didRemove(Route route, Route previousRoute) { + void didRemove(Route route, Route previousRoute) { super.didRemove(route, previousRoute); _didRouteChange(previousRoute, route); } @override - void didReplace({Route newRoute, Route oldRoute}) { + void didReplace({Route newRoute, Route oldRoute}) { super.didReplace(newRoute: newRoute, oldRoute: oldRoute); _didRouteChange(newRoute, oldRoute); } - void _didRouteChange(Route newRoute, Route oldRoute) { + void _didRouteChange(Route newRoute, Route oldRoute) { // oldRoute may be null when route first time enter. routeChange?.call(newRoute, oldRoute); } } typedef RouteChange = void Function( - Route newRoute, - Route oldRoute, -); + Route newRoute, Route oldRoute); class FFTransparentPageRoute extends PageRouteBuilder { FFTransparentPageRoute({ @@ -94,59 +92,81 @@ Route onGenerateRouteHelper( }) { arguments ??= settings.arguments; - final routeResult = getRouteResult( + final RouteResult routeResult = getRouteResult( name: settings.name, - arguments: arguments, + arguments: arguments as Map, ); if (routeResult.showStatusBar != null || routeResult.routeName != null) { settings = FFRouteSettings( name: settings.name, - isInitialRoute: settings.isInitialRoute, routeName: routeResult.routeName, - arguments: arguments, + arguments: arguments as Map, showStatusBar: routeResult.showStatusBar, ); } - final page = routeResult.widget ?? notFoundFallback; + final Widget page = routeResult.widget ?? notFoundFallback; if (page == null) { throw Exception( - '''Route "${settings.name}" returned null.Route Widget must never return null, + '''Route "${settings.name}" returned null. Route Widget must never return null, maybe the reason is that route name did not match with right path. - You can use parameter[notFoundFallback] to avoid this ugly error.'''); + You can use parameter[notFoundFallback] to avoid this ugly error.''', + ); } if (arguments is Map) { - RouteBuilder builder = arguments['routeBuilder']; - if (builder != null) return builder(page); + final RouteBuilder builder = arguments['routeBuilder'] as RouteBuilder; + if (builder != null) { + return builder(page); + } } switch (routeResult.pageRouteType) { case PageRouteType.material: - return MaterialPageRoute(settings: settings, builder: (_) => page); + return MaterialPageRoute( + settings: settings, + builder: (BuildContext _) => page, + ); case PageRouteType.cupertino: - return CupertinoPageRoute(settings: settings, builder: (_) => page); + return CupertinoPageRoute( + settings: settings, + builder: (BuildContext _) => page, + ); case PageRouteType.transparent: - return FFTransparentPageRoute( + return FFTransparentPageRoute( settings: settings, - pageBuilder: (_, __, ___) => page, + pageBuilder: ( + BuildContext _, + Animation __, + Animation ___, + ) => + page, ); default: return Platform.isIOS - ? CupertinoPageRoute(settings: settings, builder: (_) => page) - : MaterialPageRoute(settings: settings, builder: (_) => page); + ? CupertinoPageRoute( + settings: settings, + builder: (BuildContext _) => page, + ) + : MaterialPageRoute( + settings: settings, + builder: (BuildContext _) => page, + ); } } -typedef RouteBuilder = PageRoute Function(Widget page); +typedef RouteBuilder = PageRoute Function(Widget page); class FFRouteSettings extends RouteSettings { - final String routeName; - final bool showStatusBar; const FFRouteSettings({ this.routeName, this.showStatusBar, String name, - bool isInitialRoute = false, Object arguments, - }) : super(name: name, isInitialRoute: isInitialRoute, arguments: arguments); + }) : super( + name: name, + arguments: arguments, + ); + + final String routeName; + final bool showStatusBar; } diff --git a/example/lib/example_routes.dart b/example/lib/example_routes.dart new file mode 100644 index 0000000..0329b43 --- /dev/null +++ b/example/lib/example_routes.dart @@ -0,0 +1,111 @@ +// GENERATED CODE - DO NOT MODIFY MANUALLY +// ************************************************************************** +// Auto generated by https://github.com/fluttercandies/ff_annotation_route +// ************************************************************************** +const List routeNames = [ + 'fluttercandies://PingLunDemo', + 'fluttercandies://TextFieldPage', + 'fluttercandies://Tik Tok Comment', + 'fluttercandies://loadmore', + 'fluttercandies://mainpage', + 'fluttercandies://nestedscrollview', + 'fluttercandies://pinned header height', + 'fluttercandies://pulltorefresh', + 'fluttercandies://scroll to top', +]; + +class Routes { + const Routes._(); + + /// 'Tik Tok Comment' + /// + /// [name] : 'fluttercandies://PingLunDemo' + /// + /// [routeName] : 'pingLundemo' + /// + /// [description] : 'Tik Tok Comment' + /// + /// [pageRouteType] : PageRouteType.transparent + static const String fluttercandiesPingLunDemo = + 'fluttercandies://PingLunDemo'; + + /// 'Tik Tok Comment' + /// + /// [name] : 'fluttercandies://TextFieldPage' + /// + /// [routeName] : 'TextFieldPage' + /// + /// [description] : 'Tik Tok Comment' + /// + /// [arguments] : [text] + /// + /// [pageRouteType] : PageRouteType.transparent + static const String fluttercandiesTextFieldPage = + 'fluttercandies://TextFieldPage'; + + /// 'Demo for Tik Tok Comment' + /// + /// [name] : 'fluttercandies://Tik Tok Comment' + /// + /// [routeName] : 'tiktokcomment' + /// + /// [description] : 'Demo for Tik Tok Comment' + static const String fluttercandiesTikTokComment = + 'fluttercandies://Tik Tok Comment'; + + /// "show how to support load more list in NestedScrollView's body without ScrollController" + /// + /// [name] : 'fluttercandies://loadmore' + /// + /// [routeName] : 'load more demo' + /// + /// [description] : "show how to support load more list in NestedScrollView's body without ScrollController" + static const String fluttercandiesLoadmore = 'fluttercandies://loadmore'; + + /// 'MainPage' + /// + /// [name] : 'fluttercandies://mainpage' + /// + /// [routeName] : 'MainPage' + static const String fluttercandiesMainpage = 'fluttercandies://mainpage'; + + /// 'fix pinned header and inner scrollables sync issues.' + /// + /// [name] : 'fluttercandies://nestedscrollview' + /// + /// [routeName] : 'NestedScrollview' + /// + /// [description] : 'fix pinned header and inner scrollables sync issues.' + static const String fluttercandiesNestedscrollview = + 'fluttercandies://nestedscrollview'; + + /// 'how to change pinned header height dynamically' + /// + /// [name] : 'fluttercandies://pinned header height' + /// + /// [routeName] : 'pinned header height' + /// + /// [description] : 'how to change pinned header height dynamically' + static const String fluttercandiesPinnedHeaderHeight = + 'fluttercandies://pinned header height'; + + /// "how to pull to refresh for list in NestedScrollView's body without ScrollController" + /// + /// [name] : 'fluttercandies://pulltorefresh' + /// + /// [routeName] : 'pull to refresh' + /// + /// [description] : "how to pull to refresh for list in NestedScrollView's body without ScrollController" + static const String fluttercandiesPulltorefresh = + 'fluttercandies://pulltorefresh'; + + /// "how to scroll list to top in NestedScrollView's body without ScrollController" + /// + /// [name] : 'fluttercandies://scroll to top' + /// + /// [routeName] : 'scroll to top' + /// + /// [description] : "how to scroll list to top in NestedScrollView's body without ScrollController" + static const String fluttercandiesScrollToTop = + 'fluttercandies://scroll to top'; +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 29bd5fc..8d5d2b7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,68 +4,46 @@ import 'package:flutter/material.dart' hide NestedScrollView; import 'example_route.dart'; import 'example_route_helper.dart'; +import 'example_routes.dart'; -void main() => runApp(MyApp()); +void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { - MyApp(); + const MyApp(); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData( - primarySwatch: Colors.blue, - ), - builder: (c, w) { - if (kIsWeb) return w; - var data = MediaQuery.of(c); - return MediaQuery( - data: data.copyWith(textScaleFactor: 1.0), - child: w, + debugShowCheckedModeBanner: false, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + builder: (BuildContext c, Widget w) { + if (kIsWeb) { + return w; + } + final MediaQueryData data = MediaQuery.of(c); + return MediaQuery( + data: data.copyWith(textScaleFactor: 1.0), + child: w, + ); + }, + initialRoute: Routes.fluttercandiesMainpage, + onGenerateRoute: (RouteSettings settings) { + //when refresh web, route will as following + // / + // /fluttercandies: + // /fluttercandies:/ + // /fluttercandies://mainpage + if (kIsWeb && settings.name.startsWith('/')) { + return onGenerateRouteHelper( + settings.copyWith(name: settings.name.replaceFirst('/', '')), + notFoundFallback: + getRouteResult(name: Routes.fluttercandiesMainpage).widget, ); - }, - initialRoute: "fluttercandies://mainpage", - onGenerateRoute: (RouteSettings settings) { - var routeName = settings.name; - //when refresh web, route will as following - // / - // /fluttercandies: - // /fluttercandies:/ - // /fluttercandies://mainpage - - if (kIsWeb && routeName.startsWith('/')) { - routeName = routeName.replaceFirst('/', ''); - } - - var routeResult = - getRouteResult(name: routeName, arguments: settings.arguments); - - var page = routeResult.widget ?? - getRouteResult( - name: 'fluttercandies://mainpage', - arguments: settings.arguments) - .widget; - - final platform = Theme.of(context).platform; - - switch (routeResult.pageRouteType) { - case PageRouteType.material: - return MaterialPageRoute( - settings: settings, builder: (_) => page); - case PageRouteType.cupertino: - return CupertinoPageRoute( - settings: settings, builder: (_) => page); - case PageRouteType.transparent: - return FFTransparentPageRoute( - settings: settings, - pageBuilder: (_, __, ___) => page, - ); - default: - return platform == TargetPlatform.iOS - ? CupertinoPageRoute(settings: settings, builder: (_) => page) - : MaterialPageRoute(settings: settings, builder: (_) => page); - } - }); + } + return onGenerateRouteHelper(settings); + }, + ); } } diff --git a/example/lib/pages/dou_yin_ping_lun.dart b/example/lib/pages/dou_yin_ping_lun.dart index 37d1369..d84cf98 100644 --- a/example/lib/pages/dou_yin_ping_lun.dart +++ b/example/lib/pages/dou_yin_ping_lun.dart @@ -6,20 +6,19 @@ import 'package:flutter/services.dart'; import 'package:loading_more_list/loading_more_list.dart'; import 'package:ff_annotation_route/ff_annotation_route.dart'; - @FFRoute( - name: "fluttercandies://Tik Tok Comment", - routeName: "tiktokcomment", - description: "Demo for Tik Tok Comment") + name: 'fluttercandies://Tik Tok Comment', + routeName: 'tiktokcomment', + description: 'Demo for Tik Tok Comment') class DouYinPingLunDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Tik Tok Comment'), + title: const Text('Tik Tok Comment'), ), body: ListView.builder( - itemBuilder: (_, index) => Text( + itemBuilder: (_, int index) => Text( '$index', textAlign: TextAlign.center, ), @@ -36,9 +35,9 @@ class DouYinPingLunDemo extends StatelessWidget { } @FFRoute( - name: "fluttercandies://PingLunDemo", - routeName: "pingLundemo", - description: "Tik Tok Comment", + name: 'fluttercandies://PingLunDemo', + routeName: 'pingLundemo', + description: 'Tik Tok Comment', pageRouteType: PageRouteType.transparent, ) class PingLunDemo extends StatefulWidget { @@ -51,18 +50,18 @@ class _PingLunDemoState extends State TabController primaryTC; ScrollController sc = ScrollController(); TextEditingController tc = TextEditingController(); - FocusNode _focusNode = FocusNode()..canRequestFocus = false; + final FocusNode _focusNode = FocusNode()..canRequestFocus = false; Timer _timer; bool _isAnimating = false; bool _isTapped = false; @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); - WidgetsBinding.instance.addPostFrameCallback((callback) { + primaryTC = TabController(length: 2, vsync: this); + WidgetsBinding.instance.addPostFrameCallback((Duration callback) { _isAnimating = true; sc .animateTo(200.0, - duration: Duration( + duration: const Duration( milliseconds: 300, ), curve: Curves.easeIn) @@ -94,12 +93,12 @@ class _PingLunDemoState extends State } void _startTimer() { - _timer = Timer.periodic(Duration(milliseconds: 50), (Timer timer) { + _timer = Timer.periodic(const Duration(milliseconds: 50), (Timer timer) { timer.cancel(); if (sc.position.pixels != 200.0) { sc .animateTo(200.0, - duration: Duration( + duration: const Duration( milliseconds: 50, ), curve: Curves.easeIn) @@ -115,7 +114,7 @@ class _PingLunDemoState extends State onPointerDown: (_) => _isTapped = true, onPointerUp: (_) => _isTapped = false, child: NotificationListener( - onNotification: (value) { + onNotification: (ScrollNotification value) { if (value.depth == 0) { if (value is ScrollEndNotification || value is OverscrollNotification) { @@ -134,8 +133,8 @@ class _PingLunDemoState extends State Widget _buildScaffoldBody() { return NestedScrollView( controller: sc, - headerSliverBuilder: (c, f) { - return [ + headerSliverBuilder: (BuildContext c, bool f) { + return [ SliverToBoxAdapter( child: GestureDetector( child: Container( @@ -153,7 +152,7 @@ class _PingLunDemoState extends State }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; index += primaryTC.index.toString(); @@ -170,9 +169,9 @@ class _PingLunDemoState extends State indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs: const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( @@ -180,17 +179,17 @@ class _PingLunDemoState extends State controller: primaryTC, children: [ NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab0"), + const Key('Tab0'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab0"), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab0'), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, - child: - Text(Key("Tab0").toString() + ": ListView$i"), + child: Text( + const Key('Tab0').toString() + ': ListView$i'), ); }, itemCount: 50, @@ -199,17 +198,17 @@ class _PingLunDemoState extends State ), ), NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab1"), + const Key('Tab1'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab1"), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab1'), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, - child: - Text(Key("Tab1").toString() + ": ListView$i"), + child: Text( + const Key('Tab1').toString() + ': ListView$i'), ); }, itemCount: 50, @@ -228,19 +227,22 @@ class _PingLunDemoState extends State autofocus: false, focusNode: _focusNode, onTap: () { - Navigator.pushNamed(context, 'fluttercandies://TextFieldPage', - arguments: {'text': tc.text}).then((value) { - tc.text = value; + Navigator.pushNamed( + context, 'fluttercandies://TextFieldPage', + arguments: {'text': tc.text}) + .then((dynamic value) { + tc.text = value.toString(); ///make sure TextInput is hide - Future.delayed(Duration(milliseconds: 200), () { - SystemChannels.textInput.invokeMethod('TextInput.hide'); + Future.delayed(const Duration(milliseconds: 200), () { + SystemChannels.textInput + .invokeMethod('TextInput.hide'); }); }); }, decoration: InputDecoration( hintText: 'say something', - contentPadding: EdgeInsets.all( + contentPadding: const EdgeInsets.all( 10.0, ), border: OutlineInputBorder( @@ -260,22 +262,23 @@ class _PingLunDemoState extends State } @FFRoute( - name: "fluttercandies://TextFieldPage", - routeName: "TextFieldPage", - description: "Tik Tok Comment", - argumentNames: ['text'], + name: 'fluttercandies://TextFieldPage', + routeName: 'TextFieldPage', + description: 'Tik Tok Comment', + argumentNames: ['text'], pageRouteType: PageRouteType.transparent, ) class TextFieldPage extends StatefulWidget { - final String text; - TextFieldPage({this.text}); + + const TextFieldPage({this.text}); + final String text; @override _TextFieldPageState createState() => _TextFieldPageState(); } class _TextFieldPageState extends State { TextEditingController tc = TextEditingController(); - FocusNode _focusNode = FocusNode(); + final FocusNode _focusNode = FocusNode(); @override void initState() { tc.text = widget.text; @@ -285,7 +288,7 @@ class _TextFieldPageState extends State { @override Widget build(BuildContext context) { - final keyboardHeight = MediaQuery.of(context).viewInsets.bottom; + final double keyboardHeight = MediaQuery.of(context).viewInsets.bottom; return Material( color: Colors.transparent, child: Column( @@ -309,7 +312,7 @@ class _TextFieldPageState extends State { focusNode: _focusNode, decoration: InputDecoration( hintText: 'say something', - contentPadding: EdgeInsets.all( + contentPadding: const EdgeInsets.all( 10.0, ), border: OutlineInputBorder( diff --git a/example/lib/pages/dynamic_pinned_header_height.dart b/example/lib/pages/dynamic_pinned_header_height.dart index 66c9643..ac6470f 100644 --- a/example/lib/pages/dynamic_pinned_header_height.dart +++ b/example/lib/pages/dynamic_pinned_header_height.dart @@ -5,10 +5,9 @@ import 'package:loading_more_list/loading_more_list.dart'; import 'package:ff_annotation_route/ff_annotation_route.dart'; @FFRoute( - name: "fluttercandies://pinned header height", - routeName: "pinned header height", - description: - "how to change pinned header height dynamically") + name: 'fluttercandies://pinned header height', + routeName: 'pinned header height', + description: 'how to change pinned header height dynamically') class DynamicPinnedHeaderHeightDemo extends StatefulWidget { @override _DynamicPinnedHeaderHeightDemoState createState() => @@ -21,7 +20,7 @@ class _DynamicPinnedHeaderHeightDemoState ScrollController sc = ScrollController(); @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); + primaryTC = TabController(length: 2, vsync: this); super.initState(); } @@ -40,7 +39,7 @@ class _DynamicPinnedHeaderHeightDemoState child: Icon(Icons.update), onPressed: () { //change pinnedHeaderHeight here - final before = pinnedHeaderHeight; + final double before = pinnedHeaderHeight; pinnedHeaderHeight += 10.0; sc.position.applyContentDimensions(sc.position.minScrollExtent, sc.position.maxScrollExtent + before); @@ -61,17 +60,17 @@ class _DynamicPinnedHeaderHeightDemoState onRefresh: onRefresh, child: NestedScrollView( controller: sc, - headerSliverBuilder: (c, f) { - return [ + headerSliverBuilder: (BuildContext c, bool f) { + return [ SliverAppBar( pinned: true, expandedHeight: 200.0, - title: Text("pinned header height"), + title: const Text('pinned header height'), flexibleSpace: FlexibleSpaceBar( //centerTitle: true, collapseMode: CollapseMode.pin, background: Image.asset( - "assets/467141054.jpg", + 'assets/467141054.jpg', fit: BoxFit.fill, ))) ]; @@ -82,7 +81,7 @@ class _DynamicPinnedHeaderHeightDemoState }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; index += primaryTC.index.toString(); @@ -98,9 +97,9 @@ class _DynamicPinnedHeaderHeightDemoState indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs: const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( @@ -108,18 +107,18 @@ class _DynamicPinnedHeaderHeightDemoState controller: primaryTC, children: [ NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab0"), + const Key('Tab0'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab0"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab0'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, child: - Text(Key("Tab0").toString() + ": ListView$i"), + Text(const Key('Tab0').toString() + ': ListView$i'), ); }, itemCount: 50, @@ -128,18 +127,18 @@ class _DynamicPinnedHeaderHeightDemoState ), ), NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab1"), + const Key('Tab1'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab1"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab1'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, child: - Text(Key("Tab1").toString() + ": ListView$i"), + Text(const Key('Tab1').toString() + ': ListView$i'), ); }, itemCount: 50, diff --git a/example/lib/pages/extened_nested_scroll_view_demo.dart b/example/lib/pages/extened_nested_scroll_view_demo.dart index 2d3623c..408f4e6 100644 --- a/example/lib/pages/extened_nested_scroll_view_demo.dart +++ b/example/lib/pages/extened_nested_scroll_view_demo.dart @@ -6,10 +6,10 @@ import 'package:ff_annotation_route/ff_annotation_route.dart'; @FFRoute( - name: "fluttercandies://nestedscrollview", - routeName: "NestedScrollview", + name: 'fluttercandies://nestedscrollview', + routeName: 'NestedScrollview', description: - "fix pinned header and inner scrollables sync issues.") + 'fix pinned header and inner scrollables sync issues.') class OldExtendedNestedScrollViewDemo extends StatefulWidget { @override _OldExtendedNestedScrollViewDemoState createState() => @@ -24,9 +24,9 @@ class _OldExtendedNestedScrollViewDemoState @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); + primaryTC = TabController(length: 2, vsync: this); primaryTC.addListener(tabControlerListener); - secondaryTC = new TabController(length: 4, vsync: this); + secondaryTC = TabController(length: 4, vsync: this); super.initState(); } @@ -58,7 +58,7 @@ class _OldExtendedNestedScrollViewDemoState Widget _buildScaffoldBody() { final double statusBarHeight = MediaQuery.of(context).padding.top; - var pinnedHeaderHeight = + final double pinnedHeaderHeight = //statusBar height statusBarHeight + //pinned SliverAppBar height in header @@ -66,7 +66,7 @@ class _OldExtendedNestedScrollViewDemoState return NestedScrollViewRefreshIndicator( onRefresh: onRefresh, child: NestedScrollView( - headerSliverBuilder: (c, f) { + headerSliverBuilder: (BuildContext c, bool f) { return buildSliverHeader(); }, //1.[pinned sliver header issue](https://github.com/flutter/flutter/issues/22393) @@ -75,10 +75,10 @@ class _OldExtendedNestedScrollViewDemoState }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; if (primaryTC.index == 0) { index += - (primaryTC.index.toString() + secondaryTC.index.toString()); + primaryTC.index.toString() + secondaryTC.index.toString(); } else { index += primaryTC.index.toString(); } @@ -94,29 +94,29 @@ class _OldExtendedNestedScrollViewDemoState indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs: const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( child: TabBarView( controller: primaryTC, children: [ - SecondaryTabView("Tab0", secondaryTC, true), + SecondaryTabView('Tab0', secondaryTC, true), NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab1"), + const Key('Tab1'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab1"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab1'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, child: - Text(Key("Tab1").toString() + ": ListView$i"), + Text(const Key('Tab1').toString() + ': ListView$i'), ); }, itemCount: 50, diff --git a/example/lib/pages/load_more.dart b/example/lib/pages/load_more.dart index 011b91e..3e5fdfd 100644 --- a/example/lib/pages/load_more.dart +++ b/example/lib/pages/load_more.dart @@ -1,14 +1,15 @@ -import 'package:flutter/material.dart' hide NestedScrollView; +import 'dart:async'; +import 'package:flutter/material.dart' + hide NestedScrollView, NestedScrollViewState; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:loading_more_list/loading_more_list.dart'; import 'package:ff_annotation_route/ff_annotation_route.dart'; -import 'dart:async'; @FFRoute( - name: "fluttercandies://loadmore", - routeName: "load more demo", + name: 'fluttercandies://loadmore', + routeName: 'load more demo', description: - "show how to support load more list in NestedScrollView's body without ScrollController") + 'show how to support load more list in NestedScrollView\'s body without ScrollController') class LoadMoreDemo extends StatefulWidget { @override _LoadMoreDemoState createState() => _LoadMoreDemoState(); @@ -17,10 +18,11 @@ class LoadMoreDemo extends StatefulWidget { class _LoadMoreDemoState extends State with TickerProviderStateMixin { TabController primaryTC; - GlobalKey _key = GlobalKey(); + final GlobalKey _key = + GlobalKey(); @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); + primaryTC = TabController(length: 2, vsync: this); super.initState(); } @@ -39,24 +41,24 @@ class _LoadMoreDemoState extends State Widget _buildScaffoldBody() { final double statusBarHeight = MediaQuery.of(context).padding.top; - var pinnedHeaderHeight = + final double pinnedHeaderHeight = //statusBar height statusBarHeight + //pinned SliverAppBar height in header kToolbarHeight; return NestedScrollView( key: _key, - headerSliverBuilder: (c, f) { - return [ + headerSliverBuilder: (BuildContext c, bool f) { + return [ SliverAppBar( pinned: true, expandedHeight: 200.0, - title: Text("load more list"), + title: const Text('load more list'), flexibleSpace: FlexibleSpaceBar( //centerTitle: true, collapseMode: CollapseMode.pin, background: Image.asset( - "assets/467141054.jpg", + 'assets/467141054.jpg', fit: BoxFit.fill, ))) ]; @@ -67,7 +69,7 @@ class _LoadMoreDemoState extends State }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; index += primaryTC.index.toString(); @@ -83,17 +85,17 @@ class _LoadMoreDemoState extends State indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs: const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( child: TabBarView( controller: primaryTC, - children: [ - TabViewItem(Key("Tab0")), - TabViewItem(Key("Tab1")), + children: const [ + TabViewItem(Key('Tab0')), + TabViewItem(Key('Tab1')), ], ), ) @@ -106,9 +108,9 @@ class _LoadMoreDemoState extends State class LoadMoreListSource extends LoadingMoreBase { @override Future loadData([bool isloadMoreAction = false]) { - return Future.delayed(Duration(seconds: 1), () { - for (var i = 0; i < 10; i++) { - this.add(0); + return Future.delayed(const Duration(seconds: 1), () { + for (int i = 0; i < 10; i++) { + add(0); } return true; @@ -117,8 +119,8 @@ class LoadMoreListSource extends LoadingMoreBase { } class TabViewItem extends StatefulWidget { + const TabViewItem(this.tabKey); final Key tabKey; - TabViewItem(this.tabKey); @override _TabViewItemState createState() => _TabViewItemState(); } @@ -141,12 +143,12 @@ class _TabViewItemState extends State @override Widget build(BuildContext context) { super.build(context); - var child = LoadingMoreList(ListConfig( - itemBuilder: (c, item, index) { + final LoadingMoreList child = LoadingMoreList(ListConfig( + itemBuilder: (BuildContext c, int item, int index) { return Container( alignment: Alignment.center, height: 60.0, - child: Text(widget.tabKey.toString() + ": ListView$index"), + child: Text(widget.tabKey.toString() + ': ListView$index'), ); }, sourceList: source)); diff --git a/example/lib/pages/main_page.dart b/example/lib/pages/main_page.dart index 1338d7d..6d17142 100644 --- a/example/lib/pages/main_page.dart +++ b/example/lib/pages/main_page.dart @@ -3,31 +3,34 @@ import 'package:ff_annotation_route/ff_annotation_route.dart'; import 'package:url_launcher/url_launcher.dart'; import '../example_route.dart'; +import '../example_routes.dart' as example_routes; @FFRoute( - name: "fluttercandies://mainpage", - routeName: "MainPage", + name: 'fluttercandies://mainpage', + routeName: 'MainPage', ) class MainPage extends StatelessWidget { - final List routes = List(); MainPage() { - routeNames.remove("fluttercandies://mainpage"); + final List routeNames = []; + routeNames.addAll(example_routes.routeNames); + routeNames.remove('fluttercandies://mainpage'); routeNames.remove('fluttercandies://PingLunDemo'); routeNames.remove('fluttercandies://TextFieldPage'); - routes.addAll( - routeNames.map((name) => getRouteResult(name: name))); + routes.addAll(routeNames + .map((String name) => getRouteResult(name: name))); } + final List routes = []; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. - title: Text("ExtendedNestedscrollview"), + title: const Text('ExtendedNestedscrollview'), actions: [ ButtonTheme( minWidth: 0.0, - padding: EdgeInsets.symmetric(horizontal: 10.0), + padding: const EdgeInsets.symmetric(horizontal: 10.0), child: FlatButton( child: Text( 'Github', @@ -38,12 +41,13 @@ class MainPage extends StatelessWidget { ), ), onPressed: () { - launch('https://github.com/fluttercandies/extended_nested_scroll_view'); + launch( + 'https://github.com/fluttercandies/extended_nested_scroll_view'); }, ), ), ButtonTheme( - padding: EdgeInsets.only(right: 10.0), + padding: const EdgeInsets.only(right: 10.0), minWidth: 0.0, child: FlatButton( child: @@ -56,17 +60,17 @@ class MainPage extends StatelessWidget { ], ), body: ListView.builder( - itemBuilder: (c, index) { - var page = routes[index]; + itemBuilder: (BuildContext c, int index) { + final RouteResult page = routes[index]; return Container( - margin: EdgeInsets.all(20.0), + margin: const EdgeInsets.all(20.0), child: GestureDetector( behavior: HitTestBehavior.translucent, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - (index + 1).toString() + "." + page.routeName, + (index + 1).toString() + '.' + page.routeName, //style: TextStyle(inherit: false), ), Text( @@ -76,11 +80,11 @@ class MainPage extends StatelessWidget { ], ), onTap: () { - Navigator.pushNamed(context, routeNames[index]); + Navigator.pushNamed(context, routes[index].name); }, )); }, - itemCount: routeNames.length, + itemCount: routes.length, ), ); } diff --git a/example/lib/pages/pull_to_refresh.dart b/example/lib/pages/pull_to_refresh.dart index b79122e..a34bdf1 100644 --- a/example/lib/pages/pull_to_refresh.dart +++ b/example/lib/pages/pull_to_refresh.dart @@ -1,15 +1,16 @@ +import 'dart:async'; import 'package:example/common/push_to_refresh_header.dart'; import 'package:flutter/material.dart' hide NestedScrollView; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:loading_more_list/loading_more_list.dart'; import 'package:ff_annotation_route/ff_annotation_route.dart'; import 'package:pull_to_refresh_notification/pull_to_refresh_notification.dart'; -import 'dart:async'; + @FFRoute( - name: "fluttercandies://pulltorefresh", - routeName: "pull to refresh", - description: "how to pull to refresh for list in NestedScrollView's body without ScrollController") + name: 'fluttercandies://pulltorefresh', + routeName: 'pull to refresh', + description: 'how to pull to refresh for list in NestedScrollView\'s body without ScrollController') class PullToRefreshDemo extends StatefulWidget { @override _PullToRefreshDemoState createState() => _PullToRefreshDemoState(); @@ -19,11 +20,11 @@ class _PullToRefreshDemoState extends State with TickerProviderStateMixin { TabController primaryTC; int _length1 = 50; - int _length2 = 50; + final int _length2 = 50; DateTime lastRefreshTime = DateTime.now(); @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); + primaryTC = TabController(length: 2, vsync: this); super.initState(); } @@ -42,23 +43,23 @@ class _PullToRefreshDemoState extends State Widget _buildScaffoldBody() { final double statusBarHeight = MediaQuery.of(context).padding.top; - var pinnedHeaderHeight = + final double pinnedHeaderHeight = //statusBar height statusBarHeight + //pinned SliverAppBar height in header kToolbarHeight; return NestedScrollView( - headerSliverBuilder: (c, f) { - return [ + headerSliverBuilder: (BuildContext c, bool f) { + return [ SliverAppBar( pinned: true, expandedHeight: 200.0, - title: Text("pull to refresh in body"), + title: const Text('pull to refresh in body'), flexibleSpace: FlexibleSpaceBar( //centerTitle: true, collapseMode: CollapseMode.pin, background: Image.asset( - "assets/467141054.jpg", + 'assets/467141054.jpg', fit: BoxFit.fill, ))) ]; @@ -69,7 +70,7 @@ class _PullToRefreshDemoState extends State }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; index += primaryTC.index.toString(); @@ -85,9 +86,9 @@ class _PullToRefreshDemoState extends State indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs: const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( @@ -95,12 +96,12 @@ class _PullToRefreshDemoState extends State controller: primaryTC, children: [ NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab0"), + const Key('Tab0'), PullToRefreshNotification( color: Colors.blue, onRefresh: () { - return Future.delayed( - Duration( + return Future.delayed( + const Duration( seconds: 1, ), () { setState(() { @@ -114,24 +115,24 @@ class _PullToRefreshDemoState extends State child: GlowNotificationWidget( Column( children: [ - PullToRefreshContainer((info) { + PullToRefreshContainer((PullToRefreshScrollNotificationInfo info) { return PullToRefreshHeader(info, lastRefreshTime); }), Expanded( child: ListView.builder( //store Page state - key: PageStorageKey("Tab0"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab0'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, - child: Text(Key("Tab0").toString() + - ": ListView$i of $_length1"), + child: Text(const Key('Tab0').toString() + + ': ListView$i of $_length1'), ); }, itemCount: _length1, - padding: EdgeInsets.all(0.0), + padding: const EdgeInsets.all(0.0), ), ) ], @@ -141,12 +142,12 @@ class _PullToRefreshDemoState extends State ), ), NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab1"), + const Key('Tab1'), PullToRefreshNotification( color: Colors.blue, onRefresh: () { - return Future.delayed( - Duration( + return Future.delayed( + const Duration( seconds: 1, ), () { setState(() { @@ -160,24 +161,24 @@ class _PullToRefreshDemoState extends State child: GlowNotificationWidget( Column( children: [ - PullToRefreshContainer((info) { + PullToRefreshContainer((PullToRefreshScrollNotificationInfo info) { return PullToRefreshHeader(info, lastRefreshTime); }), Expanded( child: ListView.builder( //store Page state - key: PageStorageKey("Tab1"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab1'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, - child: Text(Key("Tab1").toString() + - ": ListView$i of $_length2"), + child: Text(const Key('Tab1').toString() + + ': ListView$i of $_length2'), ); }, itemCount: _length2, - padding: EdgeInsets.all(0.0), + padding: const EdgeInsets.all(0.0), ), ) ], diff --git a/example/lib/pages/scroll_to_top.dart b/example/lib/pages/scroll_to_top.dart index 00b606c..bf665aa 100644 --- a/example/lib/pages/scroll_to_top.dart +++ b/example/lib/pages/scroll_to_top.dart @@ -1,14 +1,14 @@ import 'package:example/common/common.dart'; -import 'package:flutter/material.dart' hide NestedScrollView; +import 'package:flutter/material.dart' hide NestedScrollView,NestedScrollViewState; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:loading_more_list/loading_more_list.dart'; import 'package:ff_annotation_route/ff_annotation_route.dart'; @FFRoute( - name: "fluttercandies://scroll to top", - routeName: "scroll to top", + name: 'fluttercandies://scroll to top', + routeName: 'scroll to top', description: - "how to scroll list to top in NestedScrollView's body without ScrollController") + 'how to scroll list to top in NestedScrollView\'s body without ScrollController') class ScrollToTopDemo extends StatefulWidget { @override _ScrollToTopDemoState createState() => _ScrollToTopDemoState(); @@ -17,10 +17,10 @@ class ScrollToTopDemo extends StatefulWidget { class _ScrollToTopDemoState extends State with TickerProviderStateMixin { TabController primaryTC; - GlobalKey _key = GlobalKey(); + final GlobalKey _key = GlobalKey(); @override void initState() { - primaryTC = new TabController(length: 2, vsync: this); + primaryTC = TabController(length: 2, vsync: this); super.initState(); } @@ -39,7 +39,7 @@ class _ScrollToTopDemoState extends State onPressed: () { ///scroll current tab list _key.currentState.currentInnerPosition.animateTo(0.0, - duration: Duration(seconds: 1), curve: Curves.easeIn); + duration: const Duration(seconds: 1), curve: Curves.easeIn); ///scroll all tab list // _key.currentState.innerScrollPositions.forEach((position) { @@ -53,7 +53,7 @@ class _ScrollToTopDemoState extends State Widget _buildScaffoldBody() { final double statusBarHeight = MediaQuery.of(context).padding.top; - var pinnedHeaderHeight = + final double pinnedHeaderHeight = //statusBar height statusBarHeight + //pinned SliverAppBar height in header @@ -62,17 +62,17 @@ class _ScrollToTopDemoState extends State onRefresh: onRefresh, child: NestedScrollView( key: _key, - headerSliverBuilder: (c, f) { - return [ + headerSliverBuilder: (BuildContext c, bool f) { + return [ SliverAppBar( pinned: true, expandedHeight: 200.0, - title: Text("scroll to top"), + title: const Text('scroll to top'), flexibleSpace: FlexibleSpaceBar( //centerTitle: true, collapseMode: CollapseMode.pin, background: Image.asset( - "assets/467141054.jpg", + 'assets/467141054.jpg', fit: BoxFit.fill, ))) ]; @@ -83,7 +83,7 @@ class _ScrollToTopDemoState extends State }, //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868) innerScrollPositionKeyBuilder: () { - var index = "Tab"; + String index = 'Tab'; index += primaryTC.index.toString(); @@ -99,9 +99,9 @@ class _ScrollToTopDemoState extends State indicatorWeight: 2.0, isScrollable: false, unselectedLabelColor: Colors.grey, - tabs: [ - Tab(text: "Tab0"), - Tab(text: "Tab1"), + tabs:const [ + Tab(text: 'Tab0'), + Tab(text: 'Tab1'), ], ), Expanded( @@ -109,18 +109,18 @@ class _ScrollToTopDemoState extends State controller: primaryTC, children: [ NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab0"), + const Key('Tab0'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab0"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab0'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, child: - Text(Key("Tab0").toString() + ": ListView$i"), + Text(const Key('Tab0').toString() + ': ListView$i'), ); }, itemCount: 50, @@ -129,18 +129,18 @@ class _ScrollToTopDemoState extends State ), ), NestedScrollViewInnerScrollPositionKeyWidget( - Key("Tab1"), + const Key('Tab1'), GlowNotificationWidget( ListView.builder( //store Page state - key: PageStorageKey("Tab1"), - physics: ClampingScrollPhysics(), - itemBuilder: (c, i) { + key: const PageStorageKey('Tab1'), + physics: const ClampingScrollPhysics(), + itemBuilder: (BuildContext c, int i) { return Container( alignment: Alignment.center, height: 60.0, child: - Text(Key("Tab1").toString() + ": ListView$i"), + Text(const Key('Tab1').toString() + ': ListView$i'), ); }, itemCount: 50, diff --git a/example/lib/see_your_widget_demo.dart b/example/lib/see_your_widget_demo.dart index cbc6e42..66840de 100644 --- a/example/lib/see_your_widget_demo.dart +++ b/example/lib/see_your_widget_demo.dart @@ -1,32 +1,32 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -void main() => runApp(new MyApp()); +void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override - State createState() => new MyAppState(); + State createState() => MyAppState(); } const double itemHeight = 100.0; class MyAppState extends State { - GlobalKey key = new GlobalKey(); + GlobalKey key = GlobalKey(); bool widgetIn = false; @override Widget build(BuildContext context) { - return new MaterialApp( - home: new Scaffold( - appBar: new AppBar( - title: new Text("Check whether I'm in"), + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Check whether I\'m in'), ), body: NotificationListener( - child: new ListView( + child: ListView( itemExtent: itemHeight, - children: [ + children: [ YourWidget(), YourWidget(), YourWidget(), @@ -46,11 +46,13 @@ class MyAppState extends State { ], ), onNotification: (ScrollNotification scroll) { - var currentContext = key.currentContext; - if (currentContext == null) return false; + final BuildContext currentContext = key.currentContext; + if (currentContext == null) { + return false; + } //final double screenHeight = MediaQuery.of(currentContext).size.height; - var renderObject = currentContext.findRenderObject(); - RenderAbstractViewport viewport = + final RenderObject renderObject = currentContext.findRenderObject(); + final RenderAbstractViewport viewport = RenderAbstractViewport.of(renderObject); /// The `alignment` argument describes where the target should be positioned @@ -61,17 +63,17 @@ class MyAppState extends State { /// positioned as close to the center of the viewport as possible. /// Distance between top edge of screen and MyWidget bottom edge - var offsetToRevealLeading = + final RevealedOffset offsetToRevealLeading = viewport.getOffsetToReveal(renderObject, 0.0); /// Distance between bottom edge of screen and MyWidget top edge - var offsetToRevealTrailingEdge = + final RevealedOffset offsetToRevealTrailingEdge = viewport.getOffsetToReveal(renderObject, 1.0); print( - " ${scroll.metrics.pixels} ${offsetToRevealLeading.offset} ${offsetToRevealTrailingEdge.offset}"); + ' ${scroll.metrics.pixels} ${offsetToRevealLeading.offset} ${offsetToRevealTrailingEdge.offset}'); - var offset = scroll.metrics.pixels; + final double offset = scroll.metrics.pixels; //in // if (offsetToRevealTrailingEdge.offset <= offset + itemHeight && @@ -95,9 +97,9 @@ class MyAppState extends State { return false; }, ), - floatingActionButton: new FloatingActionButton( + floatingActionButton: FloatingActionButton( child: Container( - child: Text(widgetIn ? "I see you " : "bye bye"), + child: Text(widgetIn ? 'I see you ' : 'bye bye'), height: 200.0, width: 200.0, alignment: Alignment.center, @@ -113,22 +115,22 @@ class MyWidget extends StatefulWidget { const MyWidget({Key key}) : super(key: key); @override - State createState() => new MyWidgetState(); + State createState() => MyWidgetState(); } class MyWidgetState extends State { @override Widget build(BuildContext context) { - return new Container(height: itemHeight, color: Colors.red); + return Container(height: itemHeight, color: Colors.red); } } class YourWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return new Container( + return Container( decoration: - new BoxDecoration(border: new Border.all(), color: Colors.grey), + BoxDecoration(border: Border.all(), color: Colors.grey), ); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index d799dc2..28b48e4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -10,7 +10,8 @@ description: A new Flutter application. version: 1.0.0+1 environment: - sdk: ">=2.2.0-dev.68.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" + flutter: ">=1.17.0" dependencies: flutter: diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 747db1d..0000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/lib/extended_nested_scroll_view.dart b/lib/extended_nested_scroll_view.dart index 5d55dd4..071071b 100644 --- a/lib/extended_nested_scroll_view.dart +++ b/lib/extended_nested_scroll_view.dart @@ -1,7 +1,7 @@ library extended_nested_scroll_view; -export 'src/old_extended_nested_scroll_view.dart'; //export 'src/extended_nested_scroll_view.dart'; -export 'src/nested_scroll_view_refresh_indicator.dart'; export 'src/nested_scroll_view_inner_scroll_position_key_widget.dart'; +export 'src/nested_scroll_view_refresh_indicator.dart'; +export 'src/old_extended_nested_scroll_view.dart'; export 'src/util.dart'; diff --git a/lib/src/extended_nested_scroll_view.dart b/lib/src/extended_nested_scroll_view.dart index 71d22bd..17be0e2 100644 --- a/lib/src/extended_nested_scroll_view.dart +++ b/lib/src/extended_nested_scroll_view.dart @@ -1,1551 +1,1556 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:math' as math; - -//import 'package:extended_nested_scroll_view/src/nested_scroll_view_inner_scroll_position_key_widget.dart'; -//import 'package:extended_nested_scroll_view/src/util.dart'; -//import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' -// as extend; -import 'package:flutter/gestures.dart'; -import 'package:flutter/painting.dart'; -import 'package:flutter/physics.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter/widgets.dart'; - -// Examples can assume: -// List _tabs; - -/// Signature used by [ExtendedNestedScrollView] for building its header. -/// -/// The `innerBoxIsScrolled` argument is typically used to control the -/// [SliverAppBar.forceElevated] property to ensure that the app bar shows a -/// shadow, since it would otherwise not necessarily be aware that it had -/// content ostensibly below it. - -//it include statusBarHeight ,pinned appbar height ,pinned SliverPersistentHeader height -//which are in NestedScrollViewHeaderSlivers -typedef ExtendedNestedScrollViewPinnedHeaderSliverHeightBuilder = double - Function(); - -/// A scrolling view inside of which can be nested other scrolling views, with -/// their scroll positions being intrinsically linked. -/// -/// The most common use case for this widget is a scrollable view with a -/// flexible [SliverAppBar] containing a [TabBar] in the header (build by -/// [headerSliverBuilder], and with a [TabBarView] in the [body], such that the -/// scrollable view's contents vary based on which tab is visible. -/// -/// ## Motivation -/// -/// In a normal [ScrollView], there is one set of slivers (the components of the -/// scrolling view). If one of those slivers hosted a [TabBarView] which scrolls -/// in the opposite direction (e.g. allowing the user to swipe horizontally -/// between the pages represented by the tabs, while the list scrolls -/// vertically), then any list inside that [TabBarView] would not interact with -/// the outer [ScrollView]. For example, flinging the inner list to scroll to -/// the top would not cause a collapsed [SliverAppBar] in the outer [ScrollView] -/// to expand. -/// -/// [ExtendedNestedScrollView] solves this problem by providing custom -/// [ScrollController]s for the outer [ScrollView] and the inner [ScrollView]s -/// (those inside the [TabBarView], hooking them together so that they appear, -/// to the user, as one coherent scroll view. -/// -/// {@tool sample} -/// -/// This example shows a [ExtendedNestedScrollView] whose header is the combination of a -/// [TabBar] in a [SliverAppBar] and whose body is a [TabBarView]. It uses a -/// [SliverOverlapAbsorber]/[SliverOverlapInjector] pair to make the inner lists -/// align correctly, and it uses [SafeArea] to avoid any horizontal disturbances -/// (e.g. the "notch" on iOS when the phone is horizontal). In addition, -/// [PageStorageKey]s are used to remember the scroll position of each tab's -/// list. -/// -/// In the example below, `_tabs` is a list of strings, one for each tab, giving -/// the tab labels. In a real application, it would be replaced by the actual -/// data model being represented. -/// -/// ```dart -/// DefaultTabController( -/// length: _tabs.length, // This is the number of tabs. -/// child: NestedScrollView( -/// headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { -/// // These are the slivers that show up in the "outer" scroll view. -/// return [ -/// SliverOverlapAbsorber( -/// // This widget takes the overlapping behavior of the SliverAppBar, -/// // and redirects it to the SliverOverlapInjector below. If it is -/// // missing, then it is possible for the nested "inner" scroll view -/// // below to end up under the SliverAppBar even when the inner -/// // scroll view thinks it has not been scrolled. -/// // This is not necessary if the "headerSliverBuilder" only builds -/// // widgets that do not overlap the next sliver. -/// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), -/// child: SliverAppBar( -/// title: const Text('Books'), // This is the title in the app bar. -/// pinned: true, -/// expandedHeight: 150.0, -/// // The "forceElevated" property causes the SliverAppBar to show -/// // a shadow. The "innerBoxIsScrolled" parameter is true when the -/// // inner scroll view is scrolled beyond its "zero" point, i.e. -/// // when it appears to be scrolled below the SliverAppBar. -/// // Without this, there are cases where the shadow would appear -/// // or not appear inappropriately, because the SliverAppBar is -/// // not actually aware of the precise position of the inner -/// // scroll views. -/// forceElevated: innerBoxIsScrolled, -/// bottom: TabBar( -/// // These are the widgets to put in each tab in the tab bar. -/// tabs: _tabs.map((String name) => Tab(text: name)).toList(), -/// ), -/// ), -/// ), -/// ]; -/// }, -/// body: TabBarView( -/// // These are the contents of the tab views, below the tabs. -/// children: _tabs.map((String name) { -/// return SafeArea( -/// top: false, -/// bottom: false, -/// child: Builder( -/// // This Builder is needed to provide a BuildContext that is "inside" -/// // the NestedScrollView, so that sliverOverlapAbsorberHandleFor() can -/// // find the NestedScrollView. -/// builder: (BuildContext context) { -/// return CustomScrollView( -/// // The "controller" and "primary" members should be left -/// // unset, so that the NestedScrollView can control this -/// // inner scroll view. -/// // If the "controller" property is set, then this scroll -/// // view will not be associated with the NestedScrollView. -/// // The PageStorageKey should be unique to this ScrollView; -/// // it allows the list to remember its scroll position when -/// // the tab view is not on the screen. -/// key: PageStorageKey(name), -/// slivers: [ -/// SliverOverlapInjector( -/// // This is the flip side of the SliverOverlapAbsorber above. -/// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), -/// ), -/// SliverPadding( -/// padding: const EdgeInsets.all(8.0), -/// // In this example, the inner scroll view has -/// // fixed-height list items, hence the use of -/// // SliverFixedExtentList. However, one could use any -/// // sliver widget here, e.g. SliverList or SliverGrid. -/// sliver: SliverFixedExtentList( -/// // The items in this example are fixed to 48 pixels -/// // high. This matches the Material Design spec for -/// // ListTile widgets. -/// itemExtent: 48.0, -/// delegate: SliverChildBuilderDelegate( -/// (BuildContext context, int index) { -/// // This builder is called for each child. -/// // In this example, we just number each list item. -/// return ListTile( -/// title: Text('Item $index'), -/// ); -/// }, -/// // The childCount of the SliverChildBuilderDelegate -/// // specifies how many children this inner list -/// // has. In this example, each tab has a list of -/// // exactly 30 items, but this is arbitrary. -/// childCount: 30, -/// ), -/// ), -/// ), -/// ], -/// ); -/// }, -/// ), -/// ); -/// }).toList(), -/// ), -/// ), -/// ) -/// ``` -/// {@end-tool} -class ExtendedNestedScrollView extends StatefulWidget { - /// Creates a nested scroll view. - /// - /// The [reverse], [headerSliverBuilder], and [body] arguments must not be - /// null. - const ExtendedNestedScrollView({ - Key key, - this.controller, - this.scrollDirection = Axis.vertical, - this.reverse = false, - this.physics, - this.pinnedHeaderSliverHeightBuilder, - this.pinnedHeaderSliverHeight, - this.keepOnlyOneInnerNestedScrollPositionActive: false, - @required this.headerSliverBuilder, - @required this.body, - }) : assert(false, - "new ExtendedNestedScrollView still has some issues in special layout, make it as obsolete for now till find a better solution"), - assert(scrollDirection != null), - assert(reverse != null), - assert(headerSliverBuilder != null), - assert(body != null), - - ///don't use them at the same time - assert(!(pinnedHeaderSliverHeight != null && - pinnedHeaderSliverHeightBuilder != null)), - super(key: key); - - ///get the pinned header in NestedScrollView header. - ///if your pinned header will changed, use this instead of [pinnedHeaderSliverHeight] - final ExtendedNestedScrollViewPinnedHeaderSliverHeightBuilder - pinnedHeaderSliverHeightBuilder; - - ///if your pinned header will not changed, use this instead of [pinnedHeaderSliverHeightBuilder] - final double pinnedHeaderSliverHeight; - - ///when ExtendedNestedScrollView body has [TabBarView]/[PageView] and children have - ///AutomaticKeepAliveClientMixin or PageStorageKey, - ///[_innerController.nestedPositions] will have more one, - ///when you scroll, it will scroll all of nestedPositions - ///set [keepOnlyOneInnerNestedScrollPositionActive] true to avoid it. - ///notice: only for Axis.horizontal PageView/TabBarView and - ///[scrollDirection] must be Axis.vertical. - final bool keepOnlyOneInnerNestedScrollPositionActive; - - /// An object that can be used to control the position to which the outer - /// scroll view is scrolled. - final ScrollController controller; - - /// The axis along which the scroll view scrolls. - /// - /// Defaults to [Axis.vertical]. - final Axis scrollDirection; - - /// Whether the scroll view scrolls in the reading direction. - /// - /// For example, if the reading direction is left-to-right and - /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from - /// left to right when [reverse] is false and from right to left when - /// [reverse] is true. - /// - /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view - /// scrolls from top to bottom when [reverse] is false and from bottom to top - /// when [reverse] is true. - /// - /// Defaults to false. - final bool reverse; - - /// How the scroll view should respond to user input. - /// - /// For example, determines how the scroll view continues to animate after the - /// user stops dragging the scroll view (providing a custom implementation of - /// [ScrollPhysics.createBallisticSimulation] allows this particular aspect of - /// the physics to be overridden). - /// - /// Defaults to matching platform conventions. - /// - /// The [ScrollPhysics.applyBoundaryConditions] implementation of the provided - /// object should not allow scrolling outside the scroll extent range - /// described by the [ScrollMetrics.minScrollExtent] and - /// [ScrollMetrics.maxScrollExtent] properties passed to that method. If that - /// invariant is not maintained, the nested scroll view may respond to user - /// scrolling erratically. - final ScrollPhysics physics; - - /// A builder for any widgets that are to precede the inner scroll views (as - /// given by [body]). - /// - /// Typically this is used to create a [SliverAppBar] with a [TabBar]. - final NestedScrollViewHeaderSliversBuilder headerSliverBuilder; - - /// The widget to show inside the [ExtendedNestedScrollView]. - /// - /// Typically this will be [TabBarView]. - /// - /// The [body] is built in a context that provides a [PrimaryScrollController] - /// that interacts with the [ExtendedNestedScrollView]'s scroll controller. Any - /// [ListView] or other [Scrollable]-based widget inside the [body] that is - /// intended to scroll with the [ExtendedNestedScrollView] should therefore not be - /// given an explicit [ScrollController], instead allowing it to default to - /// the [PrimaryScrollController] provided by the [ExtendedNestedScrollView]. - final Widget body; - - /// Returns the [SliverOverlapAbsorberHandle] of the nearest ancestor - /// [ExtendedNestedScrollView]. - /// - /// This is necessary to configure the [SliverOverlapAbsorber] and - /// [SliverOverlapInjector] widgets. - /// - /// For sample code showing how to use this method, see the [ExtendedNestedScrollView] - /// documentation. - static SliverOverlapAbsorberHandle sliverOverlapAbsorberHandleFor( - BuildContext context) { - final _InheritedNestedScrollView target = context - .dependOnInheritedWidgetOfExactType<_InheritedNestedScrollView>(); - assert(target != null, - 'NestedScrollView.sliverOverlapAbsorberHandleFor must be called with a context that contains a NestedScrollView.'); - return target.state._absorberHandle; - } - -// List _buildSlivers(BuildContext context, -// ScrollController innerController, bool bodyIsScrolled) { -// final List slivers = []; -// slivers.addAll(headerSliverBuilder(context, bodyIsScrolled)); -// slivers.add( -// SliverFillRemaining( -// child: PrimaryScrollController( -// controller: innerController, -// child: body, -// ), -// )); -// return slivers; -// } - - @override - _ExtendedNestedScrollViewState createState() => - _ExtendedNestedScrollViewState(); -} - -class _ExtendedNestedScrollViewState extends State { - final SliverOverlapAbsorberHandle _absorberHandle = - SliverOverlapAbsorberHandle(); - - _NestedScrollCoordinator _coordinator; - - @override - void initState() { - ///when ExtendedNestedScrollView body has [TabBarView]/[PageView] and children have - ///AutomaticKeepAliveClientMixin or PageStorageKey, - ///[_innerController.nestedPositions] will have more one, - ///when you scroll, it will scroll all of nestedPositions - ///set [keepOnlyOneInnerNestedScrollPositionActive] true to avoid it. - ///notice: only for Axis.horizontal [TabBarView]/[PageView] and - ///[scrollDirection] must be Axis.vertical. - assert(!(widget.keepOnlyOneInnerNestedScrollPositionActive && - widget.scrollDirection == Axis.horizontal)); - - super.initState(); - _coordinator = _NestedScrollCoordinator( - this, widget.controller, _handleHasScrolledBodyChanged); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _coordinator.setParent(widget.controller); - } - - @override - void didUpdateWidget(ExtendedNestedScrollView oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.controller != widget.controller) - _coordinator.setParent(widget.controller); - } - - @override - void dispose() { - _coordinator.dispose(); - _coordinator = null; - super.dispose(); - } - - bool _lastHasScrolledBody; - - void _handleHasScrolledBodyChanged() { - if (!mounted) return; - final bool newHasScrolledBody = _coordinator.hasScrolledBody; - if (_lastHasScrolledBody != newHasScrolledBody) { - setState(() { - // _coordinator.hasScrolledBody changed (we use it in the build method) - // (We record _lastHasScrolledBody in the build() method, rather than in - // this setState call, because the build() method may be called more - // often than just from here, and we want to only call setState when the - // new value is different than the last built value.) - }); - } - } - - @override - Widget build(BuildContext context) { - var child = _InheritedNestedScrollView( - state: this, - child: Builder( - builder: (BuildContext context) { - _lastHasScrolledBody = _coordinator.hasScrolledBody; - return _NestedScrollViewCustomScrollView( - scrollDirection: widget.scrollDirection, - reverse: widget.reverse, - physics: widget.physics != null - ? widget.physics.applyTo(const ClampingScrollPhysics()) - : const ClampingScrollPhysics(), - controller: _coordinator._outerController, - slivers: _buildSlivers( - context, - _coordinator._innerController, - _lastHasScrolledBody, - ), - handle: _absorberHandle, - ); - }, - ), - ); - return child; - } - - ///zmt - List _buildSlivers(BuildContext context, - ScrollController innerController, bool bodyIsScrolled) { - final List slivers = []; - slivers.addAll(widget.headerSliverBuilder(context, bodyIsScrolled)); - - Widget body = widget.body; - - if (widget.keepOnlyOneInnerNestedScrollPositionActive) { - ///get notifications and compute active one in _innerController.nestedPositions - body = NotificationListener( - onNotification: (ScrollNotification notification) { - if (((notification is ScrollEndNotification) || - (notification is UserScrollNotification && - notification.direction == ScrollDirection.idle)) && - notification.metrics is PageMetrics && - notification.metrics.axis == Axis.horizontal) { - _coordinator._innerController - ._computeActivatedNestedPosition(notification); - } - return false; - }, - child: body); - } - - slivers.add(SliverFillRemaining( - child: PrimaryScrollController( - controller: innerController, - child: body, - ), - )); - return slivers; - } -} - -class _NestedScrollViewCustomScrollView extends CustomScrollView { - const _NestedScrollViewCustomScrollView({ - @required Axis scrollDirection, - @required bool reverse, - @required ScrollPhysics physics, - @required ScrollController controller, - @required List slivers, - @required this.handle, - }) : super( - scrollDirection: scrollDirection, - reverse: reverse, - physics: physics, - controller: controller, - slivers: slivers, - ); - - final SliverOverlapAbsorberHandle handle; - - @override - Widget buildViewport( - BuildContext context, - ViewportOffset offset, - AxisDirection axisDirection, - List slivers, - ) { - assert(!shrinkWrap); - return NestedScrollViewViewport( - axisDirection: axisDirection, - offset: offset, - slivers: slivers, - handle: handle, - ); - } -} - -class _InheritedNestedScrollView extends InheritedWidget { - const _InheritedNestedScrollView({ - Key key, - @required this.state, - @required Widget child, - }) : assert(state != null), - assert(child != null), - super(key: key, child: child); - - final _ExtendedNestedScrollViewState state; - - @override - bool updateShouldNotify(_InheritedNestedScrollView old) => state != old.state; -} - -class _NestedScrollMetrics extends FixedScrollMetrics { - _NestedScrollMetrics({ - @required double minScrollExtent, - @required double maxScrollExtent, - @required double pixels, - @required double viewportDimension, - @required AxisDirection axisDirection, - @required this.minRange, - @required this.maxRange, - @required this.correctionOffset, - }) : super( - minScrollExtent: minScrollExtent, - maxScrollExtent: maxScrollExtent, - pixels: pixels, - viewportDimension: viewportDimension, - axisDirection: axisDirection, - ); - - @override - _NestedScrollMetrics copyWith({ - double minScrollExtent, - double maxScrollExtent, - double pixels, - double viewportDimension, - AxisDirection axisDirection, - double minRange, - double maxRange, - double correctionOffset, - }) { - return _NestedScrollMetrics( - minScrollExtent: minScrollExtent ?? this.minScrollExtent, - maxScrollExtent: maxScrollExtent ?? this.maxScrollExtent, - pixels: pixels ?? this.pixels, - viewportDimension: viewportDimension ?? this.viewportDimension, - axisDirection: axisDirection ?? this.axisDirection, - minRange: minRange ?? this.minRange, - maxRange: maxRange ?? this.maxRange, - correctionOffset: correctionOffset ?? this.correctionOffset, - ); - } - - final double minRange; - - final double maxRange; - - final double correctionOffset; -} - -typedef _NestedScrollActivityGetter = ScrollActivity Function( - _NestedScrollPosition position); - -class _NestedScrollCoordinator - implements ScrollActivityDelegate, ScrollHoldController { - _NestedScrollCoordinator( - this._state, this._parent, this._onHasScrolledBodyChanged) { - final double initialScrollOffset = _parent?.initialScrollOffset ?? 0.0; - _outerController = _NestedScrollController(this, - initialScrollOffset: initialScrollOffset, debugLabel: 'outer'); - _innerController = _NestedScrollController(this, - initialScrollOffset: 0.0, debugLabel: 'inner'); - } - - final _ExtendedNestedScrollViewState _state; - ScrollController _parent; - final VoidCallback _onHasScrolledBodyChanged; - - _NestedScrollController _outerController; - _NestedScrollController _innerController; - - _NestedScrollPosition get _outerPosition { - if (!_outerController.hasClients) return null; - return _outerController.nestedPositions.single; - } - - ///zmt - ///scroll only for actived one - Iterable<_NestedScrollPosition> get _activedInnerPositions { - var list = _innerController.nestedPositions; - if (_state.widget.keepOnlyOneInnerNestedScrollPositionActive && - list.length > 1) { - var temp = list.where((item) { - return item._isActived; - }); -// -// if (temp.length == 0 && -// _innerController.prePageChangedRenderBox != null) { -// _innerController._computeActivatedNestedPosition(null); -// temp = list.where((item) { -// return item._isActived; -// }); -// } - - if (temp.length != 1) { - return list; - } - return temp; - } - return list; - } - - Iterable<_NestedScrollPosition> get _innerPositions { - return _innerController.nestedPositions; - } - - bool get canScrollBody { - final _NestedScrollPosition outer = _outerPosition; - if (outer == null) return true; - return outer.haveDimensions && outer.extentAfter == 0.0; - } - - bool get hasScrolledBody { - for (_NestedScrollPosition position in _activedInnerPositions) { - if (position.pixels > position.minScrollExtent) return true; - } - return false; - } - - void updateShadow() { - if (_onHasScrolledBodyChanged != null) _onHasScrolledBodyChanged(); - } - - ScrollDirection get userScrollDirection => _userScrollDirection; - ScrollDirection _userScrollDirection = ScrollDirection.idle; - - void updateUserScrollDirection(ScrollDirection value) { - assert(value != null); - if (userScrollDirection == value) return; - _userScrollDirection = value; - _outerPosition.didUpdateScrollDirection(value); - for (_NestedScrollPosition position in _innerPositions) - position.didUpdateScrollDirection(value); - } - - ScrollDragController _currentDrag; - - void beginActivity(ScrollActivity newOuterActivity, - _NestedScrollActivityGetter innerActivityGetter) { - _outerPosition.beginActivity(newOuterActivity); - bool scrolling = newOuterActivity.isScrolling; - for (_NestedScrollPosition position in _activedInnerPositions) { - final ScrollActivity newInnerActivity = innerActivityGetter(position); - position.beginActivity(newInnerActivity); - scrolling = scrolling && newInnerActivity.isScrolling; - } - _currentDrag?.dispose(); - _currentDrag = null; - if (!scrolling) updateUserScrollDirection(ScrollDirection.idle); - } - - @override - AxisDirection get axisDirection => _outerPosition.axisDirection; - - static IdleScrollActivity _createIdleScrollActivity( - _NestedScrollPosition position) { - return IdleScrollActivity(position); - } - - @override - void goIdle() { - beginActivity( - _createIdleScrollActivity(_outerPosition), _createIdleScrollActivity); - } - - @override - void goBallistic(double velocity) { - beginActivity( - createOuterBallisticScrollActivity(velocity), - (_NestedScrollPosition position) => - createInnerBallisticScrollActivity(position, velocity), - ); - } - - ScrollActivity createOuterBallisticScrollActivity(double velocity) { - // This function creates a ballistic scroll for the outer scrollable. - // - // It assumes that the outer scrollable can't be overscrolled, and sets up a - // ballistic scroll over the combined space of the innerPositions and the - // outerPosition. - - // First we must pick a representative inner position that we will care - // about. This is somewhat arbitrary. Ideally we'd pick the one that is "in - // the center" but there isn't currently a good way to do that so we - // arbitrarily pick the one that is the furthest away from the infinity we - // are heading towards. - _NestedScrollPosition innerPosition; - if (velocity != 0.0) { - for (_NestedScrollPosition position in _activedInnerPositions) { - if (innerPosition != null) { - if (velocity > 0.0) { - if (innerPosition.pixels < position.pixels) continue; - } else { - assert(velocity < 0.0); - if (innerPosition.pixels > position.pixels) continue; - } - } - innerPosition = position; - } - } - - if (innerPosition == null) { - // It's either just us or a velocity=0 situation. - return _outerPosition.createBallisticScrollActivity( - _outerPosition.physics - .createBallisticSimulation(_outerPosition, velocity), - mode: _NestedBallisticScrollActivityMode.independent, - ); - } - - final _NestedScrollMetrics metrics = _getMetrics(innerPosition, velocity); - - return _outerPosition.createBallisticScrollActivity( - _outerPosition.physics.createBallisticSimulation(metrics, velocity), - mode: _NestedBallisticScrollActivityMode.outer, - metrics: metrics, - ); - } - - @protected - ScrollActivity createInnerBallisticScrollActivity( - _NestedScrollPosition position, double velocity) { - return position.createBallisticScrollActivity( - position.physics.createBallisticSimulation( - velocity == 0 ? position : _getMetrics(position, velocity), - velocity, - ), - mode: _NestedBallisticScrollActivityMode.inner, - ); - } - - _NestedScrollMetrics _getMetrics( - _NestedScrollPosition innerPosition, double velocity) { - assert(innerPosition != null); - double pixels, minRange, maxRange, correctionOffset, extra; - if (innerPosition.pixels == innerPosition.minScrollExtent) { - pixels = _outerPosition.pixels.clamp( - _outerPosition.minScrollExtent, - _outerPosition - .maxScrollExtent); // TODO(ianh): gracefully handle out-of-range outer positions - minRange = _outerPosition.minScrollExtent; - maxRange = _outerPosition.maxScrollExtent; - assert(minRange <= maxRange); - correctionOffset = 0.0; - extra = 0.0; - } else { - assert(innerPosition.pixels != innerPosition.minScrollExtent); - if (innerPosition.pixels < innerPosition.minScrollExtent) { - pixels = innerPosition.pixels - - innerPosition.minScrollExtent + - _outerPosition.minScrollExtent; - } else { - assert(innerPosition.pixels > innerPosition.minScrollExtent); - pixels = innerPosition.pixels - - innerPosition.minScrollExtent + - _outerPosition.maxScrollExtent; - } - if ((velocity > 0.0) && - (innerPosition.pixels > innerPosition.minScrollExtent)) { - // This handles going forward (fling up) and inner list is scrolled past - // zero. We want to grab the extra pixels immediately to shrink. - extra = _outerPosition.maxScrollExtent - _outerPosition.pixels; - assert(extra >= 0.0); - minRange = pixels; - maxRange = pixels + extra; - assert(minRange <= maxRange); - correctionOffset = _outerPosition.pixels - pixels; - } else if ((velocity < 0.0) && - (innerPosition.pixels < innerPosition.minScrollExtent)) { - // This handles going backward (fling down) and inner list is - // underscrolled. We want to grab the extra pixels immediately to grow. - extra = _outerPosition.pixels - _outerPosition.minScrollExtent; - assert(extra >= 0.0); - minRange = pixels - extra; - maxRange = pixels; - assert(minRange <= maxRange); - correctionOffset = _outerPosition.pixels - pixels; - } else { - // This handles going forward (fling up) and inner list is - // underscrolled, OR, going backward (fling down) and inner list is - // scrolled past zero. We want to skip the pixels we don't need to grow - // or shrink over. - if (velocity > 0.0) { - // shrinking - extra = _outerPosition.minScrollExtent - _outerPosition.pixels; - } else { - assert(velocity < 0.0); - // growing - extra = _outerPosition.pixels - - (_outerPosition.maxScrollExtent - _outerPosition.minScrollExtent); - } - assert(extra <= 0.0); - minRange = _outerPosition.minScrollExtent; - maxRange = _outerPosition.maxScrollExtent + extra; - assert(minRange <= maxRange); - correctionOffset = 0.0; - } - } - return _NestedScrollMetrics( - minScrollExtent: _outerPosition.minScrollExtent, - maxScrollExtent: _outerPosition.maxScrollExtent + - innerPosition.maxScrollExtent - - innerPosition.minScrollExtent + - extra, - pixels: pixels, - viewportDimension: _outerPosition.viewportDimension, - axisDirection: _outerPosition.axisDirection, - minRange: minRange, - maxRange: maxRange, - correctionOffset: correctionOffset, - ); - } - - double unnestOffset(double value, _NestedScrollPosition source) { - if (source == _outerPosition) - return value.clamp( - _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); - if (value < source.minScrollExtent) - return value - source.minScrollExtent + _outerPosition.minScrollExtent; - return value - source.minScrollExtent + _outerPosition.maxScrollExtent; - } - - double nestOffset(double value, _NestedScrollPosition target) { - if (target == _outerPosition) - return value.clamp( - _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); - if (value < _outerPosition.minScrollExtent) - return value - _outerPosition.minScrollExtent + target.minScrollExtent; - if (value > _outerPosition.maxScrollExtent) - return value - _outerPosition.maxScrollExtent + target.minScrollExtent; - return target.minScrollExtent; - } - - void updateCanDrag() { - if (!_outerPosition.haveDimensions) return; - double maxInnerExtent = 0.0; - for (_NestedScrollPosition position in _activedInnerPositions) { - if (!position.haveDimensions) return; - maxInnerExtent = math.max( - maxInnerExtent, position.maxScrollExtent - position.minScrollExtent); - } - _outerPosition.updateCanDrag(maxInnerExtent); - } - - Future animateTo( - double to, { - @required Duration duration, - @required Curve curve, - }) async { - final DrivenScrollActivity outerActivity = - _outerPosition.createDrivenScrollActivity( - nestOffset(to, _outerPosition), - duration, - curve, - ); - final List> resultFutures = >[outerActivity.done]; - beginActivity( - outerActivity, - (_NestedScrollPosition position) { - final DrivenScrollActivity innerActivity = - position.createDrivenScrollActivity( - nestOffset(to, position), - duration, - curve, - ); - resultFutures.add(innerActivity.done); - return innerActivity; - }, - ); - await Future.wait(resultFutures); - } - - void jumpTo(double to) { - goIdle(); - _outerPosition.localJumpTo(nestOffset(to, _outerPosition)); - for (_NestedScrollPosition position in _activedInnerPositions) - position.localJumpTo(nestOffset(to, position)); - goBallistic(0.0); - } - - @override - double setPixels(double newPixels) { - assert(false); - return 0.0; - } - - ScrollHoldController hold(VoidCallback holdCancelCallback) { - beginActivity( - HoldScrollActivity( - delegate: _outerPosition, onHoldCanceled: holdCancelCallback), - (_NestedScrollPosition position) => - HoldScrollActivity(delegate: position), - ); - return this; - } - - @override - void cancel() { - goBallistic(0.0); - } - - Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) { - final ScrollDragController drag = ScrollDragController( - delegate: this, - details: details, - onDragCanceled: dragCancelCallback, - ); - beginActivity( - DragScrollActivity(_outerPosition, drag), - (_NestedScrollPosition position) => DragScrollActivity(position, drag), - ); - assert(_currentDrag == null); - _currentDrag = drag; - return drag; - } - - @override - - ///zmt - void applyUserOffset(double delta) { - updateUserScrollDirection( - delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse); - assert(delta != 0.0); - if (_innerPositions.isEmpty) { - _outerPosition.applyFullDragUpdate(delta); - } else if (delta < 0.0) { - // dragging "up" - // TODO(ianh): prioritize first getting rid of overscroll, and then the - // outer view, so that the app bar will scroll out of the way asap. - // Right now we ignore overscroll. This works fine on Android but looks - // weird on iOS if you fling down then up. The problem is it's not at all - // clear what this should do when you have multiple inner positions at - // different levels of overscroll. - final double innerDelta = _outerPosition.applyClampedDragUpdate(delta); - - ///this is a bug that the out postion is not overscroll actually and it get minimal value - ///do under code will scroll inner positions - ///so i igore minimal value here(value like following data) - /// I/flutter (14963): 5.684341886080802e-14 - /// I/flutter (14963): -5.684341886080802e-14 - /// I/flutter (14963): -5.684341886080802e-14 - /// I/flutter (14963): 5.684341886080802e-14 - /// I/flutter (14963): -5.684341886080802e-14 - /// I/flutter (14963): -5.684341886080802e-14 - /// I/flutter (14963): -5.684341886080802e-14 - if (innerDelta != 0.0 && innerDelta.abs() > 0.0001) { - for (_NestedScrollPosition position in _activedInnerPositions) { - position.applyFullDragUpdate(innerDelta); - } - } - } else { - // dragging "down" - delta is positive - // prioritize the inner views, so that the inner content will move before the app bar grows - double outerDelta = 0.0; // it will go positive if it changes - final List overscrolls = []; - final List<_NestedScrollPosition> innerPositions = - _activedInnerPositions.toList(); - for (_NestedScrollPosition position in innerPositions) { - final double overscroll = position.applyClampedDragUpdate(delta); - outerDelta = math.max(outerDelta, overscroll); - overscrolls.add(overscroll); - } - if (outerDelta != 0.0) - outerDelta -= _outerPosition.applyClampedDragUpdate(outerDelta); - // now deal with any overscroll - for (int i = 0; i < innerPositions.length; ++i) { - final double remainingDelta = overscrolls[i] - outerDelta; - if (remainingDelta > 0.0) - innerPositions[i].applyFullDragUpdate(remainingDelta); - } - } - } - - void setParent(ScrollController value) { - _parent = value; - updateParent(); - } - - void updateParent() { - _outerPosition - ?.setParent(_parent ?? PrimaryScrollController.of(_state.context)); - } - - @mustCallSuper - void dispose() { - _currentDrag?.dispose(); - _currentDrag = null; - _outerController.dispose(); - _innerController.dispose(); - } - - @override - String toString() => - '$runtimeType(outer=$_outerController; inner=$_innerController)'; -} - -class _NestedScrollController extends ScrollController { - _NestedScrollController( - this.coordinator, { - double initialScrollOffset = 0.0, - String debugLabel, - }) : super(initialScrollOffset: initialScrollOffset, debugLabel: debugLabel); - - final _NestedScrollCoordinator coordinator; - - @override - ScrollPosition createScrollPosition( - ScrollPhysics physics, - ScrollContext context, - ScrollPosition oldPosition, - ) { - return _NestedScrollPosition( - coordinator: coordinator, - physics: physics, - context: context, - initialPixels: initialScrollOffset, - oldPosition: oldPosition, - debugLabel: debugLabel, - ); - } - - @override - void attach(ScrollPosition position) { - assert(position is _NestedScrollPosition); - super.attach(position); - coordinator.updateParent(); - coordinator.updateCanDrag(); - position.addListener(_scheduleUpdateShadow); - _scheduleUpdateShadow(); - } - - @override - void detach(ScrollPosition position) { - assert(position is _NestedScrollPosition); - position.removeListener(_scheduleUpdateShadow); - if (position is _NestedScrollPosition) { - position._isActived = false; - } - super.detach(position); - _scheduleUpdateShadow(); - } - - void _scheduleUpdateShadow() { - // We do this asynchronously for attach() so that the new position has had - // time to be initialized, and we do it asynchronously for detach() and from - // the position change notifications because those happen synchronously - // during a frame, at a time where it's too late to call setState. Since the - // result is usually animated, the lag incurred is no big deal. - SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { - coordinator.updateShadow(); - }); - } - - ///store page index - Map _pageMetricsList = Map(); - - ///zmt - ///compute activated one when page changed - void _computeActivatedNestedPosition(ScrollNotification notification) { - final key = notification.context.widget.key; - var page = _pageMetricsList[key]; - - ///it's not an available - if (page == -1) { -// print( -// "${this.runtimeType}: it's not available pageMetrics(no actived nested positions in it)"); - return; - } - - final PageMetrics metrics = notification.metrics; - final int currentPage = metrics.page.round(); - _pageMetricsList[key] = currentPage; - - //ComputeActivatedNestedPosition only when page changed - if (page != currentPage) { - ///if layout is not completed, the data will has some gap. - ///need more accurate time to compute - ///delay it in case. - ///to do - Future.delayed(const Duration(milliseconds: 150), () { - var list = nestedPositions.toList(); - if (list.length > 1) { - int activeCount = 0; - int exceptionCount = 0; - - /// this is the page changed of PageView's renderBox, - /// it maybe not the renderBox of [nestedPositions] - /// because it maybe has more one tabbarview or pageview in NestedScrollView body - final RenderBox pageChangedRenderBox = - notification.context.findRenderObject(); - - var activedItem = list.firstWhere((x) { - return x._isActived; - }, orElse: () => null); - - list.forEach((item) { - if (item._computeActived(pageChangedRenderBox)) { - exceptionCount++; - } - if (item._isActived) { - activeCount++; - } - }); - - if (activeCount != 1) { - //use prePageChangedRenderBox try one more time. - //no actived nested positions in it, it will throw expection for all of nested positions - if (activeCount == 0 && exceptionCount == list.length) { - ///it's not available pageMetrics(no actived nested positions in it) - _pageMetricsList[key] = -1; - - ///reset actived - if (activedItem != null) { - activedItem._isActived = true; - } - } else { - print( - "${this.runtimeType}: activeCount is $activeCount, please report to zmtzawqlp@live.com and show your case."); - } - } else { - coordinator.updateCanDrag(); - } - } - }); - } - } - - Iterable<_NestedScrollPosition> get nestedPositions sync* { - // TODO(vegorov): use instance method version of castFrom when it is available. - yield* Iterable.castFrom(positions); - } -} - -// The _NestedScrollPosition is used by both the inner and outer viewports of a -// NestedScrollView. It tracks the offset to use for those viewports, and knows -// about the _NestedScrollCoordinator, so that when activities are triggered on -// this class, they can defer, or be influenced by, the coordinator. -class _NestedScrollPosition extends ScrollPosition - implements ScrollActivityDelegate { - _NestedScrollPosition({ - @required ScrollPhysics physics, - @required ScrollContext context, - double initialPixels = 0.0, - ScrollPosition oldPosition, - String debugLabel, - @required this.coordinator, - }) : super( - physics: physics, - context: context, - oldPosition: oldPosition, - debugLabel: debugLabel, - ) { - if (pixels == null && initialPixels != null) correctPixels(initialPixels); - if (activity == null) goIdle(); - assert(activity != null); - saveScrollOffset(); // in case we didn't restore but could, so that we don't restore it later - } - - final _NestedScrollCoordinator coordinator; - - TickerProvider get vsync => context.vsync; - - ScrollController _parent; - - void setParent(ScrollController value) { - _parent?.detach(this); - _parent = value; - _parent?.attach(this); - } - - ///whether it is actived - bool _isActived = false; - //RenderBox _renderBox; - - ///zmt - ///whether it's actived in its' owner viewport - bool _computeActived(RenderBox pageChangedRenderBox) { - var context = (this.context as ScrollableState)?.context; - try { - if (context == null) { - _isActived = false; - //print("$scrollPositionKey $_isActived"); - return false; - } - final RenderBox renderBox = context.findRenderObject(); - - if (renderBox == null) { - _isActived = false; - //print("$scrollPositionKey $_isActived"); - return false; - } - - ///the nearest pageview/tabview - final RenderBox parentRenderBox = _getParentPageViewRenderBox(context); - -// RenderAbstractViewport viewport = RenderAbstractViewport.of(renderBox); -// RenderAbstractViewport viewport1 = -// RenderAbstractViewport.of(pageChangedRenderBox); -// RenderAbstractViewport viewport2 = -// RenderAbstractViewport.of(parentRenderBox); - -// var test = viewport.getOffsetToReveal(renderBox, 0.0); -// var test1 = viewport1.getOffsetToReveal(pageChangedRenderBox, 0.0); -// var test2 = viewport2.getOffsetToReveal(parentRenderBox, 0.0); -// print("$test $test1 $test2"); -// -// var test = viewport.getOffsetToReveal(renderBox, 0.0, -// rect: viewport2.semanticBounds); - - _isActived = _childIsActivedInViewport(renderBox, pageChangedRenderBox) && - _childIsActivedInViewport(renderBox, parentRenderBox); - -// // just for test -// var key = context.ancestorWidgetOfExactType(extend -// .typeOf()) -// as extend.NestedScrollViewInnerScrollPositionKeyWidget; -// scrollPositionKey = key?.scrollPositionKey; -// -// print("$scrollPositionKey $_isActived"); - return false; - } catch (e) { - //print("${this.runtimeType}: $e"); - _isActived = false; - //print("$scrollPositionKey $_isActived"); - return true; - } - } - - //Key scrollPositionKey; - - ///whether child is zero to parent - bool _childIsActivedInViewport(RenderBox child, RenderBox parent) { - Size parentSize = parent?.size ?? Size(0.0, 0.0); - final Offset position = child.localToGlobal(Offset.zero, ancestor: parent); - - ///remove the margin/padding - final Offset size = Offset(parentSize.width - child.size.width, - parentSize.height - child.size.height); - - ///if layout is not completed, the data will has some gap. - ///need more accurate time to compute - ///to do - bool childIsActivedInViewport = ((position.dx - size.dx).abs() < 1 && - (position.dy - size.dy).abs() < 1); - return childIsActivedInViewport; - } - - ///the nearest pageview/tabbarview - RenderBox _getParentPageViewRenderBox(BuildContext context) { - ScrollableState parent = context.findAncestorStateOfType(); - if (parent == null) { - return null; - } - - ///find horizontal pageview/tabbarview - if (parent.widget.controller is! PageController || - parent.widget.axis != Axis.horizontal) { - return _getParentPageViewRenderBox(parent.context); - } - return parent.context.findRenderObject(); - } - - @override - bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { - if (debugLabel == 'outer') { - if (coordinator._state.widget.pinnedHeaderSliverHeight != null) { - maxScrollExtent = maxScrollExtent - - coordinator._state.widget.pinnedHeaderSliverHeight; - maxScrollExtent = math.max(0.0, maxScrollExtent); - } else if (coordinator._state.widget.pinnedHeaderSliverHeightBuilder != - null) { - maxScrollExtent = maxScrollExtent - - coordinator._state.widget.pinnedHeaderSliverHeightBuilder(); - - maxScrollExtent = math.max(0.0, maxScrollExtent); - } - } - return super.applyContentDimensions(minScrollExtent, maxScrollExtent); - } - - @override - AxisDirection get axisDirection => context.axisDirection; - - @override - void absorb(ScrollPosition other) { - super.absorb(other); - activity.updateDelegate(this); - } - - @override - void restoreScrollOffset() { - if (coordinator.canScrollBody) super.restoreScrollOffset(); - } - - // Returns the amount of delta that was not used. - // - // Positive delta means going down (exposing stuff above), negative delta - // going up (exposing stuff below). - double applyClampedDragUpdate(double delta) { - assert(delta != 0.0); - // If we are going towards the maxScrollExtent (negative scroll offset), - // then the furthest we can be in the minScrollExtent direction is negative - // infinity. For example, if we are already overscrolled, then scrolling to - // reduce the overscroll should not disallow the overscroll. - // - // If we are going towards the minScrollExtent (positive scroll offset), - // then the furthest we can be in the minScrollExtent direction is wherever - // we are now, if we are already overscrolled (in which case pixels is less - // than the minScrollExtent), or the minScrollExtent if we are not. - // - // In other words, we cannot, via applyClampedDragUpdate, _enter_ an - // overscroll situation. - // - // An overscroll situation might be nonetheless entered via several means. - // One is if the physics allow it, via applyFullDragUpdate (see below). An - // overscroll situation can also be forced, e.g. if the scroll position is - // artificially set using the scroll controller. - final double min = - delta < 0.0 ? -double.infinity : math.min(minScrollExtent, pixels); - // The logic for max is equivalent but on the other side. - final double max = - delta > 0.0 ? double.infinity : math.max(maxScrollExtent, pixels); - final double oldPixels = pixels; - final double newPixels = (pixels - delta).clamp(min, max); - final double clampedDelta = newPixels - pixels; - if (clampedDelta == 0.0) return delta; - final double overscroll = physics.applyBoundaryConditions(this, newPixels); - final double actualNewPixels = newPixels - overscroll; - final double offset = actualNewPixels - oldPixels; - if (offset != 0.0) { - forcePixels(actualNewPixels); - didUpdateScrollPositionBy(offset); - } - return delta + offset; - } - - // Returns the overscroll. - double applyFullDragUpdate(double delta) { - assert(delta != 0.0); - final double oldPixels = pixels; - // Apply friction: - final double newPixels = - pixels - physics.applyPhysicsToUserOffset(this, delta); - if (oldPixels == newPixels) - return 0.0; // delta must have been so small we dropped it during floating point addition - // Check for overscroll: - final double overscroll = physics.applyBoundaryConditions(this, newPixels); - final double actualNewPixels = newPixels - overscroll; - if (actualNewPixels != oldPixels) { - forcePixels(actualNewPixels); - didUpdateScrollPositionBy(actualNewPixels - oldPixels); - } - if (overscroll != 0.0) { - didOverscrollBy(overscroll); - return overscroll; - } - return 0.0; - } - - @override - ScrollDirection get userScrollDirection => coordinator.userScrollDirection; - - DrivenScrollActivity createDrivenScrollActivity( - double to, Duration duration, Curve curve) { - return DrivenScrollActivity( - this, - from: pixels, - to: to, - duration: duration, - curve: curve, - vsync: vsync, - ); - } - - @override - double applyUserOffset(double delta) { - assert(false); - return 0.0; - } - - // This is called by activities when they finish their work. - @override - void goIdle() { - beginActivity(IdleScrollActivity(this)); - } - - // This is called by activities when they finish their work and want to go ballistic. - @override - void goBallistic(double velocity) { - Simulation simulation; - if (velocity != 0.0 || outOfRange) - simulation = physics.createBallisticSimulation(this, velocity); - beginActivity(createBallisticScrollActivity( - simulation, - mode: _NestedBallisticScrollActivityMode.independent, - )); - } - - ScrollActivity createBallisticScrollActivity( - Simulation simulation, { - @required _NestedBallisticScrollActivityMode mode, - _NestedScrollMetrics metrics, - }) { - if (simulation == null) return IdleScrollActivity(this); - assert(mode != null); - switch (mode) { - case _NestedBallisticScrollActivityMode.outer: - assert(metrics != null); - if (metrics.minRange == metrics.maxRange) - return IdleScrollActivity(this); - return _NestedOuterBallisticScrollActivity( - coordinator, this, metrics, simulation, context.vsync); - case _NestedBallisticScrollActivityMode.inner: - return _NestedInnerBallisticScrollActivity( - coordinator, this, simulation, context.vsync); - case _NestedBallisticScrollActivityMode.independent: - return BallisticScrollActivity(this, simulation, context.vsync); - } - return null; - } - - @override - Future animateTo( - double to, { - @required Duration duration, - @required Curve curve, - }) { - return coordinator.animateTo(coordinator.unnestOffset(to, this), - duration: duration, curve: curve); - } - - @override - void jumpTo(double value) { - return coordinator.jumpTo(coordinator.unnestOffset(value, this)); - } - - @override - void jumpToWithoutSettling(double value) { - assert(false); - } - - void localJumpTo(double value) { - if (pixels != value) { - final double oldPixels = pixels; - forcePixels(value); - didStartScroll(); - didUpdateScrollPositionBy(pixels - oldPixels); - didEndScroll(); - } - } - - @override - void applyNewDimensions() { - super.applyNewDimensions(); - coordinator.updateCanDrag(); - } - - void updateCanDrag(double totalExtent) { - context.setCanDrag(totalExtent > (viewportDimension - maxScrollExtent) || - minScrollExtent != maxScrollExtent); - } - - @override - ScrollHoldController hold(VoidCallback holdCancelCallback) { - return coordinator.hold(holdCancelCallback); - } - - @override - Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) { - return coordinator.drag(details, dragCancelCallback); - } - - @override - void dispose() { - _parent?.detach(this); - super.dispose(); - } -} - -enum _NestedBallisticScrollActivityMode { outer, inner, independent } - -class _NestedInnerBallisticScrollActivity extends BallisticScrollActivity { - _NestedInnerBallisticScrollActivity( - this.coordinator, - _NestedScrollPosition position, - Simulation simulation, - TickerProvider vsync, - ) : super(position, simulation, vsync); - - final _NestedScrollCoordinator coordinator; - - @override - _NestedScrollPosition get delegate => super.delegate; - - @override - void resetActivity() { - delegate.beginActivity( - coordinator.createInnerBallisticScrollActivity(delegate, velocity)); - } - - @override - void applyNewDimensions() { - delegate.beginActivity( - coordinator.createInnerBallisticScrollActivity(delegate, velocity)); - } - - @override - bool applyMoveTo(double value) { - return super.applyMoveTo(coordinator.nestOffset(value, delegate)); - } -} - -class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity { - _NestedOuterBallisticScrollActivity( - this.coordinator, - _NestedScrollPosition position, - this.metrics, - Simulation simulation, - TickerProvider vsync, - ) : assert(metrics.minRange != metrics.maxRange), - assert(metrics.maxRange > metrics.minRange), - super(position, simulation, vsync); - - final _NestedScrollCoordinator coordinator; - final _NestedScrollMetrics metrics; - - @override - _NestedScrollPosition get delegate => super.delegate; - - @override - void resetActivity() { - delegate.beginActivity( - coordinator.createOuterBallisticScrollActivity(velocity)); - } - - @override - void applyNewDimensions() { - delegate.beginActivity( - coordinator.createOuterBallisticScrollActivity(velocity)); - } - - @override - bool applyMoveTo(double value) { - bool done = false; - if (velocity > 0.0) { - if (value < metrics.minRange) return true; - if (value > metrics.maxRange) { - value = metrics.maxRange; - done = true; - } - } else if (velocity < 0.0) { - if (value > metrics.maxRange) return true; - if (value < metrics.minRange) { - value = metrics.minRange; - done = true; - } - } else { - value = value.clamp(metrics.minRange, metrics.maxRange); - done = true; - } - final bool result = super.applyMoveTo(value + metrics.correctionOffset); - assert( - result); // since we tried to pass an in-range value, it shouldn't ever overflow - return !done; - } - - @override - String toString() { - return '$runtimeType(${metrics.minRange} .. ${metrics.maxRange}; correcting by ${metrics.correctionOffset})'; - } -} +// // Copyright 2016 The Chromium Authors. All rights reserved. +// // Use of this source code is governed by a BSD-style license that can be +// // found in the LICENSE file. + +// import 'dart:async'; +// import 'dart:math' as math; + +// //import 'package:extended_nested_scroll_view/src/nested_scroll_view_inner_scroll_position_key_widget.dart'; +// //import 'package:extended_nested_scroll_view/src/util.dart'; +// //import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' +// // as extend; +// import 'package:flutter/gestures.dart'; +// import 'package:flutter/painting.dart'; +// import 'package:flutter/physics.dart'; +// import 'package:flutter/rendering.dart'; +// import 'package:flutter/scheduler.dart'; +// import 'package:flutter/widgets.dart'; + +// // Examples can assume: +// // List _tabs; + +// /// Signature used by [ExtendedNestedScrollView] for building its header. +// /// +// /// The `innerBoxIsScrolled` argument is typically used to control the +// /// [SliverAppBar.forceElevated] property to ensure that the app bar shows a +// /// shadow, since it would otherwise not necessarily be aware that it had +// /// content ostensibly below it. + +// //it include statusBarHeight ,pinned appbar height ,pinned SliverPersistentHeader height +// //which are in NestedScrollViewHeaderSlivers +// typedef ExtendedNestedScrollViewPinnedHeaderSliverHeightBuilder = double +// Function(); + +// /// A scrolling view inside of which can be nested other scrolling views, with +// /// their scroll positions being intrinsically linked. +// /// +// /// The most common use case for this widget is a scrollable view with a +// /// flexible [SliverAppBar] containing a [TabBar] in the header (build by +// /// [headerSliverBuilder], and with a [TabBarView] in the [body], such that the +// /// scrollable view's contents vary based on which tab is visible. +// /// +// /// ## Motivation +// /// +// /// In a normal [ScrollView], there is one set of slivers (the components of the +// /// scrolling view). If one of those slivers hosted a [TabBarView] which scrolls +// /// in the opposite direction (e.g. allowing the user to swipe horizontally +// /// between the pages represented by the tabs, while the list scrolls +// /// vertically), then any list inside that [TabBarView] would not interact with +// /// the outer [ScrollView]. For example, flinging the inner list to scroll to +// /// the top would not cause a collapsed [SliverAppBar] in the outer [ScrollView] +// /// to expand. +// /// +// /// [ExtendedNestedScrollView] solves this problem by providing custom +// /// [ScrollController]s for the outer [ScrollView] and the inner [ScrollView]s +// /// (those inside the [TabBarView], hooking them together so that they appear, +// /// to the user, as one coherent scroll view. +// /// +// /// {@tool sample} +// /// +// /// This example shows a [ExtendedNestedScrollView] whose header is the combination of a +// /// [TabBar] in a [SliverAppBar] and whose body is a [TabBarView]. It uses a +// /// [SliverOverlapAbsorber]/[SliverOverlapInjector] pair to make the inner lists +// /// align correctly, and it uses [SafeArea] to avoid any horizontal disturbances +// /// (e.g. the "notch" on iOS when the phone is horizontal). In addition, +// /// [PageStorageKey]s are used to remember the scroll position of each tab's +// /// list. +// /// +// /// In the example below, `_tabs` is a list of strings, one for each tab, giving +// /// the tab labels. In a real application, it would be replaced by the actual +// /// data model being represented. +// /// +// /// ```dart +// /// DefaultTabController( +// /// length: _tabs.length, // This is the number of tabs. +// /// child: NestedScrollView( +// /// headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { +// /// // These are the slivers that show up in the "outer" scroll view. +// /// return [ +// /// SliverOverlapAbsorber( +// /// // This widget takes the overlapping behavior of the SliverAppBar, +// /// // and redirects it to the SliverOverlapInjector below. If it is +// /// // missing, then it is possible for the nested "inner" scroll view +// /// // below to end up under the SliverAppBar even when the inner +// /// // scroll view thinks it has not been scrolled. +// /// // This is not necessary if the "headerSliverBuilder" only builds +// /// // widgets that do not overlap the next sliver. +// /// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), +// /// child: SliverAppBar( +// /// title: const Text('Books'), // This is the title in the app bar. +// /// pinned: true, +// /// expandedHeight: 150.0, +// /// // The "forceElevated" property causes the SliverAppBar to show +// /// // a shadow. The "innerBoxIsScrolled" parameter is true when the +// /// // inner scroll view is scrolled beyond its "zero" point, i.e. +// /// // when it appears to be scrolled below the SliverAppBar. +// /// // Without this, there are cases where the shadow would appear +// /// // or not appear inappropriately, because the SliverAppBar is +// /// // not actually aware of the precise position of the inner +// /// // scroll views. +// /// forceElevated: innerBoxIsScrolled, +// /// bottom: TabBar( +// /// // These are the widgets to put in each tab in the tab bar. +// /// tabs: _tabs.map((String name) => Tab(text: name)).toList(), +// /// ), +// /// ), +// /// ), +// /// ]; +// /// }, +// /// body: TabBarView( +// /// // These are the contents of the tab views, below the tabs. +// /// children: _tabs.map((String name) { +// /// return SafeArea( +// /// top: false, +// /// bottom: false, +// /// child: Builder( +// /// // This Builder is needed to provide a BuildContext that is "inside" +// /// // the NestedScrollView, so that sliverOverlapAbsorberHandleFor() can +// /// // find the NestedScrollView. +// /// builder: (BuildContext context) { +// /// return CustomScrollView( +// /// // The "controller" and "primary" members should be left +// /// // unset, so that the NestedScrollView can control this +// /// // inner scroll view. +// /// // If the "controller" property is set, then this scroll +// /// // view will not be associated with the NestedScrollView. +// /// // The PageStorageKey should be unique to this ScrollView; +// /// // it allows the list to remember its scroll position when +// /// // the tab view is not on the screen. +// /// key: PageStorageKey(name), +// /// slivers: [ +// /// SliverOverlapInjector( +// /// // This is the flip side of the SliverOverlapAbsorber above. +// /// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), +// /// ), +// /// SliverPadding( +// /// padding: const EdgeInsets.all(8.0), +// /// // In this example, the inner scroll view has +// /// // fixed-height list items, hence the use of +// /// // SliverFixedExtentList. However, one could use any +// /// // sliver widget here, e.g. SliverList or SliverGrid. +// /// sliver: SliverFixedExtentList( +// /// // The items in this example are fixed to 48 pixels +// /// // high. This matches the Material Design spec for +// /// // ListTile widgets. +// /// itemExtent: 48.0, +// /// delegate: SliverChildBuilderDelegate( +// /// (BuildContext context, int index) { +// /// // This builder is called for each child. +// /// // In this example, we just number each list item. +// /// return ListTile( +// /// title: Text('Item $index'), +// /// ); +// /// }, +// /// // The childCount of the SliverChildBuilderDelegate +// /// // specifies how many children this inner list +// /// // has. In this example, each tab has a list of +// /// // exactly 30 items, but this is arbitrary. +// /// childCount: 30, +// /// ), +// /// ), +// /// ), +// /// ], +// /// ); +// /// }, +// /// ), +// /// ); +// /// }).toList(), +// /// ), +// /// ), +// /// ) +// /// ``` +// /// {@end-tool} +// class ExtendedNestedScrollView extends StatefulWidget { +// /// Creates a nested scroll view. +// /// +// /// The [reverse], [headerSliverBuilder], and [body] arguments must not be +// /// null. +// const ExtendedNestedScrollView({ +// Key key, +// this.controller, +// this.scrollDirection = Axis.vertical, +// this.reverse = false, +// this.physics, +// this.pinnedHeaderSliverHeightBuilder, +// this.pinnedHeaderSliverHeight, +// this.keepOnlyOneInnerNestedScrollPositionActive: false, +// @required this.headerSliverBuilder, +// @required this.body, +// }) : assert(false, +// "new ExtendedNestedScrollView still has some issues in special layout, make it as obsolete for now till find a better solution"), +// assert(scrollDirection != null), +// assert(reverse != null), +// assert(headerSliverBuilder != null), +// assert(body != null), + +// ///don't use them at the same time +// assert(!(pinnedHeaderSliverHeight != null && +// pinnedHeaderSliverHeightBuilder != null)), +// super(key: key); + +// ///get the pinned header in NestedScrollView header. +// ///if your pinned header will changed, use this instead of [pinnedHeaderSliverHeight] +// final ExtendedNestedScrollViewPinnedHeaderSliverHeightBuilder +// pinnedHeaderSliverHeightBuilder; + +// ///if your pinned header will not changed, use this instead of [pinnedHeaderSliverHeightBuilder] +// final double pinnedHeaderSliverHeight; + +// ///when ExtendedNestedScrollView body has [TabBarView]/[PageView] and children have +// ///AutomaticKeepAliveClientMixin or PageStorageKey, +// ///[_innerController.nestedPositions] will have more one, +// ///when you scroll, it will scroll all of nestedPositions +// ///set [keepOnlyOneInnerNestedScrollPositionActive] true to avoid it. +// ///notice: only for Axis.horizontal PageView/TabBarView and +// ///[scrollDirection] must be Axis.vertical. +// final bool keepOnlyOneInnerNestedScrollPositionActive; + +// /// An object that can be used to control the position to which the outer +// /// scroll view is scrolled. +// final ScrollController controller; + +// /// The axis along which the scroll view scrolls. +// /// +// /// Defaults to [Axis.vertical]. +// final Axis scrollDirection; + +// /// Whether the scroll view scrolls in the reading direction. +// /// +// /// For example, if the reading direction is left-to-right and +// /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from +// /// left to right when [reverse] is false and from right to left when +// /// [reverse] is true. +// /// +// /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view +// /// scrolls from top to bottom when [reverse] is false and from bottom to top +// /// when [reverse] is true. +// /// +// /// Defaults to false. +// final bool reverse; + +// /// How the scroll view should respond to user input. +// /// +// /// For example, determines how the scroll view continues to animate after the +// /// user stops dragging the scroll view (providing a custom implementation of +// /// [ScrollPhysics.createBallisticSimulation] allows this particular aspect of +// /// the physics to be overridden). +// /// +// /// Defaults to matching platform conventions. +// /// +// /// The [ScrollPhysics.applyBoundaryConditions] implementation of the provided +// /// object should not allow scrolling outside the scroll extent range +// /// described by the [ScrollMetrics.minScrollExtent] and +// /// [ScrollMetrics.maxScrollExtent] properties passed to that method. If that +// /// invariant is not maintained, the nested scroll view may respond to user +// /// scrolling erratically. +// final ScrollPhysics physics; + +// /// A builder for any widgets that are to precede the inner scroll views (as +// /// given by [body]). +// /// +// /// Typically this is used to create a [SliverAppBar] with a [TabBar]. +// final NestedScrollViewHeaderSliversBuilder headerSliverBuilder; + +// /// The widget to show inside the [ExtendedNestedScrollView]. +// /// +// /// Typically this will be [TabBarView]. +// /// +// /// The [body] is built in a context that provides a [PrimaryScrollController] +// /// that interacts with the [ExtendedNestedScrollView]'s scroll controller. Any +// /// [ListView] or other [Scrollable]-based widget inside the [body] that is +// /// intended to scroll with the [ExtendedNestedScrollView] should therefore not be +// /// given an explicit [ScrollController], instead allowing it to default to +// /// the [PrimaryScrollController] provided by the [ExtendedNestedScrollView]. +// final Widget body; + +// /// Returns the [SliverOverlapAbsorberHandle] of the nearest ancestor +// /// [ExtendedNestedScrollView]. +// /// +// /// This is necessary to configure the [SliverOverlapAbsorber] and +// /// [SliverOverlapInjector] widgets. +// /// +// /// For sample code showing how to use this method, see the [ExtendedNestedScrollView] +// /// documentation. +// static SliverOverlapAbsorberHandle sliverOverlapAbsorberHandleFor( +// BuildContext context) { +// final _InheritedNestedScrollView target = context +// .dependOnInheritedWidgetOfExactType<_InheritedNestedScrollView>(); +// assert(target != null, +// 'NestedScrollView.sliverOverlapAbsorberHandleFor must be called with a context that contains a NestedScrollView.'); +// return target.state._absorberHandle; +// } + +// // List _buildSlivers(BuildContext context, +// // ScrollController innerController, bool bodyIsScrolled) { +// // final List slivers = []; +// // slivers.addAll(headerSliverBuilder(context, bodyIsScrolled)); +// // slivers.add( +// // SliverFillRemaining( +// // child: PrimaryScrollController( +// // controller: innerController, +// // child: body, +// // ), +// // )); +// // return slivers; +// // } + +// @override +// _ExtendedNestedScrollViewState createState() => +// _ExtendedNestedScrollViewState(); +// } + +// class _ExtendedNestedScrollViewState extends State { +// final SliverOverlapAbsorberHandle _absorberHandle = +// SliverOverlapAbsorberHandle(); + +// _NestedScrollCoordinator _coordinator; + +// @override +// void initState() { +// ///when ExtendedNestedScrollView body has [TabBarView]/[PageView] and children have +// ///AutomaticKeepAliveClientMixin or PageStorageKey, +// ///[_innerController.nestedPositions] will have more one, +// ///when you scroll, it will scroll all of nestedPositions +// ///set [keepOnlyOneInnerNestedScrollPositionActive] true to avoid it. +// ///notice: only for Axis.horizontal [TabBarView]/[PageView] and +// ///[scrollDirection] must be Axis.vertical. +// assert(!(widget.keepOnlyOneInnerNestedScrollPositionActive && +// widget.scrollDirection == Axis.horizontal)); + +// super.initState(); +// _coordinator = _NestedScrollCoordinator( +// this, widget.controller, _handleHasScrolledBodyChanged); +// } + +// @override +// void didChangeDependencies() { +// super.didChangeDependencies(); +// _coordinator.setParent(widget.controller); +// } + +// @override +// void didUpdateWidget(ExtendedNestedScrollView oldWidget) { +// super.didUpdateWidget(oldWidget); +// if (oldWidget.controller != widget.controller) +// _coordinator.setParent(widget.controller); +// } + +// @override +// void dispose() { +// _coordinator.dispose(); +// _coordinator = null; +// super.dispose(); +// } + +// bool _lastHasScrolledBody; + +// void _handleHasScrolledBodyChanged() { +// if (!mounted) return; +// final bool newHasScrolledBody = _coordinator.hasScrolledBody; +// if (_lastHasScrolledBody != newHasScrolledBody) { +// setState(() { +// // _coordinator.hasScrolledBody changed (we use it in the build method) +// // (We record _lastHasScrolledBody in the build() method, rather than in +// // this setState call, because the build() method may be called more +// // often than just from here, and we want to only call setState when the +// // new value is different than the last built value.) +// }); +// } +// } + +// @override +// Widget build(BuildContext context) { +// var child = _InheritedNestedScrollView( +// state: this, +// child: Builder( +// builder: (BuildContext context) { +// _lastHasScrolledBody = _coordinator.hasScrolledBody; +// return _NestedScrollViewCustomScrollView( +// scrollDirection: widget.scrollDirection, +// reverse: widget.reverse, +// physics: widget.physics != null +// ? widget.physics.applyTo(const ClampingScrollPhysics()) +// : const ClampingScrollPhysics(), +// controller: _coordinator._outerController, +// slivers: _buildSlivers( +// context, +// _coordinator._innerController, +// _lastHasScrolledBody, +// ), +// handle: _absorberHandle, +// ); +// }, +// ), +// ); +// return child; +// } + +// ///zmt +// List _buildSlivers(BuildContext context, +// ScrollController innerController, bool bodyIsScrolled) { +// final List slivers = []; +// slivers.addAll(widget.headerSliverBuilder(context, bodyIsScrolled)); + +// Widget body = widget.body; + +// if (widget.keepOnlyOneInnerNestedScrollPositionActive) { +// ///get notifications and compute active one in _innerController.nestedPositions +// body = NotificationListener( +// onNotification: (ScrollNotification notification) { +// if (((notification is ScrollEndNotification) || +// (notification is UserScrollNotification && +// notification.direction == ScrollDirection.idle)) && +// notification.metrics is PageMetrics && +// notification.metrics.axis == Axis.horizontal) { +// _coordinator._innerController +// ._computeActivatedNestedPosition(notification); +// } +// return false; +// }, +// child: body); +// } + +// slivers.add(SliverFillRemaining( +// child: PrimaryScrollController( +// controller: innerController, +// child: body, +// ), +// )); +// return slivers; +// } +// } + +// class _NestedScrollViewCustomScrollView extends CustomScrollView { +// const _NestedScrollViewCustomScrollView({ +// @required Axis scrollDirection, +// @required bool reverse, +// @required ScrollPhysics physics, +// @required ScrollController controller, +// @required List slivers, +// @required this.handle, +// }) : super( +// scrollDirection: scrollDirection, +// reverse: reverse, +// physics: physics, +// controller: controller, +// slivers: slivers, +// ); + +// final SliverOverlapAbsorberHandle handle; + +// @override +// Widget buildViewport( +// BuildContext context, +// ViewportOffset offset, +// AxisDirection axisDirection, +// List slivers, +// ) { +// assert(!shrinkWrap); +// return NestedScrollViewViewport( +// axisDirection: axisDirection, +// offset: offset, +// slivers: slivers, +// handle: handle, +// ); +// } +// } + +// class _InheritedNestedScrollView extends InheritedWidget { +// const _InheritedNestedScrollView({ +// Key key, +// @required this.state, +// @required Widget child, +// }) : assert(state != null), +// assert(child != null), +// super(key: key, child: child); + +// final _ExtendedNestedScrollViewState state; + +// @override +// bool updateShouldNotify(_InheritedNestedScrollView old) => state != old.state; +// } + +// class _NestedScrollMetrics extends FixedScrollMetrics { +// _NestedScrollMetrics({ +// @required double minScrollExtent, +// @required double maxScrollExtent, +// @required double pixels, +// @required double viewportDimension, +// @required AxisDirection axisDirection, +// @required this.minRange, +// @required this.maxRange, +// @required this.correctionOffset, +// }) : super( +// minScrollExtent: minScrollExtent, +// maxScrollExtent: maxScrollExtent, +// pixels: pixels, +// viewportDimension: viewportDimension, +// axisDirection: axisDirection, +// ); + +// @override +// _NestedScrollMetrics copyWith({ +// double minScrollExtent, +// double maxScrollExtent, +// double pixels, +// double viewportDimension, +// AxisDirection axisDirection, +// double minRange, +// double maxRange, +// double correctionOffset, +// }) { +// return _NestedScrollMetrics( +// minScrollExtent: minScrollExtent ?? this.minScrollExtent, +// maxScrollExtent: maxScrollExtent ?? this.maxScrollExtent, +// pixels: pixels ?? this.pixels, +// viewportDimension: viewportDimension ?? this.viewportDimension, +// axisDirection: axisDirection ?? this.axisDirection, +// minRange: minRange ?? this.minRange, +// maxRange: maxRange ?? this.maxRange, +// correctionOffset: correctionOffset ?? this.correctionOffset, +// ); +// } + +// final double minRange; + +// final double maxRange; + +// final double correctionOffset; +// } + +// typedef _NestedScrollActivityGetter = ScrollActivity Function( +// _NestedScrollPosition position); + +// class _NestedScrollCoordinator +// implements ScrollActivityDelegate, ScrollHoldController { +// _NestedScrollCoordinator( +// this._state, this._parent, this._onHasScrolledBodyChanged) { +// final double initialScrollOffset = _parent?.initialScrollOffset ?? 0.0; +// _outerController = _NestedScrollController(this, +// initialScrollOffset: initialScrollOffset, debugLabel: 'outer'); +// _innerController = _NestedScrollController(this, +// initialScrollOffset: 0.0, debugLabel: 'inner'); +// } + +// final _ExtendedNestedScrollViewState _state; +// ScrollController _parent; +// final VoidCallback _onHasScrolledBodyChanged; + +// _NestedScrollController _outerController; +// _NestedScrollController _innerController; + +// _NestedScrollPosition get _outerPosition { +// if (!_outerController.hasClients) return null; +// return _outerController.nestedPositions.single; +// } + +// ///zmt +// ///scroll only for actived one +// Iterable<_NestedScrollPosition> get _activedInnerPositions { +// var list = _innerController.nestedPositions; +// if (_state.widget.keepOnlyOneInnerNestedScrollPositionActive && +// list.length > 1) { +// var temp = list.where((item) { +// return item._isActived; +// }); +// // +// // if (temp.length == 0 && +// // _innerController.prePageChangedRenderBox != null) { +// // _innerController._computeActivatedNestedPosition(null); +// // temp = list.where((item) { +// // return item._isActived; +// // }); +// // } + +// if (temp.length != 1) { +// return list; +// } +// return temp; +// } +// return list; +// } + +// Iterable<_NestedScrollPosition> get _innerPositions { +// return _innerController.nestedPositions; +// } + +// bool get canScrollBody { +// final _NestedScrollPosition outer = _outerPosition; +// if (outer == null) return true; +// return outer.haveDimensions && outer.extentAfter == 0.0; +// } + +// bool get hasScrolledBody { +// for (_NestedScrollPosition position in _activedInnerPositions) { +// if (position.pixels > position.minScrollExtent) return true; +// } +// return false; +// } + +// void updateShadow() { +// if (_onHasScrolledBodyChanged != null) _onHasScrolledBodyChanged(); +// } + +// ScrollDirection get userScrollDirection => _userScrollDirection; +// ScrollDirection _userScrollDirection = ScrollDirection.idle; + +// void updateUserScrollDirection(ScrollDirection value) { +// assert(value != null); +// if (userScrollDirection == value) return; +// _userScrollDirection = value; +// _outerPosition.didUpdateScrollDirection(value); +// for (_NestedScrollPosition position in _innerPositions) +// position.didUpdateScrollDirection(value); +// } + +// ScrollDragController _currentDrag; + +// void beginActivity(ScrollActivity newOuterActivity, +// _NestedScrollActivityGetter innerActivityGetter) { +// _outerPosition.beginActivity(newOuterActivity); +// bool scrolling = newOuterActivity.isScrolling; +// for (_NestedScrollPosition position in _activedInnerPositions) { +// final ScrollActivity newInnerActivity = innerActivityGetter(position); +// position.beginActivity(newInnerActivity); +// scrolling = scrolling && newInnerActivity.isScrolling; +// } +// _currentDrag?.dispose(); +// _currentDrag = null; +// if (!scrolling) updateUserScrollDirection(ScrollDirection.idle); +// } + +// @override +// AxisDirection get axisDirection => _outerPosition.axisDirection; + +// static IdleScrollActivity _createIdleScrollActivity( +// _NestedScrollPosition position) { +// return IdleScrollActivity(position); +// } + +// @override +// void goIdle() { +// beginActivity( +// _createIdleScrollActivity(_outerPosition), _createIdleScrollActivity); +// } + +// @override +// void goBallistic(double velocity) { +// beginActivity( +// createOuterBallisticScrollActivity(velocity), +// (_NestedScrollPosition position) => +// createInnerBallisticScrollActivity(position, velocity), +// ); +// } + +// ScrollActivity createOuterBallisticScrollActivity(double velocity) { +// // This function creates a ballistic scroll for the outer scrollable. +// // +// // It assumes that the outer scrollable can't be overscrolled, and sets up a +// // ballistic scroll over the combined space of the innerPositions and the +// // outerPosition. + +// // First we must pick a representative inner position that we will care +// // about. This is somewhat arbitrary. Ideally we'd pick the one that is "in +// // the center" but there isn't currently a good way to do that so we +// // arbitrarily pick the one that is the furthest away from the infinity we +// // are heading towards. +// _NestedScrollPosition innerPosition; +// if (velocity != 0.0) { +// for (_NestedScrollPosition position in _activedInnerPositions) { +// if (innerPosition != null) { +// if (velocity > 0.0) { +// if (innerPosition.pixels < position.pixels) continue; +// } else { +// assert(velocity < 0.0); +// if (innerPosition.pixels > position.pixels) continue; +// } +// } +// innerPosition = position; +// } +// } + +// if (innerPosition == null) { +// // It's either just us or a velocity=0 situation. +// return _outerPosition.createBallisticScrollActivity( +// _outerPosition.physics +// .createBallisticSimulation(_outerPosition, velocity), +// mode: _NestedBallisticScrollActivityMode.independent, +// ); +// } + +// final _NestedScrollMetrics metrics = _getMetrics(innerPosition, velocity); + +// return _outerPosition.createBallisticScrollActivity( +// _outerPosition.physics.createBallisticSimulation(metrics, velocity), +// mode: _NestedBallisticScrollActivityMode.outer, +// metrics: metrics, +// ); +// } + +// @protected +// ScrollActivity createInnerBallisticScrollActivity( +// _NestedScrollPosition position, double velocity) { +// return position.createBallisticScrollActivity( +// position.physics.createBallisticSimulation( +// velocity == 0 +// ? position as ScrollMetrics +// : _getMetrics(position, velocity), +// velocity, +// ), +// mode: _NestedBallisticScrollActivityMode.inner, +// ); +// } + +// _NestedScrollMetrics _getMetrics( +// _NestedScrollPosition innerPosition, double velocity) { +// assert(innerPosition != null); +// double pixels, minRange, maxRange, correctionOffset, extra; +// if (innerPosition.pixels == innerPosition.minScrollExtent) { +// pixels = _outerPosition.pixels.clamp( +// _outerPosition.minScrollExtent, +// _outerPosition +// .maxScrollExtent); + // TODO(ianh): gracefully handle out-of-range outer positions +// minRange = _outerPosition.minScrollExtent; +// maxRange = _outerPosition.maxScrollExtent; +// assert(minRange <= maxRange); +// correctionOffset = 0.0; +// extra = 0.0; +// } else { +// assert(innerPosition.pixels != innerPosition.minScrollExtent); +// if (innerPosition.pixels < innerPosition.minScrollExtent) { +// pixels = innerPosition.pixels - +// innerPosition.minScrollExtent + +// _outerPosition.minScrollExtent; +// } else { +// assert(innerPosition.pixels > innerPosition.minScrollExtent); +// pixels = innerPosition.pixels - +// innerPosition.minScrollExtent + +// _outerPosition.maxScrollExtent; +// } +// if ((velocity > 0.0) && +// (innerPosition.pixels > innerPosition.minScrollExtent)) { +// // This handles going forward (fling up) and inner list is scrolled past +// // zero. We want to grab the extra pixels immediately to shrink. +// extra = _outerPosition.maxScrollExtent - _outerPosition.pixels; +// assert(extra >= 0.0); +// minRange = pixels; +// maxRange = pixels + extra; +// assert(minRange <= maxRange); +// correctionOffset = _outerPosition.pixels - pixels; +// } else if ((velocity < 0.0) && +// (innerPosition.pixels < innerPosition.minScrollExtent)) { +// // This handles going backward (fling down) and inner list is +// // underscrolled. We want to grab the extra pixels immediately to grow. +// extra = _outerPosition.pixels - _outerPosition.minScrollExtent; +// assert(extra >= 0.0); +// minRange = pixels - extra; +// maxRange = pixels; +// assert(minRange <= maxRange); +// correctionOffset = _outerPosition.pixels - pixels; +// } else { +// // This handles going forward (fling up) and inner list is +// // underscrolled, OR, going backward (fling down) and inner list is +// // scrolled past zero. We want to skip the pixels we don't need to grow +// // or shrink over. +// if (velocity > 0.0) { +// // shrinking +// extra = _outerPosition.minScrollExtent - _outerPosition.pixels; +// } else { +// assert(velocity < 0.0); +// // growing +// extra = _outerPosition.pixels - +// (_outerPosition.maxScrollExtent - _outerPosition.minScrollExtent); +// } +// assert(extra <= 0.0); +// minRange = _outerPosition.minScrollExtent; +// maxRange = _outerPosition.maxScrollExtent + extra; +// assert(minRange <= maxRange); +// correctionOffset = 0.0; +// } +// } +// return _NestedScrollMetrics( +// minScrollExtent: _outerPosition.minScrollExtent, +// maxScrollExtent: _outerPosition.maxScrollExtent + +// innerPosition.maxScrollExtent - +// innerPosition.minScrollExtent + +// extra, +// pixels: pixels, +// viewportDimension: _outerPosition.viewportDimension, +// axisDirection: _outerPosition.axisDirection, +// minRange: minRange, +// maxRange: maxRange, +// correctionOffset: correctionOffset, +// ); +// } + +// double unnestOffset(double value, _NestedScrollPosition source) { +// if (source == _outerPosition) +// return value.clamp( +// _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); +// if (value < source.minScrollExtent) +// return value - source.minScrollExtent + _outerPosition.minScrollExtent; +// return value - source.minScrollExtent + _outerPosition.maxScrollExtent; +// } + +// double nestOffset(double value, _NestedScrollPosition target) { +// if (target == _outerPosition) +// return value.clamp( +// _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); +// if (value < _outerPosition.minScrollExtent) +// return value - _outerPosition.minScrollExtent + target.minScrollExtent; +// if (value > _outerPosition.maxScrollExtent) +// return value - _outerPosition.maxScrollExtent + target.minScrollExtent; +// return target.minScrollExtent; +// } + +// void updateCanDrag() { +// if (!_outerPosition.haveDimensions) return; +// double maxInnerExtent = 0.0; +// for (_NestedScrollPosition position in _activedInnerPositions) { +// if (!position.haveDimensions) return; +// maxInnerExtent = math.max( +// maxInnerExtent, position.maxScrollExtent - position.minScrollExtent); +// } +// _outerPosition.updateCanDrag(maxInnerExtent); +// } + +// Future animateTo( +// double to, { +// @required Duration duration, +// @required Curve curve, +// }) async { +// final DrivenScrollActivity outerActivity = +// _outerPosition.createDrivenScrollActivity( +// nestOffset(to, _outerPosition), +// duration, +// curve, +// ); +// final List> resultFutures = >[outerActivity.done]; +// beginActivity( +// outerActivity, +// (_NestedScrollPosition position) { +// final DrivenScrollActivity innerActivity = +// position.createDrivenScrollActivity( +// nestOffset(to, position), +// duration, +// curve, +// ); +// resultFutures.add(innerActivity.done); +// return innerActivity; +// }, +// ); +// await Future.wait(resultFutures); +// } + +// void jumpTo(double to) { +// goIdle(); +// _outerPosition.localJumpTo(nestOffset(to, _outerPosition)); +// for (_NestedScrollPosition position in _activedInnerPositions) +// position.localJumpTo(nestOffset(to, position)); +// goBallistic(0.0); +// } + +// @override +// double setPixels(double newPixels) { +// assert(false); +// return 0.0; +// } + +// ScrollHoldController hold(VoidCallback holdCancelCallback) { +// beginActivity( +// HoldScrollActivity( +// delegate: _outerPosition, onHoldCanceled: holdCancelCallback), +// (_NestedScrollPosition position) => +// HoldScrollActivity(delegate: position), +// ); +// return this; +// } + +// @override +// void cancel() { +// goBallistic(0.0); +// } + +// Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) { +// final ScrollDragController drag = ScrollDragController( +// delegate: this, +// details: details, +// onDragCanceled: dragCancelCallback, +// ); +// beginActivity( +// DragScrollActivity(_outerPosition, drag), +// (_NestedScrollPosition position) => DragScrollActivity(position, drag), +// ); +// assert(_currentDrag == null); +// _currentDrag = drag; +// return drag; +// } + +// @override + +// ///zmt +// void applyUserOffset(double delta) { +// updateUserScrollDirection( +// delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse); +// assert(delta != 0.0); +// if (_innerPositions.isEmpty) { +// _outerPosition.applyFullDragUpdate(delta); +// } else if (delta < 0.0) { +// // dragging "up" +// +// TODO(ianh): prioritize first getting rid of overscroll, and then the +// // outer view, so that the app bar will scroll out of the way asap. +// // Right now we ignore overscroll. This works fine on Android but looks +// // weird on iOS if you fling down then up. The problem is it's not at all +// // clear what this should do when you have multiple inner positions at +// // different levels of overscroll. +// final double innerDelta = _outerPosition.applyClampedDragUpdate(delta); + +// ///this is a bug that the out postion is not overscroll actually and it get minimal value +// ///do under code will scroll inner positions +// ///so i igore minimal value here(value like following data) +// /// I/flutter (14963): 5.684341886080802e-14 +// /// I/flutter (14963): -5.684341886080802e-14 +// /// I/flutter (14963): -5.684341886080802e-14 +// /// I/flutter (14963): 5.684341886080802e-14 +// /// I/flutter (14963): -5.684341886080802e-14 +// /// I/flutter (14963): -5.684341886080802e-14 +// /// I/flutter (14963): -5.684341886080802e-14 +// if (innerDelta != 0.0 && innerDelta.abs() > 0.0001) { +// for (_NestedScrollPosition position in _activedInnerPositions) { +// position.applyFullDragUpdate(innerDelta); +// } +// } +// } else { +// // dragging "down" - delta is positive +// // prioritize the inner views, so that the inner content will move before the app bar grows +// double outerDelta = 0.0; // it will go positive if it changes +// final List overscrolls = []; +// final List<_NestedScrollPosition> innerPositions = +// _activedInnerPositions.toList(); +// for (_NestedScrollPosition position in innerPositions) { +// final double overscroll = position.applyClampedDragUpdate(delta); +// outerDelta = math.max(outerDelta, overscroll); +// overscrolls.add(overscroll); +// } +// if (outerDelta != 0.0) +// outerDelta -= _outerPosition.applyClampedDragUpdate(outerDelta); +// // now deal with any overscroll +// for (int i = 0; i < innerPositions.length; ++i) { +// final double remainingDelta = overscrolls[i] - outerDelta; +// if (remainingDelta > 0.0) +// innerPositions[i].applyFullDragUpdate(remainingDelta); +// } +// } +// } + +// void setParent(ScrollController value) { +// _parent = value; +// updateParent(); +// } + +// void updateParent() { +// _outerPosition +// ?.setParent(_parent ?? PrimaryScrollController.of(_state.context)); +// } + +// @mustCallSuper +// void dispose() { +// _currentDrag?.dispose(); +// _currentDrag = null; +// _outerController.dispose(); +// _innerController.dispose(); +// } + +// @override +// String toString() => +// '$runtimeType(outer=$_outerController; inner=$_innerController)'; +// } + +// class _NestedScrollController extends ScrollController { +// _NestedScrollController( +// this.coordinator, { +// double initialScrollOffset = 0.0, +// String debugLabel, +// }) : super(initialScrollOffset: initialScrollOffset, debugLabel: debugLabel); + +// final _NestedScrollCoordinator coordinator; + +// @override +// ScrollPosition createScrollPosition( +// ScrollPhysics physics, +// ScrollContext context, +// ScrollPosition oldPosition, +// ) { +// return _NestedScrollPosition( +// coordinator: coordinator, +// physics: physics, +// context: context, +// initialPixels: initialScrollOffset, +// oldPosition: oldPosition, +// debugLabel: debugLabel, +// ); +// } + +// @override +// void attach(ScrollPosition position) { +// assert(position is _NestedScrollPosition); +// super.attach(position); +// coordinator.updateParent(); +// coordinator.updateCanDrag(); +// position.addListener(_scheduleUpdateShadow); +// _scheduleUpdateShadow(); +// } + +// @override +// void detach(ScrollPosition position) { +// assert(position is _NestedScrollPosition); +// position.removeListener(_scheduleUpdateShadow); +// if (position is _NestedScrollPosition) { +// position._isActived = false; +// } +// super.detach(position); +// _scheduleUpdateShadow(); +// } + +// void _scheduleUpdateShadow() { +// // We do this asynchronously for attach() so that the new position has had +// // time to be initialized, and we do it asynchronously for detach() and from +// // the position change notifications because those happen synchronously +// // during a frame, at a time where it's too late to call setState. Since the +// // result is usually animated, the lag incurred is no big deal. +// SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { +// coordinator.updateShadow(); +// }); +// } + +// ///store page index +// Map _pageMetricsList = Map(); + +// ///zmt +// ///compute activated one when page changed +// void _computeActivatedNestedPosition(ScrollNotification notification) { +// final key = notification.context.widget.key; +// var page = _pageMetricsList[key]; + +// ///it's not an available +// if (page == -1) { +// // print( +// // "${this.runtimeType}: it's not available pageMetrics(no actived nested positions in it)"); +// return; +// } + +// final PageMetrics metrics = notification.metrics; +// final int currentPage = metrics.page.round(); +// _pageMetricsList[key] = currentPage; + +// //ComputeActivatedNestedPosition only when page changed +// if (page != currentPage) { +// ///if layout is not completed, the data will has some gap. +// ///need more accurate time to compute +// ///delay it in case. +// ///to do +// Future.delayed(const Duration(milliseconds: 150), () { +// var list = nestedPositions.toList(); +// if (list.length > 1) { +// int activeCount = 0; +// int exceptionCount = 0; + +// /// this is the page changed of PageView's renderBox, +// /// it maybe not the renderBox of [nestedPositions] +// /// because it maybe has more one tabbarview or pageview in NestedScrollView body +// final RenderBox pageChangedRenderBox = +// notification.context.findRenderObject(); + +// var activedItem = list.firstWhere((x) { +// return x._isActived; +// }, orElse: () => null); + +// list.forEach((item) { +// if (item._computeActived(pageChangedRenderBox)) { +// exceptionCount++; +// } +// if (item._isActived) { +// activeCount++; +// } +// }); + +// if (activeCount != 1) { +// //use prePageChangedRenderBox try one more time. +// //no actived nested positions in it, it will throw expection for all of nested positions +// if (activeCount == 0 && exceptionCount == list.length) { +// ///it's not available pageMetrics(no actived nested positions in it) +// _pageMetricsList[key] = -1; + +// ///reset actived +// if (activedItem != null) { +// activedItem._isActived = true; +// } +// } else { +// print( +// "${this.runtimeType}: activeCount is $activeCount, please report to zmtzawqlp@live.com and show your case."); +// } +// } else { +// coordinator.updateCanDrag(); +// } +// } +// }); +// } +// } + +// Iterable<_NestedScrollPosition> get nestedPositions sync* { +// +// TODO(vegorov): use instance method version of castFrom when it is available. +// yield* Iterable.castFrom(positions); +// } +// } + +// // The _NestedScrollPosition is used by both the inner and outer viewports of a +// // NestedScrollView. It tracks the offset to use for those viewports, and knows +// // about the _NestedScrollCoordinator, so that when activities are triggered on +// // this class, they can defer, or be influenced by, the coordinator. +// class _NestedScrollPosition extends ScrollPosition +// implements ScrollActivityDelegate { +// _NestedScrollPosition({ +// @required ScrollPhysics physics, +// @required ScrollContext context, +// double initialPixels = 0.0, +// ScrollPosition oldPosition, +// String debugLabel, +// @required this.coordinator, +// }) : super( +// physics: physics, +// context: context, +// oldPosition: oldPosition, +// debugLabel: debugLabel, +// ) { +// if (pixels == null && initialPixels != null) correctPixels(initialPixels); +// if (activity == null) goIdle(); +// assert(activity != null); +// saveScrollOffset(); // in case we didn't restore but could, so that we don't restore it later +// } + +// final _NestedScrollCoordinator coordinator; + +// TickerProvider get vsync => context.vsync; + +// ScrollController _parent; + +// void setParent(ScrollController value) { +// _parent?.detach(this); +// _parent = value; +// _parent?.attach(this); +// } + +// ///whether it is actived +// bool _isActived = false; +// //RenderBox _renderBox; + +// ///zmt +// ///whether it's actived in its' owner viewport +// bool _computeActived(RenderBox pageChangedRenderBox) { +// var context = (this.context as ScrollableState)?.context; +// try { +// if (context == null) { +// _isActived = false; +// //print("$scrollPositionKey $_isActived"); +// return false; +// } +// final RenderBox renderBox = context.findRenderObject(); + +// if (renderBox == null) { +// _isActived = false; +// //print("$scrollPositionKey $_isActived"); +// return false; +// } + +// ///the nearest pageview/tabview +// final RenderBox parentRenderBox = _getParentPageViewRenderBox(context); + +// // RenderAbstractViewport viewport = RenderAbstractViewport.of(renderBox); +// // RenderAbstractViewport viewport1 = +// // RenderAbstractViewport.of(pageChangedRenderBox); +// // RenderAbstractViewport viewport2 = +// // RenderAbstractViewport.of(parentRenderBox); + +// // var test = viewport.getOffsetToReveal(renderBox, 0.0); +// // var test1 = viewport1.getOffsetToReveal(pageChangedRenderBox, 0.0); +// // var test2 = viewport2.getOffsetToReveal(parentRenderBox, 0.0); +// // print("$test $test1 $test2"); +// // +// // var test = viewport.getOffsetToReveal(renderBox, 0.0, +// // rect: viewport2.semanticBounds); + +// _isActived = _childIsActivedInViewport(renderBox, pageChangedRenderBox) && +// _childIsActivedInViewport(renderBox, parentRenderBox); + +// // // just for test +// // var key = context.ancestorWidgetOfExactType(extend +// // .typeOf()) +// // as extend.NestedScrollViewInnerScrollPositionKeyWidget; +// // scrollPositionKey = key?.scrollPositionKey; +// // +// // print("$scrollPositionKey $_isActived"); +// return false; +// } catch (e) { +// //print("${this.runtimeType}: $e"); +// _isActived = false; +// //print("$scrollPositionKey $_isActived"); +// return true; +// } +// } + +// //Key scrollPositionKey; + +// ///whether child is zero to parent +// bool _childIsActivedInViewport(RenderBox child, RenderBox parent) { +// Size parentSize = parent?.size ?? Size(0.0, 0.0); +// final Offset position = child.localToGlobal(Offset.zero, ancestor: parent); + +// ///remove the margin/padding +// final Offset size = Offset(parentSize.width - child.size.width, +// parentSize.height - child.size.height); + +// ///if layout is not completed, the data will has some gap. +// ///need more accurate time to compute +// ///to do +// bool childIsActivedInViewport = ((position.dx - size.dx).abs() < 1 && +// (position.dy - size.dy).abs() < 1); +// return childIsActivedInViewport; +// } + +// ///the nearest pageview/tabbarview +// RenderBox _getParentPageViewRenderBox(BuildContext context) { +// ScrollableState parent = context.findAncestorStateOfType(); +// if (parent == null) { +// return null; +// } + +// ///find horizontal pageview/tabbarview +// if (parent.widget.controller is! PageController || +// parent.widget.axis != Axis.horizontal) { +// return _getParentPageViewRenderBox(parent.context); +// } +// return parent.context.findRenderObject(); +// } + +// @override +// bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) { +// if (debugLabel == 'outer') { +// if (coordinator._state.widget.pinnedHeaderSliverHeight != null) { +// maxScrollExtent = maxScrollExtent - +// coordinator._state.widget.pinnedHeaderSliverHeight; +// maxScrollExtent = math.max(0.0, maxScrollExtent); +// } else if (coordinator._state.widget.pinnedHeaderSliverHeightBuilder != +// null) { +// maxScrollExtent = maxScrollExtent - +// coordinator._state.widget.pinnedHeaderSliverHeightBuilder(); + +// maxScrollExtent = math.max(0.0, maxScrollExtent); +// } +// } +// return super.applyContentDimensions(minScrollExtent, maxScrollExtent); +// } + +// @override +// AxisDirection get axisDirection => context.axisDirection; + +// @override +// void absorb(ScrollPosition other) { +// super.absorb(other); +// activity.updateDelegate(this); +// } + +// @override +// void restoreScrollOffset() { +// if (coordinator.canScrollBody) super.restoreScrollOffset(); +// } + +// // Returns the amount of delta that was not used. +// // +// // Positive delta means going down (exposing stuff above), negative delta +// // going up (exposing stuff below). +// double applyClampedDragUpdate(double delta) { +// assert(delta != 0.0); +// // If we are going towards the maxScrollExtent (negative scroll offset), +// // then the furthest we can be in the minScrollExtent direction is negative +// // infinity. For example, if we are already overscrolled, then scrolling to +// // reduce the overscroll should not disallow the overscroll. +// // +// // If we are going towards the minScrollExtent (positive scroll offset), +// // then the furthest we can be in the minScrollExtent direction is wherever +// // we are now, if we are already overscrolled (in which case pixels is less +// // than the minScrollExtent), or the minScrollExtent if we are not. +// // +// // In other words, we cannot, via applyClampedDragUpdate, _enter_ an +// // overscroll situation. +// // +// // An overscroll situation might be nonetheless entered via several means. +// // One is if the physics allow it, via applyFullDragUpdate (see below). An +// // overscroll situation can also be forced, e.g. if the scroll position is +// // artificially set using the scroll controller. +// final double min = +// delta < 0.0 ? -double.infinity : math.min(minScrollExtent, pixels); +// // The logic for max is equivalent but on the other side. +// final double max = +// delta > 0.0 ? double.infinity : math.max(maxScrollExtent, pixels); +// final double oldPixels = pixels; +// final double newPixels = (pixels - delta).clamp(min, max); +// final double clampedDelta = newPixels - pixels; +// if (clampedDelta == 0.0) return delta; +// final double overscroll = physics.applyBoundaryConditions(this, newPixels); +// final double actualNewPixels = newPixels - overscroll; +// final double offset = actualNewPixels - oldPixels; +// if (offset != 0.0) { +// forcePixels(actualNewPixels); +// didUpdateScrollPositionBy(offset); +// } +// return delta + offset; +// } + +// // Returns the overscroll. +// double applyFullDragUpdate(double delta) { +// assert(delta != 0.0); +// final double oldPixels = pixels; +// // Apply friction: +// final double newPixels = +// pixels - physics.applyPhysicsToUserOffset(this, delta); +// if (oldPixels == newPixels) +// return 0.0; // delta must have been so small we dropped it during floating point addition +// // Check for overscroll: +// final double overscroll = physics.applyBoundaryConditions(this, newPixels); +// final double actualNewPixels = newPixels - overscroll; +// if (actualNewPixels != oldPixels) { +// forcePixels(actualNewPixels); +// didUpdateScrollPositionBy(actualNewPixels - oldPixels); +// } +// if (overscroll != 0.0) { +// didOverscrollBy(overscroll); +// return overscroll; +// } +// return 0.0; +// } + +// @override +// ScrollDirection get userScrollDirection => coordinator.userScrollDirection; + +// DrivenScrollActivity createDrivenScrollActivity( +// double to, Duration duration, Curve curve) { +// return DrivenScrollActivity( +// this, +// from: pixels, +// to: to, +// duration: duration, +// curve: curve, +// vsync: vsync, +// ); +// } + +// @override +// double applyUserOffset(double delta) { +// assert(false); +// return 0.0; +// } + +// // This is called by activities when they finish their work. +// @override +// void goIdle() { +// beginActivity(IdleScrollActivity(this)); +// } + +// // This is called by activities when they finish their work and want to go ballistic. +// @override +// void goBallistic(double velocity) { +// Simulation simulation; +// if (velocity != 0.0 || outOfRange) +// simulation = physics.createBallisticSimulation(this, velocity); +// beginActivity(createBallisticScrollActivity( +// simulation, +// mode: _NestedBallisticScrollActivityMode.independent, +// )); +// } + +// ScrollActivity createBallisticScrollActivity( +// Simulation simulation, { +// @required _NestedBallisticScrollActivityMode mode, +// _NestedScrollMetrics metrics, +// }) { +// if (simulation == null) return IdleScrollActivity(this); +// assert(mode != null); +// switch (mode) { +// case _NestedBallisticScrollActivityMode.outer: +// assert(metrics != null); +// if (metrics.minRange == metrics.maxRange) +// return IdleScrollActivity(this); +// return _NestedOuterBallisticScrollActivity( +// coordinator, this, metrics, simulation, context.vsync); +// case _NestedBallisticScrollActivityMode.inner: +// return _NestedInnerBallisticScrollActivity( +// coordinator, this, simulation, context.vsync); +// case _NestedBallisticScrollActivityMode.independent: +// return BallisticScrollActivity(this, simulation, context.vsync); +// } +// return null; +// } + +// @override +// Future animateTo( +// double to, { +// @required Duration duration, +// @required Curve curve, +// }) { +// return coordinator.animateTo(coordinator.unnestOffset(to, this), +// duration: duration, curve: curve); +// } + +// @override +// void jumpTo(double value) { +// return coordinator.jumpTo(coordinator.unnestOffset(value, this)); +// } + +// @override +// void jumpToWithoutSettling(double value) { +// assert(false); +// } + +// void localJumpTo(double value) { +// if (pixels != value) { +// final double oldPixels = pixels; +// forcePixels(value); +// didStartScroll(); +// didUpdateScrollPositionBy(pixels - oldPixels); +// didEndScroll(); +// } +// } + +// @override +// void applyNewDimensions() { +// super.applyNewDimensions(); +// coordinator.updateCanDrag(); +// } + +// void updateCanDrag(double totalExtent) { +// context.setCanDrag(totalExtent > (viewportDimension - maxScrollExtent) || +// minScrollExtent != maxScrollExtent); +// } + +// @override +// ScrollHoldController hold(VoidCallback holdCancelCallback) { +// return coordinator.hold(holdCancelCallback); +// } + +// @override +// Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) { +// return coordinator.drag(details, dragCancelCallback); +// } + +// @override +// void dispose() { +// _parent?.detach(this); +// super.dispose(); +// } +// } + +// enum _NestedBallisticScrollActivityMode { outer, inner, independent } + +// class _NestedInnerBallisticScrollActivity extends BallisticScrollActivity { +// _NestedInnerBallisticScrollActivity( +// this.coordinator, +// _NestedScrollPosition position, +// Simulation simulation, +// TickerProvider vsync, +// ) : super(position, simulation, vsync); + +// final _NestedScrollCoordinator coordinator; + +// @override +// _NestedScrollPosition get delegate => super.delegate; + +// @override +// void resetActivity() { +// delegate.beginActivity( +// coordinator.createInnerBallisticScrollActivity(delegate, velocity)); +// } + +// @override +// void applyNewDimensions() { +// delegate.beginActivity( +// coordinator.createInnerBallisticScrollActivity(delegate, velocity)); +// } + +// @override +// bool applyMoveTo(double value) { +// return super.applyMoveTo(coordinator.nestOffset(value, delegate)); +// } +// } + +// class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity { +// _NestedOuterBallisticScrollActivity( +// this.coordinator, +// _NestedScrollPosition position, +// this.metrics, +// Simulation simulation, +// TickerProvider vsync, +// ) : assert(metrics.minRange != metrics.maxRange), +// assert(metrics.maxRange > metrics.minRange), +// super(position, simulation, vsync); + +// final _NestedScrollCoordinator coordinator; +// final _NestedScrollMetrics metrics; + +// @override +// _NestedScrollPosition get delegate => super.delegate; + +// @override +// void resetActivity() { +// delegate.beginActivity( +// coordinator.createOuterBallisticScrollActivity(velocity)); +// } + +// @override +// void applyNewDimensions() { +// delegate.beginActivity( +// coordinator.createOuterBallisticScrollActivity(velocity)); +// } + +// @override +// bool applyMoveTo(double value) { +// bool done = false; +// if (velocity > 0.0) { +// if (value < metrics.minRange) return true; +// if (value > metrics.maxRange) { +// value = metrics.maxRange; +// done = true; +// } +// } else if (velocity < 0.0) { +// if (value > metrics.maxRange) return true; +// if (value < metrics.minRange) { +// value = metrics.minRange; +// done = true; +// } +// } else { +// value = value.clamp(metrics.minRange, metrics.maxRange); +// done = true; +// } +// final bool result = super.applyMoveTo(value + metrics.correctionOffset); +// assert( +// result); // since we tried to pass an in-range value, it shouldn't ever overflow +// return !done; +// } + +// @override +// String toString() { +// return '$runtimeType(${metrics.minRange} .. ${metrics.maxRange}; correcting by ${metrics.correctionOffset})'; +// } +// } diff --git a/lib/src/nested_scroll_view_inner_scroll_position_key_widget.dart b/lib/src/nested_scroll_view_inner_scroll_position_key_widget.dart index e9e0542..dc52399 100644 --- a/lib/src/nested_scroll_view_inner_scroll_position_key_widget.dart +++ b/lib/src/nested_scroll_view_inner_scroll_position_key_widget.dart @@ -4,11 +4,10 @@ import 'package:flutter/material.dart'; class NestedScrollViewInnerScrollPositionKeyWidget extends StatefulWidget { + const NestedScrollViewInnerScrollPositionKeyWidget( + this.scrollPositionKey, this.child); final Key scrollPositionKey; final Widget child; - NestedScrollViewInnerScrollPositionKeyWidget( - this.scrollPositionKey, this.child); - static State of(BuildContext context) { return context.findAncestorStateOfType< _NestedScrollViewInnerScrollPositionKeyWidgetState>(); @@ -23,27 +22,6 @@ class _NestedScrollViewInnerScrollPositionKeyWidgetState extends State { @override Widget build(BuildContext context) { - //print(widget.scrollPositionKey); return widget.child; } - -// @override -// void didChangeDependencies() { -// // TODO: implement didChangeDependencies -// //print("didChangeDependencies"+widget.scrollPositionKey.toString()); -// super.didChangeDependencies(); -// } -// -// @override -// void didUpdateWidget(NestedScrollViewInnerScrollPositionKeyWidget oldWidget) { -// // TODO: implement didUpdateWidget -// //print("didUpdateWidget"+widget.scrollPositionKey.toString()+oldWidget.scrollPositionKey.toString()); -// super.didUpdateWidget(oldWidget); -// } - -// void _afterLayout(Duration timeStamp) { -// final RenderBox renderBox = this.context.findRenderObject(); -// final position = renderBox.localToGlobal(Offset.zero); -// print("${widget.scrollPositionKey} POSITION : $position "); -// } } diff --git a/lib/src/nested_scroll_view_refresh_indicator.dart b/lib/src/nested_scroll_view_refresh_indicator.dart index 019cb5b..a10dbb5 100644 --- a/lib/src/nested_scroll_view_refresh_indicator.dart +++ b/lib/src/nested_scroll_view_refresh_indicator.dart @@ -202,9 +202,11 @@ class NestedScrollViewRefreshIndicatorState double maxContainerExtent = 0.0; bool _handleScrollNotification(ScrollNotification notification) { - if (!widget.notificationPredicate(notification)) return false; + if (!widget.notificationPredicate(notification)) { + return false; + } maxContainerExtent = math.max( - notification.metrics.viewportDimension, this.maxContainerExtent); + notification.metrics.viewportDimension, maxContainerExtent); if (notification is ScrollStartNotification && notification.metrics.extentBefore == 0.0 && _mode == null && @@ -271,7 +273,9 @@ class NestedScrollViewRefreshIndicatorState } bool _handleGlowNotification(OverscrollIndicatorNotification notification) { - if (notification.depth != 0 || !notification.leading) return false; + if (notification.depth != 0 || !notification.leading) { + return false; + } if (_mode == _RefreshIndicatorMode.drag) { notification.disallowGlow(); return true; @@ -310,7 +314,7 @@ class NestedScrollViewRefreshIndicatorState if (_mode == _RefreshIndicatorMode.armed) newValue = math.max(newValue, 1.0 / _kDragSizeFactorLimit); _positionController.value = - newValue.clamp(0.0, 1.0); // this triggers various rebuilds + newValue.clamp(0.0, 1.0) as double; // this triggers various rebuilds if (_mode == _RefreshIndicatorMode.drag && _valueColor.value.alpha == 0xFF) _mode = _RefreshIndicatorMode.armed; } @@ -375,7 +379,9 @@ class NestedScrollViewRefreshIndicatorState )); return true; }()); - if (refreshResult == null) return; + if (refreshResult == null) { + return; + } refreshResult.whenComplete(() { if (mounted && _mode == _RefreshIndicatorMode.refresh) { completer.complete(); @@ -405,7 +411,9 @@ class NestedScrollViewRefreshIndicatorState Future show({bool atTop = true}) { if (_mode != _RefreshIndicatorMode.refresh && _mode != _RefreshIndicatorMode.snap) { - if (_mode == null) _start(atTop ? AxisDirection.down : AxisDirection.up); + if (_mode == null) { + _start(atTop ? AxisDirection.down : AxisDirection.up); + } _show(); } return _pendingRefreshFuture; diff --git a/lib/src/old_extended_nested_scroll_view.dart b/lib/src/old_extended_nested_scroll_view.dart index 2458966..dcc0b61 100644 --- a/lib/src/old_extended_nested_scroll_view.dart +++ b/lib/src/old_extended_nested_scroll_view.dart @@ -88,7 +88,7 @@ typedef NestedScrollViewInnerScrollPositionKeyBuilder = Key Function(); /// // This is not necessary if the "headerSliverBuilder" only builds /// // widgets that do not overlap the next sliver. /// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), -/// child: SliverAppBar( +/// sliver: SliverAppBar( /// title: const Text('Books'), // This is the title in the app bar. /// pinned: true, /// expandedHeight: 150.0, @@ -116,9 +116,10 @@ typedef NestedScrollViewInnerScrollPositionKeyBuilder = Key Function(); /// top: false, /// bottom: false, /// child: Builder( -/// // This Builder is needed to provide a BuildContext that is "inside" -/// // the NestedScrollView, so that sliverOverlapAbsorberHandleFor() can -/// // find the NestedScrollView. +/// // This Builder is needed to provide a BuildContext that is +/// // "inside" the NestedScrollView, so that +/// // sliverOverlapAbsorberHandleFor() can find the +/// // NestedScrollView. /// builder: (BuildContext context) { /// return CustomScrollView( /// // The "controller" and "primary" members should be left @@ -132,7 +133,8 @@ typedef NestedScrollViewInnerScrollPositionKeyBuilder = Key Function(); /// key: PageStorageKey(name), /// slivers: [ /// SliverOverlapInjector( -/// // This is the flip side of the SliverOverlapAbsorber above. +/// // This is the flip side of the SliverOverlapAbsorber +/// // above. /// handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), /// ), /// SliverPadding( @@ -282,16 +284,15 @@ class NestedScrollView extends StatefulWidget { List _buildSlivers(BuildContext context, ScrollController innerController, bool bodyIsScrolled) { - final List slivers = []; - - slivers.addAll(headerSliverBuilder(context, bodyIsScrolled)); - slivers.add(SliverFillRemaining( - child: PrimaryScrollController( - controller: innerController, - child: body, + return [ + ...headerSliverBuilder(context, bodyIsScrolled), + SliverFillRemaining( + child: PrimaryScrollController( + controller: innerController, + child: body, + ), ), - )); - return slivers; + ]; } @override @@ -302,10 +303,40 @@ class NestedScrollViewState extends State { final SliverOverlapAbsorberHandle _absorberHandle = SliverOverlapAbsorberHandle(); + /// The [ScrollController] provided to the [ScrollView] in + /// [NestedScrollView.body]. + /// + /// Manipulating the [ScrollPosition] of this controller pushes the outer + /// header sliver(s) up and out of view. The position of the [outerController] + /// will be set to [ScrollPosition.maxScrollExtent], unless you use + /// [ScrollPosition.setPixels]. + /// + /// See also: + /// + /// * [outerController], which exposes the [ScrollController] used by the + /// the sliver(s) contained in [NestedScrollView.headerSliverBuilder]. + ScrollController get innerController => _coordinator._innerController; + + /// The [ScrollController] provided to the [ScrollView] in + /// [NestedScrollView.headerSliverBuilder]. + /// + /// This is equivalent to [NestedScrollView.controller], if provided. + /// + /// Manipulating the [ScrollPosition] of this controller pushes the inner body + /// sliver(s) down. The position of the [innerController] will be set to + /// [ScrollPosition.minScrollExtent], unless you use + /// [ScrollPosition.setPixels]. Visually, the inner body will be scrolled to + /// its beginning. + /// + /// See also: + /// + /// * [innerController], which exposes the [ScrollController] used by the + /// [ScrollView] contained in [NestedScrollView.body]. + ScrollController get outerController => _coordinator._outerController; _NestedScrollCoordinator _coordinator; Iterable<_NestedScrollPosition> get innerScrollPositions => - _coordinator.innerScrollPositions; + _coordinator.innerScrollPositions.cast<_NestedScrollPosition>(); _NestedScrollPosition get currentInnerPosition => _coordinator.currentInnerPositions.first; @@ -344,7 +375,9 @@ class NestedScrollViewState extends State { bool _lastHasScrolledBody; void _handleHasScrolledBodyChanged() { - if (!mounted) return; + if (!mounted) { + return; + } final bool newHasScrolledBody = _coordinator.hasScrolledBody; if (_lastHasScrolledBody != newHasScrolledBody) { setState(() { @@ -520,7 +553,9 @@ class _NestedScrollCoordinator _NestedScrollController _innerController; _NestedScrollPosition get _outerPosition { - if (!_outerController.hasClients) return null; + if (!_outerController.hasClients) { + return null; + } return _outerController.nestedPositions.single; } @@ -539,19 +574,26 @@ class _NestedScrollCoordinator bool get canScrollBody { final _NestedScrollPosition outer = _outerPosition; - if (outer == null) return true; + if (outer == null) { + return true; + } return outer.haveDimensions && outer.extentAfter == 0.0; } bool get hasScrolledBody { - for (_NestedScrollPosition position in _currentInnerPositions) { - if (position.pixels > position.minScrollExtent) return true; + for (final _NestedScrollPosition position in _currentInnerPositions) { + assert(position.minScrollExtent != null && position.pixels != null); + if (position.pixels > position.minScrollExtent) { + return true; + } } return false; } void updateShadow() { - if (_onHasScrolledBodyChanged != null) _onHasScrolledBodyChanged(); + if (_onHasScrolledBodyChanged != null) { + _onHasScrolledBodyChanged(); + } } ScrollDirection get userScrollDirection => _userScrollDirection; @@ -559,10 +601,12 @@ class _NestedScrollCoordinator void updateUserScrollDirection(ScrollDirection value) { assert(value != null); - if (userScrollDirection == value) return; + if (userScrollDirection == value) { + return; + } _userScrollDirection = value; _outerPosition.didUpdateScrollDirection(value); - for (_NestedScrollPosition position in _innerPositions) + for (final _NestedScrollPosition position in _innerPositions) position.didUpdateScrollDirection(value); } @@ -572,14 +616,16 @@ class _NestedScrollCoordinator _NestedScrollActivityGetter innerActivityGetter) { _outerPosition.beginActivity(newOuterActivity); bool scrolling = newOuterActivity.isScrolling; - for (_NestedScrollPosition position in _currentInnerPositions) { + for (final _NestedScrollPosition position in _currentInnerPositions) { final ScrollActivity newInnerActivity = innerActivityGetter(position); position.beginActivity(newInnerActivity); scrolling = scrolling && newInnerActivity.isScrolling; } _currentDrag?.dispose(); _currentDrag = null; - if (!scrolling) updateUserScrollDirection(ScrollDirection.idle); + if (!scrolling) { + updateUserScrollDirection(ScrollDirection.idle); + } } @override @@ -619,13 +665,17 @@ class _NestedScrollCoordinator // are heading towards. _NestedScrollPosition innerPosition; if (velocity != 0.0) { - for (_NestedScrollPosition position in _currentInnerPositions) { + for (final _NestedScrollPosition position in _currentInnerPositions) { if (innerPosition != null) { if (velocity > 0.0) { - if (innerPosition.pixels < position.pixels) continue; + if (innerPosition.pixels < position.pixels) { + continue; + } } else { assert(velocity < 0.0); - if (innerPosition.pixels > position.pixels) continue; + if (innerPosition.pixels > position.pixels) { + continue; + } } } innerPosition = position; @@ -655,7 +705,9 @@ class _NestedScrollCoordinator _NestedScrollPosition position, double velocity) { return position.createBallisticScrollActivity( position.physics.createBallisticSimulation( - velocity == 0 ? position : _getMetrics(position, velocity), + velocity == 0 + ? position as ScrollMetrics + : _getMetrics(position, velocity), velocity, ), mode: _NestedBallisticScrollActivityMode.inner, @@ -668,9 +720,8 @@ class _NestedScrollCoordinator double pixels, minRange, maxRange, correctionOffset, extra; if (innerPosition.pixels == innerPosition.minScrollExtent) { pixels = _outerPosition.pixels.clamp( - _outerPosition.minScrollExtent, - _outerPosition - .maxScrollExtent); // TODO(ianh): gracefully handle out-of-range outer positions + _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent) + as double; // TODO(ianh): gracefully handle out-of-range outer positions minRange = _outerPosition.minScrollExtent; maxRange = _outerPosition.maxScrollExtent; assert(minRange <= maxRange); @@ -747,7 +798,8 @@ class _NestedScrollCoordinator double unnestOffset(double value, _NestedScrollPosition source) { if (source == _outerPosition) return value.clamp( - _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); + _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent) + as double; if (value < source.minScrollExtent) return value - source.minScrollExtent + _outerPosition.minScrollExtent; return value - source.minScrollExtent + _outerPosition.maxScrollExtent; @@ -756,7 +808,8 @@ class _NestedScrollCoordinator double nestOffset(double value, _NestedScrollPosition target) { if (target == _outerPosition) return value.clamp( - _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent); + _outerPosition.minScrollExtent, _outerPosition.maxScrollExtent) + as double; if (value < _outerPosition.minScrollExtent) return value - _outerPosition.minScrollExtent + target.minScrollExtent; if (value > _outerPosition.maxScrollExtent) @@ -765,10 +818,14 @@ class _NestedScrollCoordinator } void updateCanDrag() { - if (!_outerPosition.haveDimensions) return; + if (!_outerPosition.haveDimensions) { + return; + } double maxInnerExtent = 0.0; - for (_NestedScrollPosition position in _currentInnerPositions) { - if (!position.haveDimensions) return; + for (final _NestedScrollPosition position in _currentInnerPositions) { + if (!position.haveDimensions) { + return; + } maxInnerExtent = math.max( maxInnerExtent, position.maxScrollExtent - position.minScrollExtent); } @@ -806,7 +863,7 @@ class _NestedScrollCoordinator void jumpTo(double to) { goIdle(); _outerPosition.localJumpTo(nestOffset(to, _outerPosition)); - for (_NestedScrollPosition position in _currentInnerPositions) + for (final _NestedScrollPosition position in _currentInnerPositions) position.localJumpTo(nestOffset(to, position)); goBallistic(0.0); } @@ -875,7 +932,7 @@ class _NestedScrollCoordinator /// I/flutter (14963): -5.684341886080802e-14 /// I/flutter (14963): -5.684341886080802e-14 if (innerDelta != 0.0 && innerDelta.abs() > 0.0001) { - for (_NestedScrollPosition position in _currentInnerPositions) { + for (final _NestedScrollPosition position in _currentInnerPositions) { position.applyFullDragUpdate(innerDelta); } } @@ -887,7 +944,7 @@ class _NestedScrollCoordinator final List<_NestedScrollPosition> innerPositions = _currentInnerPositions.toList(); - for (_NestedScrollPosition position in innerPositions) { + for (final _NestedScrollPosition position in innerPositions) { final double overscroll = position.applyClampedDragUpdate(delta); outerDelta = math.max(outerDelta, overscroll); overscrolls.add(overscroll); @@ -933,7 +990,7 @@ class _NestedScrollController extends ScrollController { String debugLabel, }) : super(initialScrollOffset: initialScrollOffset, debugLabel: debugLabel) { if (debugLabel == 'inner') { - scrollPositionKeyMap = new Map(); + scrollPositionKeyMap = {}; } } @@ -997,7 +1054,7 @@ class _NestedScrollController extends ScrollController { innerScrollPositionKeyBuilder) { if (innerScrollPositionKeyBuilder != null && scrollPositionKeyMap.length > 1) { - var key = innerScrollPositionKeyBuilder(); + final Key key = innerScrollPositionKeyBuilder(); if (scrollPositionKeyMap.containsKey(key)) { return <_NestedScrollPosition>[scrollPositionKeyMap[key]]; // return nestedPositions.where((p) { @@ -1026,14 +1083,12 @@ class _NestedScrollController extends ScrollController { } void resetScrollPositionKey() { - nestedPositions.forEach((p) { - attachScrollPositionKey(p); - }); + nestedPositions.forEach(attachScrollPositionKey); } void attachScrollPositionKey(_NestedScrollPosition position) { if (position != null && scrollPositionKeyMap != null) { - var key = position.setScrollPositionKey(); + final Key key = position.setScrollPositionKey(); if (key != null) { if (!scrollPositionKeyMap.containsKey(key)) { scrollPositionKeyMap[key] = position; @@ -1043,7 +1098,7 @@ class _NestedScrollController extends ScrollController { //this is not a good solution position.clearScrollPositionKey(); - Future.delayed(Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 500), () { attachScrollPositionKey(position); }); } @@ -1081,8 +1136,12 @@ class _NestedScrollPosition extends ScrollPosition oldPosition: oldPosition, debugLabel: debugLabel, ) { - if (pixels == null && initialPixels != null) correctPixels(initialPixels); - if (activity == null) goIdle(); + if (pixels == null && initialPixels != null) { + correctPixels(initialPixels); + } + if (activity == null) { + goIdle(); + } assert(activity != null); saveScrollOffset(); // in case we didn't restore but could, so that we don't restore it later } @@ -1115,7 +1174,9 @@ class _NestedScrollPosition extends ScrollPosition @override void restoreScrollOffset() { - if (coordinator.canScrollBody) super.restoreScrollOffset(); + if (coordinator.canScrollBody) { + super.restoreScrollOffset(); + } } @override @@ -1132,11 +1193,9 @@ class _NestedScrollPosition extends ScrollPosition Key setScrollPositionKey() { //if (haveDimensions) { - NestedScrollViewInnerScrollPositionKeyWidget keyWidget = - (this.context as ScrollableState) - ?.context - ?.findAncestorWidgetOfExactType< - NestedScrollViewInnerScrollPositionKeyWidget>(); + final NestedScrollViewInnerScrollPositionKeyWidget keyWidget = + (context as ScrollableState)?.context?.findAncestorWidgetOfExactType< + NestedScrollViewInnerScrollPositionKeyWidget>(); _key = keyWidget?.scrollPositionKey; // // var b= a.widget.viewportBuilder(a.context,this); @@ -1181,9 +1240,11 @@ class _NestedScrollPosition extends ScrollPosition delta > 0.0 ? double.infinity : math.max(maxScrollExtent, pixels); final double oldPixels = pixels; - final double newPixels = (pixels - delta).clamp(min, max); + final double newPixels = (pixels - delta).clamp(min, max) as double; final double clampedDelta = newPixels - pixels; - if (clampedDelta == 0.0) return delta; + if (clampedDelta == 0.0) { + return delta; + } final double overscroll = physics.applyBoundaryConditions(this, newPixels); final double actualNewPixels = newPixels - overscroll; final double offset = actualNewPixels - oldPixels; @@ -1269,7 +1330,9 @@ class _NestedScrollPosition extends ScrollPosition @required _NestedBallisticScrollActivityMode mode, _NestedScrollMetrics metrics, }) { - if (simulation == null) return IdleScrollActivity(this); + if (simulation == null) { + return IdleScrollActivity(this); + } assert(mode != null); switch (mode) { case _NestedBallisticScrollActivityMode.outer: @@ -1358,7 +1421,7 @@ class _NestedInnerBallisticScrollActivity extends BallisticScrollActivity { final _NestedScrollCoordinator coordinator; @override - _NestedScrollPosition get delegate => super.delegate; + _NestedScrollPosition get delegate => super.delegate as _NestedScrollPosition; @override void resetActivity() { @@ -1393,7 +1456,7 @@ class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity { final _NestedScrollMetrics metrics; @override - _NestedScrollPosition get delegate => super.delegate; + _NestedScrollPosition get delegate => super.delegate as _NestedScrollPosition; @override void resetActivity() { @@ -1411,19 +1474,23 @@ class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity { bool applyMoveTo(double value) { bool done = false; if (velocity > 0.0) { - if (value < metrics.minRange) return true; + if (value < metrics.minRange) { + return true; + } if (value > metrics.maxRange) { value = metrics.maxRange; done = true; } } else if (velocity < 0.0) { - if (value > metrics.maxRange) return true; + if (value > metrics.maxRange) { + return true; + } if (value < metrics.minRange) { value = metrics.minRange; done = true; } } else { - value = value.clamp(metrics.minRange, metrics.maxRange); + value = value.clamp(metrics.minRange, metrics.maxRange) as double; done = true; } final bool result = super.applyMoveTo(value + metrics.correctionOffset); diff --git a/pubspec.lock b/pubspec.lock index c57bb09..99f924b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,42 +7,42 @@ packages: name: archive url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.11" + version: "2.0.13" args: dependency: transitive description: name: args url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.2" + version: "1.6.0" async: dependency: transitive description: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection url: "https://pub.flutter-io.cn" source: hosted - version: "1.14.11" + version: "1.14.12" convert: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: crypto url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -73,7 +73,7 @@ packages: name: image url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.4" + version: "2.1.12" matcher: dependency: transitive description: @@ -95,13 +95,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.6.4" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.8.0+1" petitparser: dependency: transitive description: @@ -115,7 +108,7 @@ packages: name: quiver url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.5" + version: "2.1.3" sky_engine: dependency: transitive description: flutter @@ -127,7 +120,7 @@ packages: name: source_span url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: @@ -162,7 +155,7 @@ packages: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.11" + version: "0.2.15" typed_data: dependency: transitive description: @@ -183,6 +176,7 @@ packages: name: xml url: "https://pub.flutter-io.cn" source: hosted - version: "3.5.0" + version: "3.6.1" sdks: - dart: ">=2.4.0 <3.0.0" + dart: ">=2.6.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index 02674c7..2621ba5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,13 @@ name: extended_nested_scroll_view description: extended nested scroll view to fix pinned header and inner scrollables sync issues. -version: 0.4.1 +version: 1.0.0 author: zmtzawqlp homepage: https://github.com/fluttercandies/extended_nested_scroll_view environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" - + sdk: ">=2.6.0 <3.0.0" + flutter: ">=1.17.0" + dependencies: flutter: sdk: flutter