diff --git a/packages/flutter/lib/foundation.dart b/packages/flutter/lib/foundation.dart
index a463f554bc..21cb3f2ab8 100644
--- a/packages/flutter/lib/foundation.dart
+++ b/packages/flutter/lib/foundation.dart
@@ -14,5 +14,6 @@ export 'src/foundation/basic_types.dart';
export 'src/foundation/binding.dart';
export 'src/foundation/change_notifier.dart';
export 'src/foundation/licenses.dart';
+export 'src/foundation/platform.dart';
export 'src/foundation/print.dart';
export 'src/foundation/synchronous_future.dart';
diff --git a/packages/flutter/lib/src/foundation/platform.dart b/packages/flutter/lib/src/foundation/platform.dart
new file mode 100644
index 0000000000..01bd4892e0
--- /dev/null
+++ b/packages/flutter/lib/src/foundation/platform.dart
@@ -0,0 +1,12 @@
+// 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.
+
+/// The platform that user interaction should adapt to target.
+enum TargetPlatform {
+ /// Android:
+ android,
+
+ /// iOS:
+ iOS,
+}
diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart
index 83b215a100..d79d3d2e4b 100644
--- a/packages/flutter/lib/src/material/app.dart
+++ b/packages/flutter/lib/src/material/app.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:io' show Platform;
-
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
@@ -25,6 +23,15 @@ const TextStyle _errorTextStyle = const TextStyle(
decorationStyle: TextDecorationStyle.double
);
+/// The visual and interaction design for overscroll.
+enum OverscrollStyle {
+ /// Overscrolls are clamped and indicated with a glow.
+ glow,
+
+ /// Overscrolls are not clamped and indicated with elastic physics.
+ bounce
+}
+
/// An application that uses material design.
///
/// A convenience widget that wraps a number of widgets that are commonly
@@ -53,6 +60,7 @@ class MaterialApp extends StatefulWidget {
this.theme,
this.home,
this.routes: const {},
+ this.overscrollStyle,
this.onGenerateRoute,
this.onLocaleChanged,
this.debugShowMaterialGrid: false,
@@ -104,6 +112,11 @@ class MaterialApp extends StatefulWidget {
/// build the page instead.
final Map routes;
+ /// The visual and interaction design for overscroll.
+ ///
+ /// Defaults to being adapted to the current [TargetPlatform].
+ final OverscrollStyle overscrollStyle;
+
/// The route generator callback used when the app is navigated to a
/// named route.
final RouteFactory onGenerateRoute;
@@ -149,7 +162,8 @@ class _IndicatorScrollConfigurationDelegate extends ScrollConfigurationDelegate
@override
Widget wrapScrollWidget(Widget scrollWidget) => new OverscrollIndicator(child: scrollWidget);
}
-final ScrollConfigurationDelegate _indicatorScroll = new _IndicatorScrollConfigurationDelegate();
+
+final ScrollConfigurationDelegate _glowScroll = new _IndicatorScrollConfigurationDelegate();
final ScrollConfigurationDelegate _bounceScroll = new ScrollConfigurationDelegate();
class _MaterialAppState extends State {
@@ -180,6 +194,24 @@ class _MaterialAppState extends State {
return null;
}
+ ScrollConfigurationDelegate _getScrollDelegate(TargetPlatform platform) {
+ if (config.overscrollStyle != null) {
+ switch (config.overscrollStyle) {
+ case OverscrollStyle.glow:
+ return _glowScroll;
+ case OverscrollStyle.bounce:
+ return _bounceScroll;
+ }
+ }
+ switch (platform) {
+ case TargetPlatform.android:
+ return _glowScroll;
+ case TargetPlatform.iOS:
+ return _bounceScroll;
+ }
+ return null;
+ }
+
@override
Widget build(BuildContext context) {
ThemeData theme = config.theme ?? new ThemeData.fallback();
@@ -213,7 +245,7 @@ class _MaterialAppState extends State {
});
return new ScrollConfiguration(
- delegate: (Platform.isIOS || Platform.isMacOS) ? _bounceScroll : _indicatorScroll,
+ delegate: _getScrollDelegate(theme.platform),
child: result
);
}
diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart
index ca6faf16ec..78241fba95 100644
--- a/packages/flutter/lib/src/material/theme_data.dart
+++ b/packages/flutter/lib/src/material/theme_data.dart
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:io' show Platform;
import 'dart:ui' show Color, hashValues;
+import 'package:flutter/foundation.dart';
+
import 'colors.dart';
import 'icon_theme_data.dart';
import 'typography.dart';
@@ -90,7 +93,8 @@ class ThemeData {
TextTheme textTheme,
TextTheme primaryTextTheme,
IconThemeData iconTheme,
- IconThemeData primaryIconTheme
+ IconThemeData primaryIconTheme,
+ TargetPlatform platform
}) {
brightness ??= Brightness.light;
final bool isDark = brightness == Brightness.dark;
@@ -121,6 +125,7 @@ class ThemeData {
primaryTextTheme ??= primaryIsDark ? Typography.white : Typography.black;
iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
+ platform ??= (Platform.isIOS || Platform.isMacOS) ? TargetPlatform.iOS : TargetPlatform.android;
return new ThemeData.raw(
brightness: brightness,
primaryColor: primaryColor,
@@ -146,7 +151,8 @@ class ThemeData {
textTheme: textTheme,
primaryTextTheme: primaryTextTheme,
iconTheme: iconTheme,
- primaryIconTheme: primaryIconTheme
+ primaryIconTheme: primaryIconTheme,
+ platform: platform
);
}
@@ -181,7 +187,8 @@ class ThemeData {
this.textTheme,
this.primaryTextTheme,
this.iconTheme,
- this.primaryIconTheme
+ this.primaryIconTheme,
+ this.platform
}) {
assert(brightness != null);
assert(primaryColor != null);
@@ -208,6 +215,7 @@ class ThemeData {
assert(primaryTextTheme != null);
assert(iconTheme != null);
assert(primaryIconTheme != null);
+ assert(platform != null);
}
/// A default light blue theme.
@@ -320,6 +328,11 @@ class ThemeData {
/// An icon theme that contrasts with the primary color.
final IconThemeData primaryIconTheme;
+ /// The platform the material widgets should adapt to target.
+ ///
+ /// Defaults to the current platform.
+ final TargetPlatform platform;
+
/// Linearly interpolate between two themes.
static ThemeData lerp(ThemeData begin, ThemeData end, double t) {
return new ThemeData.raw(
@@ -347,7 +360,8 @@ class ThemeData {
textTheme: TextTheme.lerp(begin.textTheme, end.textTheme, t),
primaryTextTheme: TextTheme.lerp(begin.primaryTextTheme, end.primaryTextTheme, t),
iconTheme: IconThemeData.lerp(begin.iconTheme, end.iconTheme, t),
- primaryIconTheme: IconThemeData.lerp(begin.primaryIconTheme, end.primaryIconTheme, t)
+ primaryIconTheme: IconThemeData.lerp(begin.primaryIconTheme, end.primaryIconTheme, t),
+ platform: t < 0.5 ? begin.platform : end.platform
);
}