Merge pull request #2664 from Hixie/less-dynamic
Remove some more 'dynamic's
diff --git a/examples/material_gallery/lib/demo/flexible_space_demo.dart b/examples/material_gallery/lib/demo/flexible_space_demo.dart
index 0282dbe..ec7eab3 100644
--- a/examples/material_gallery/lib/demo/flexible_space_demo.dart
+++ b/examples/material_gallery/lib/demo/flexible_space_demo.dart
@@ -72,8 +72,10 @@
}
class FlexibleSpaceDemoState extends State<FlexibleSpaceDemo> {
+ final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
final double appBarHeight = 256.0;
final Key scrollableKey = new UniqueKey();
+ AppBarBehavior _appBarBehavior = AppBarBehavior.scroll;
Widget build(BuildContext context) {
return new Theme(
@@ -82,18 +84,37 @@
primarySwatch: Colors.indigo
),
child: new Scaffold(
+ key: scaffoldKey,
appBarHeight: appBarHeight,
scrollableKey: scrollableKey,
- appBarBehavior: AppBarBehavior.scroll,
+ appBarBehavior: _appBarBehavior,
appBar: new AppBar(
actions: <Widget>[
new IconButton(
icon: Icons.create,
- tooltip: 'Search'
+ tooltip: 'Search',
+ onPressed: () {
+ scaffoldKey.currentState.showSnackBar(new SnackBar(
+ content: new Text('Not supported.')
+ ));
+ }
),
- new IconButton(
- icon: Icons.more_vert,
- tooltip: 'Show menu'
+ new PopupMenuButton<AppBarBehavior>(
+ onSelected: (AppBarBehavior value) {
+ setState(() {
+ _appBarBehavior = value;
+ });
+ },
+ items: <PopupMenuItem<AppBarBehavior>>[
+ new PopupMenuItem<AppBarBehavior>(
+ value: AppBarBehavior.scroll,
+ child: new Text('AppBar scrolls away')
+ ),
+ new PopupMenuItem<AppBarBehavior>(
+ value: AppBarBehavior.under,
+ child: new Text('AppBar stays put')
+ )
+ ]
)
],
flexibleSpace: (BuildContext context) {
diff --git a/examples/material_gallery/lib/gallery/section.dart b/examples/material_gallery/lib/gallery/section.dart
index c1060f1..2670c2d 100644
--- a/examples/material_gallery/lib/gallery/section.dart
+++ b/examples/material_gallery/lib/gallery/section.dart
@@ -37,7 +37,7 @@
data: theme,
child: new Scaffold(
appBarHeight: appBarHeight,
- appBarBehavior: AppBarBehavior.scroll,
+ appBarBehavior: AppBarBehavior.under,
scrollableKey: scrollableKey,
appBar: new AppBar(
flexibleSpace: (BuildContext context) => new FlexibleSpaceBar(title: new Text(title))
diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart
index d478d6e..596bcd8 100644
--- a/packages/flutter/lib/src/material/app_bar.dart
+++ b/packages/flutter/lib/src/material/app_bar.dart
@@ -117,7 +117,7 @@
// If the toolBar's height shrinks below toolBarHeight, it will be clipped and bottom
// justified. This is so that the toolbar appears to move upwards as its height is reduced.
- final double toolBarHeight = kAppBarHeight + combinedPadding.top + combinedPadding.bottom;
+ final double toolBarHeight = kToolBarHeight + combinedPadding.top + combinedPadding.bottom;
final Widget toolBar = new ConstrainedBox(
constraints: new BoxConstraints(maxHeight: toolBarHeight),
child: new Padding(
diff --git a/packages/flutter/lib/src/material/constants.dart b/packages/flutter/lib/src/material/constants.dart
index 93f37f0..f56f506 100644
--- a/packages/flutter/lib/src/material/constants.dart
+++ b/packages/flutter/lib/src/material/constants.dart
@@ -9,7 +9,7 @@
// Mobile Landscape: 48dp
// Mobile Portrait: 56dp
// Tablet/Desktop: 64dp
-const double kAppBarHeight = 56.0;
+const double kToolBarHeight = 56.0;
const double kExtendedAppBarHeight = 128.0;
const double kTextTabBarHeight = 48.0;
diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart
index b9d4408..f61b63e 100644
--- a/packages/flutter/lib/src/material/flexible_space_bar.dart
+++ b/packages/flutter/lib/src/material/flexible_space_bar.dart
@@ -27,7 +27,7 @@
final double appBarHeight = Scaffold.of(context).appBarHeight;
final Animation<double> animation = Scaffold.of(context).appBarAnimation;
final EdgeInsets toolBarPadding = MediaQuery.of(context)?.padding ?? EdgeInsets.zero;
- final double toolBarHeight = kAppBarHeight + toolBarPadding.top;
+ final double toolBarHeight = kToolBarHeight + toolBarPadding.top;
final List<Widget> children = <Widget>[];
// background image
@@ -63,7 +63,7 @@
color: titleStyle.color.withAlpha(new Tween<double>(begin: 255.0, end: 0.0).evaluate(opacityCurve).toInt())
);
final double yAlignStart = 1.0;
- final double yAlignEnd = (toolBarPadding.top + kAppBarHeight / 2.0) / toolBarHeight;
+ final double yAlignEnd = (toolBarPadding.top + kToolBarHeight / 2.0) / toolBarHeight;
final double scaleAndAlignEnd = (appBarHeight - toolBarHeight) / appBarHeight;
final CurvedAnimation scaleAndAlignCurve = new CurvedAnimation(
parent: animation,
diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart
index 8cb699d..954d3de 100644
--- a/packages/flutter/lib/src/material/scaffold.dart
+++ b/packages/flutter/lib/src/material/scaffold.dart
@@ -20,9 +20,25 @@
const double _kFloatingActionButtonMargin = 16.0; // TODO(hmuller): should be device dependent
const Duration _kFloatingActionButtonSegue = const Duration(milliseconds: 400);
+/// The Scaffold's appbar is the toolbar, tabbar, and the "flexible space" that's
+/// stacked behind them. The Scaffold's appBarBehavior defines how the appbar
+/// responds to scrolling the application.
enum AppBarBehavior {
+ /// The tool bar's layout does not respond to scrolling.
anchor,
+
+ /// The tool bar's appearance and layout depend on the scrollOffset of the
+ /// Scrollable identified by the Scaffold's scrollableKey. With the scrollOffset
+ /// at 0.0, scrolling downwards causes the toolbar's flexible space to shrink,
+ /// and then the entire toolbar fade outs and scrolls off the top of the screen.
+ /// Scrolling upwards always causes the toolbar to reappear.
scroll,
+
+ /// The tool bar's appearance and layout depend on the scrollOffset of the
+ /// Scrollable identified by the Scaffold's scrollableKey. With the scrollOffset
+ /// at 0.0, Scrolling downwards causes the toolbar's flexible space to shrink.
+ /// Other than that, the toolbar remains anchored at the top.
+ under,
}
enum _ScaffoldSlot {
@@ -192,7 +208,7 @@
this.appBarHeight
}) : super(key: key) {
assert((appBarBehavior == AppBarBehavior.scroll) ? scrollableKey != null : true);
- assert((appBarBehavior == AppBarBehavior.scroll) ? appBarHeight != null && appBarHeight > kAppBarHeight : true);
+ assert((appBarBehavior == AppBarBehavior.scroll) ? appBarHeight != null && appBarHeight > kToolBarHeight : true);
}
final AppBar appBar;
@@ -430,36 +446,53 @@
));
}
+ Widget _buildAnchoredAppBar(double toolBarHeight, EdgeInsets toolBarPadding) {
+ // Drive _appBarController to the point where the flexible space has disappeared.
+ _appBarController.value = (appBarHeight - toolBarHeight) / appBarHeight;
+ return new SizedBox(
+ height: toolBarHeight,
+ child: _getModifiedAppBar(padding: toolBarPadding)
+ );
+ }
+
Widget _buildScrollableAppBar(BuildContext context) {
- final EdgeInsets appBarPadding = MediaQuery.of(context)?.padding ?? EdgeInsets.zero;
- final double appBarHeight = kAppBarHeight + appBarPadding.top;
+ final EdgeInsets toolBarPadding = MediaQuery.of(context)?.padding ?? EdgeInsets.zero;
+ final double toolBarHeight = kToolBarHeight + toolBarPadding.top;
Widget appBar;
- if (_scrollOffset <= appBarHeight && _scrollOffset >= appBarHeight - appBarHeight) {
- // scrolled to the top, only the app bar is (partially) visible
- final double height = math.max(_floatingAppBarHeight, appBarHeight - _scrollOffset);
- final double opacity = _appBarOpacity(1.0 - ((appBarHeight - height) / appBarHeight));
- _appBarController.value = (appBarHeight - height) / appBarHeight;
- appBar = new SizedBox(
- height: height,
- child: _getModifiedAppBar(padding: appBarPadding, foregroundOpacity: opacity)
- );
+ if (_scrollOffset <= appBarHeight && _scrollOffset >= appBarHeight - toolBarHeight) {
+ // scrolled to the top, only the toolbar is (partially) visible.
+ if (config.appBarBehavior == AppBarBehavior.under) {
+ appBar = _buildAnchoredAppBar(toolBarHeight, toolBarPadding);
+ } else {
+ final double height = math.max(_floatingAppBarHeight, appBarHeight - _scrollOffset);
+ final double opacity = _appBarOpacity(1.0 - ((toolBarHeight - height) / toolBarHeight));
+ _appBarController.value = (appBarHeight - height) / appBarHeight;
+ appBar = new SizedBox(
+ height: height,
+ child: _getModifiedAppBar(padding: toolBarPadding, foregroundOpacity: opacity)
+ );
+ }
} else if (_scrollOffset > appBarHeight) {
- // scrolled down, show the "floating" app bar
- _floatingAppBarHeight = (_floatingAppBarHeight + _scrollOffsetDelta).clamp(0.0, appBarHeight);
- final double appBarOpacity = _appBarOpacity(_floatingAppBarHeight / appBarHeight);
- _appBarController.value = (appBarHeight - _floatingAppBarHeight) / appBarHeight;
- appBar = new SizedBox(
- height: _floatingAppBarHeight,
- child: _getModifiedAppBar(padding: appBarPadding, foregroundOpacity: appBarOpacity)
- );
+ // scrolled past the entire app bar, maybe show the "floating" toolbar.
+ if (config.appBarBehavior == AppBarBehavior.under) {
+ appBar = _buildAnchoredAppBar(toolBarHeight, toolBarPadding);
+ } else {
+ _floatingAppBarHeight = (_floatingAppBarHeight + _scrollOffsetDelta).clamp(0.0, toolBarHeight);
+ final double toolBarOpacity = _appBarOpacity(_floatingAppBarHeight / toolBarHeight);
+ _appBarController.value = (appBarHeight - _floatingAppBarHeight) / appBarHeight;
+ appBar = new SizedBox(
+ height: _floatingAppBarHeight,
+ child: _getModifiedAppBar(padding: toolBarPadding, foregroundOpacity: toolBarOpacity)
+ );
+ }
} else {
// _scrollOffset < appBarHeight - appBarHeight, scrolled to the top, flexible space is visible
final double height = appBarHeight - _scrollOffset.clamp(0.0, appBarHeight);
_appBarController.value = (appBarHeight - height) / appBarHeight;
appBar = new SizedBox(
height: height,
- child: _getModifiedAppBar(padding: appBarPadding, elevation: 0)
+ child: _getModifiedAppBar(padding: toolBarPadding, elevation: 0)
);
_floatingAppBarHeight = 0.0;
}
@@ -468,10 +501,10 @@
}
Widget build(BuildContext context) {
- EdgeInsets padding = MediaQuery.of(context)?.padding ?? EdgeInsets.zero;
+ final EdgeInsets padding = MediaQuery.of(context)?.padding ?? EdgeInsets.zero;
if (_snackBars.length > 0) {
- ModalRoute<dynamic> route = ModalRoute.of(context);
+ final ModalRoute<dynamic> route = ModalRoute.of(context);
if (route == null || route.isCurrent) {
if (_snackBarController.isCompleted && _snackBarTimer == null)
_snackBarTimer = new Timer(_snackBars.first._widget.duration, _hideSnackBar);
@@ -484,7 +517,7 @@
final List<LayoutId> children = new List<LayoutId>();
_addIfNonNull(children, config.body, _ScaffoldSlot.body);
if (config.appBarBehavior == AppBarBehavior.anchor) {
- Widget appBar = new ConstrainedBox(
+ final Widget appBar = new ConstrainedBox(
child: _getModifiedAppBar(padding: padding),
constraints: new BoxConstraints(maxHeight: config.appBarHeight ?? kExtendedAppBarHeight + padding.top)
);
@@ -494,7 +527,7 @@
if (_currentBottomSheet != null ||
(_dismissedBottomSheets != null && _dismissedBottomSheets.isNotEmpty)) {
- List<Widget> bottomSheets = <Widget>[];
+ final List<Widget> bottomSheets = <Widget>[];
if (_dismissedBottomSheets != null && _dismissedBottomSheets.isNotEmpty)
bottomSheets.addAll(_dismissedBottomSheets);
if (_currentBottomSheet != null)
@@ -510,7 +543,7 @@
_addIfNonNull(children, _snackBars.first._widget, _ScaffoldSlot.snackBar);
if (config.floatingActionButton != null) {
- Widget fab = new _FloatingActionButtonTransition(
+ final Widget fab = new _FloatingActionButtonTransition(
key: new ValueKey<Key>(config.floatingActionButton.key),
child: config.floatingActionButton
);
@@ -529,8 +562,7 @@
Widget application;
- if (config.appBarBehavior == AppBarBehavior.scroll) {
- double overScroll = _scrollOffset.clamp(double.NEGATIVE_INFINITY, 0.0);
+ if (config.appBarBehavior != AppBarBehavior.anchor) {
application = new NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification,
child: new Stack(
@@ -542,7 +574,7 @@
)
),
new Positioned(
- top: -overScroll,
+ top: 0.0,
left: 0.0,
right: 0.0,
child: _buildScrollableAppBar(context)
diff --git a/packages/flutter/lib/src/widgets/scrollable_list.dart b/packages/flutter/lib/src/widgets/scrollable_list.dart
index 5641b1e..b8bfbdc 100644
--- a/packages/flutter/lib/src/widgets/scrollable_list.dart
+++ b/packages/flutter/lib/src/widgets/scrollable_list.dart
@@ -45,7 +45,7 @@
}
class _ScrollableListState extends ScrollableState<ScrollableList> {
- ScrollBehavior<double, double> createScrollBehavior() => new OverscrollBehavior();
+ ScrollBehavior<double, double> createScrollBehavior() => new OverscrollWhenScrollableBehavior();
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
void _handleExtentsChanged(double contentExtent, double containerExtent) {