mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
207 lines
8.0 KiB
Dart
207 lines
8.0 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
/// @docImport 'package:flutter/material.dart';
|
|
/// @docImport 'package:flutter/rendering.dart';
|
|
/// @docImport 'package:flutter_test/flutter_test.dart';
|
|
///
|
|
/// @docImport 'actions.dart';
|
|
/// @docImport 'focus_manager.dart';
|
|
/// @docImport 'scroll_view.dart';
|
|
/// @docImport 'scrollable.dart';
|
|
/// @docImport 'scrollable_helpers.dart';
|
|
/// @docImport 'shortcuts.dart';
|
|
library;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/painting.dart';
|
|
|
|
import 'framework.dart';
|
|
import 'scroll_configuration.dart';
|
|
import 'scroll_controller.dart';
|
|
|
|
const Set<TargetPlatform> _kMobilePlatforms = <TargetPlatform>{
|
|
TargetPlatform.android,
|
|
TargetPlatform.iOS,
|
|
TargetPlatform.fuchsia,
|
|
};
|
|
|
|
/// Associates a [ScrollController] with a subtree.
|
|
///
|
|
/// {@youtube 560 315 https://www.youtube.com/watch?v=33_0ABjFJUU}
|
|
///
|
|
/// When a [ScrollView] has [ScrollView.primary] set to true, the [ScrollView]
|
|
/// uses [of] to inherit the [PrimaryScrollController] associated with its
|
|
/// subtree.
|
|
///
|
|
/// A ScrollView that doesn't have a controller or the primary flag set will
|
|
/// inherit the PrimaryScrollController, if [shouldInherit] allows it. By
|
|
/// default [shouldInherit] is true for mobile platforms when the ScrollView has
|
|
/// a scroll direction of [Axis.vertical]. This automatic inheritance can be
|
|
/// configured with [automaticallyInheritForPlatforms] and [scrollDirection].
|
|
///
|
|
/// Inheriting this ScrollController can provide default behavior for scroll
|
|
/// views in a subtree. For example, the [Scaffold] uses this mechanism to
|
|
/// implement the scroll-to-top gesture on iOS.
|
|
///
|
|
/// Another default behavior handled by the PrimaryScrollController is default
|
|
/// [ScrollAction]s. If a ScrollAction is not handled by an otherwise focused
|
|
/// part of the application, the ScrollAction will be evaluated using the scroll
|
|
/// view associated with a PrimaryScrollController, for example, when executing
|
|
/// [Shortcuts] key events like page up and down.
|
|
///
|
|
/// See also:
|
|
/// * [ScrollAction], an [Action] that scrolls the [Scrollable] that encloses
|
|
/// the current [primaryFocus] or is attached to the PrimaryScrollController.
|
|
/// * [Shortcuts], a widget that establishes a [ShortcutManager] to be used
|
|
/// by its descendants when invoking an [Action] via a keyboard key
|
|
/// combination that maps to an [Intent].
|
|
class PrimaryScrollController extends InheritedWidget {
|
|
/// Creates a widget that associates a [ScrollController] with a subtree.
|
|
const PrimaryScrollController({
|
|
super.key,
|
|
required ScrollController this.controller,
|
|
this.automaticallyInheritForPlatforms = _kMobilePlatforms,
|
|
this.scrollDirection = Axis.vertical,
|
|
required super.child,
|
|
});
|
|
|
|
/// Creates a subtree without an associated [ScrollController].
|
|
const PrimaryScrollController.none({super.key, required super.child})
|
|
: automaticallyInheritForPlatforms = const <TargetPlatform>{},
|
|
scrollDirection = null,
|
|
controller = null;
|
|
|
|
/// The [ScrollController] associated with the subtree.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [ScrollView.controller], which discusses the purpose of specifying a
|
|
/// scroll controller.
|
|
final ScrollController? controller;
|
|
|
|
/// The [Axis] this controller is configured for [ScrollView]s to
|
|
/// automatically inherit.
|
|
///
|
|
/// Used in conjunction with [automaticallyInheritForPlatforms]. If the
|
|
/// current [TargetPlatform] is not included in
|
|
/// [automaticallyInheritForPlatforms], this is ignored.
|
|
///
|
|
/// When null, no [ScrollView] in any Axis will automatically inherit this
|
|
/// controller. This is dissimilar to [PrimaryScrollController.none]. When a
|
|
/// PrimaryScrollController is inherited, ScrollView will insert
|
|
/// PrimaryScrollController.none into the tree to prevent further descendant
|
|
/// ScrollViews from inheriting the current PrimaryScrollController.
|
|
///
|
|
/// For the direction in which active scrolling may be occurring, see
|
|
/// [ScrollDirection].
|
|
///
|
|
/// Defaults to [Axis.vertical].
|
|
final Axis? scrollDirection;
|
|
|
|
/// The [TargetPlatform]s this controller is configured for [ScrollView]s to
|
|
/// automatically inherit.
|
|
///
|
|
/// Used in conjunction with [scrollDirection]. If the [Axis] provided to
|
|
/// [shouldInherit] is not [scrollDirection], this is ignored.
|
|
///
|
|
/// When empty, no ScrollView in any Axis will automatically inherit this
|
|
/// controller. Defaults to [TargetPlatformVariant.mobile].
|
|
final Set<TargetPlatform> automaticallyInheritForPlatforms;
|
|
|
|
/// Returns true if this PrimaryScrollController is configured to be
|
|
/// automatically inherited for the current [TargetPlatform] and the given
|
|
/// [Axis].
|
|
///
|
|
/// This method is typically not called directly. [ScrollView] will call this
|
|
/// method if it has not been provided a [ScrollController] and
|
|
/// [ScrollView.primary] is unset.
|
|
///
|
|
/// If a ScrollController has already been provided to
|
|
/// [ScrollView.controller], or [ScrollView.primary] is set, this is method is
|
|
/// not called by ScrollView as it will have determined whether or not to
|
|
/// inherit the PrimaryScrollController.
|
|
static bool shouldInherit(BuildContext context, Axis scrollDirection) {
|
|
final PrimaryScrollController? result =
|
|
context.findAncestorWidgetOfExactType<PrimaryScrollController>();
|
|
if (result == null) {
|
|
return false;
|
|
}
|
|
|
|
final TargetPlatform platform = ScrollConfiguration.of(context).getPlatform(context);
|
|
if (result.automaticallyInheritForPlatforms.contains(platform)) {
|
|
return result.scrollDirection == scrollDirection;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Returns the [ScrollController] most closely associated with the given
|
|
/// context.
|
|
///
|
|
/// Returns null if there is no [ScrollController] associated with the given
|
|
/// context.
|
|
///
|
|
/// Calling this method will create a dependency on the closest
|
|
/// [PrimaryScrollController] in the [context], if there is one.
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [PrimaryScrollController.maybeOf], which is similar to this method, but
|
|
/// asserts if no [PrimaryScrollController] ancestor is found.
|
|
static ScrollController? maybeOf(BuildContext context) {
|
|
final PrimaryScrollController? result =
|
|
context.dependOnInheritedWidgetOfExactType<PrimaryScrollController>();
|
|
return result?.controller;
|
|
}
|
|
|
|
/// Returns the [ScrollController] most closely associated with the given
|
|
/// context.
|
|
///
|
|
/// If no ancestor is found, this method will assert in debug mode, and throw
|
|
/// an exception in release mode.
|
|
///
|
|
/// Calling this method will create a dependency on the closest
|
|
/// [PrimaryScrollController] in the [context].
|
|
///
|
|
/// See also:
|
|
///
|
|
/// * [PrimaryScrollController.maybeOf], which is similar to this method, but
|
|
/// returns null if no [PrimaryScrollController] ancestor is found.
|
|
static ScrollController of(BuildContext context) {
|
|
final ScrollController? controller = maybeOf(context);
|
|
assert(() {
|
|
if (controller == null) {
|
|
throw FlutterError(
|
|
'PrimaryScrollController.of() was called with a context that does not contain a '
|
|
'PrimaryScrollController widget.\n'
|
|
'No PrimaryScrollController widget ancestor could be found starting from the '
|
|
'context that was passed to PrimaryScrollController.of(). This can happen '
|
|
'because you are using a widget that looks for a PrimaryScrollController '
|
|
'ancestor, but no such ancestor exists.\n'
|
|
'The context used was:\n'
|
|
' $context',
|
|
);
|
|
}
|
|
return true;
|
|
}());
|
|
return controller!;
|
|
}
|
|
|
|
@override
|
|
bool updateShouldNotify(PrimaryScrollController oldWidget) => controller != oldWidget.controller;
|
|
|
|
@override
|
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
super.debugFillProperties(properties);
|
|
properties.add(
|
|
DiagnosticsProperty<ScrollController>(
|
|
'controller',
|
|
controller,
|
|
ifNull: 'no controller',
|
|
showName: false,
|
|
),
|
|
);
|
|
}
|
|
}
|