blob: 43693e3240a5a3d2463fee2a8b3a3dd130afa958 [file] [log] [blame]
// 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 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'framework.dart';
import 'overscroll_indicator.dart';
import 'scroll_physics.dart';
const Color _kDefaultGlowColor = Color(0xFFFFFFFF);
/// Describes how [Scrollable] widgets should behave.
/// Used by [ScrollConfiguration] to configure the [Scrollable] widgets in a
/// subtree.
class ScrollBehavior {
/// Creates a description of how [Scrollable] widgets should behave.
const ScrollBehavior();
/// The platform whose scroll physics should be implemented.
/// Defaults to the current platform.
TargetPlatform getPlatform(BuildContext context) => defaultTargetPlatform;
/// Wraps the given widget, which scrolls in the given [AxisDirection].
/// For example, on Android, this method wraps the given widget with a
/// [GlowingOverscrollIndicator] to provide visual feedback when the user
/// overscrolls.
Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) {
// When modifying this function, consider modifying the implementation in
// _MaterialScrollBehavior as well.
switch (getPlatform(context)) {
case TargetPlatform.iOS:
return child;
case TargetPlatform.fuchsia:
return GlowingOverscrollIndicator(
child: child,
axisDirection: axisDirection,
color: _kDefaultGlowColor,
return null;
/// The scroll physics to use for the platform given by [getPlatform].
/// Defaults to [BouncingScrollPhysics] on iOS and [ClampingScrollPhysics] on
/// Android.
ScrollPhysics getScrollPhysics(BuildContext context) {
switch (getPlatform(context)) {
case TargetPlatform.iOS:
return const BouncingScrollPhysics();
case TargetPlatform.fuchsia:
return const ClampingScrollPhysics();
return null;
/// Called whenever a [ScrollConfiguration] is rebuilt with a new
/// [ScrollBehavior] of the same [runtimeType].
/// If the new instance represents different information than the old
/// instance, then the method should return true, otherwise it should return
/// false.
/// If this method returns true, all the widgets that inherit from the
/// [ScrollConfiguration] will rebuild using the new [ScrollBehavior]. If this
/// method returns false, the rebuilds might be optimized away.
bool shouldNotify(covariant ScrollBehavior oldDelegate) => false;
String toString() => '$runtimeType';
/// Controls how [Scrollable] widgets behave in a subtree.
/// The scroll configuration determines the [ScrollPhysics] and viewport
/// decorations used by descendants of [child].
class ScrollConfiguration extends InheritedWidget {
/// Creates a widget that controls how [Scrollable] widgets behave in a subtree.
/// The [behavior] and [child] arguments must not be null.
const ScrollConfiguration({
Key key,
@required this.behavior,
@required Widget child,
}) : super(key: key, child: child);
/// How [Scrollable] widgets that are descendants of [child] should behave.
final ScrollBehavior behavior;
/// The [ScrollBehavior] for [Scrollable] widgets in the given [BuildContext].
/// If no [ScrollConfiguration] widget is in scope of the given `context`,
/// a default [ScrollBehavior] instance is returned.
static ScrollBehavior of(BuildContext context) {
final ScrollConfiguration configuration = context.inheritFromWidgetOfExactType(ScrollConfiguration);
return configuration?.behavior ?? const ScrollBehavior();
bool updateShouldNotify(ScrollConfiguration oldWidget) {
assert(behavior != null);
return behavior.runtimeType != oldWidget.behavior.runtimeType
|| (behavior != oldWidget.behavior && behavior.shouldNotify(oldWidget.behavior));
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties.add(DiagnosticsProperty<ScrollBehavior>('behavior', behavior));