Commit 082730e9 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Tapping status bar scrolls to top on IOS (#5425)

parent ba53d192
......@@ -128,15 +128,18 @@ class TravelDestinationItem extends StatelessWidget {
}
class CardsDemo extends StatelessWidget {
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
static const String routeName = '/cards';
@override
Widget build(BuildContext context) {
return new Scaffold(
scrollableKey: _scrollableKey,
appBar: new AppBar(
title: new Text('Travel stream')
),
body: new ScrollableList(
scrollableKey: _scrollableKey,
itemExtent: TravelDestinationItem.height,
padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0),
children: destinations.map((TravelDestination destination) {
......
......@@ -8,8 +8,9 @@ import 'package:flutter/widgets.dart';
const double kColorItemHeight = 48.0;
class ColorSwatch {
const ColorSwatch({ this.name, this.colors, this.accentColors, this.threshold: 900});
ColorSwatch({ this.name, this.colors, this.accentColors, this.threshold: 900});
final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
final String name;
final Map<int, Color> colors;
final Map<int, Color> accentColors;
......@@ -18,26 +19,26 @@ class ColorSwatch {
bool get isValid => this.name != null && this.colors != null && threshold != null;
}
const List<ColorSwatch> colorSwatches = const <ColorSwatch>[
const ColorSwatch(name: 'RED', colors: Colors.red, accentColors: Colors.redAccent, threshold: 300),
const ColorSwatch(name: 'PINK', colors: Colors.pink, accentColors: Colors.pinkAccent, threshold: 200),
const ColorSwatch(name: 'PURPLE', colors: Colors.purple, accentColors: Colors.purpleAccent, threshold: 200),
const ColorSwatch(name: 'DEEP PURPLE', colors: Colors.deepPurple, accentColors: Colors.deepPurpleAccent, threshold: 200),
const ColorSwatch(name: 'INDIGO', colors: Colors.indigo, accentColors: Colors.indigoAccent, threshold: 200),
const ColorSwatch(name: 'BLUE', colors: Colors.blue, accentColors: Colors.blueAccent, threshold: 400),
const ColorSwatch(name: 'LIGHT BLUE', colors: Colors.lightBlue, accentColors: Colors.lightBlueAccent, threshold: 500),
const ColorSwatch(name: 'CYAN', colors: Colors.cyan, accentColors: Colors.cyanAccent, threshold: 600),
const ColorSwatch(name: 'TEAL', colors: Colors.teal, accentColors: Colors.tealAccent, threshold: 400),
const ColorSwatch(name: 'GREEN', colors: Colors.green, accentColors: Colors.greenAccent, threshold: 500),
const ColorSwatch(name: 'LIGHT GREEN', colors: Colors.lightGreen, accentColors: Colors.lightGreenAccent, threshold: 600),
const ColorSwatch(name: 'LIME', colors: Colors.lime, accentColors: Colors.limeAccent, threshold: 800),
const ColorSwatch(name: 'YELLOW', colors: Colors.yellow, accentColors: Colors.yellowAccent),
const ColorSwatch(name: 'AMBER', colors: Colors.amber, accentColors: Colors.amberAccent),
const ColorSwatch(name: 'ORANGE', colors: Colors.orange, accentColors: Colors.orangeAccent, threshold: 700),
const ColorSwatch(name: 'DEEP ORANGE', colors: Colors.deepOrange, accentColors: Colors.deepOrangeAccent, threshold: 400),
const ColorSwatch(name: 'BROWN', colors: Colors.brown, threshold: 200),
const ColorSwatch(name: 'GREY', colors: Colors.grey, threshold: 500),
const ColorSwatch(name: 'BLUE GREY', colors: Colors.blueGrey, threshold: 500)
final List<ColorSwatch> colorSwatches = <ColorSwatch>[
new ColorSwatch(name: 'RED', colors: Colors.red, accentColors: Colors.redAccent, threshold: 300),
new ColorSwatch(name: 'PINK', colors: Colors.pink, accentColors: Colors.pinkAccent, threshold: 200),
new ColorSwatch(name: 'PURPLE', colors: Colors.purple, accentColors: Colors.purpleAccent, threshold: 200),
new ColorSwatch(name: 'DEEP PURPLE', colors: Colors.deepPurple, accentColors: Colors.deepPurpleAccent, threshold: 200),
new ColorSwatch(name: 'INDIGO', colors: Colors.indigo, accentColors: Colors.indigoAccent, threshold: 200),
new ColorSwatch(name: 'BLUE', colors: Colors.blue, accentColors: Colors.blueAccent, threshold: 400),
new ColorSwatch(name: 'LIGHT BLUE', colors: Colors.lightBlue, accentColors: Colors.lightBlueAccent, threshold: 500),
new ColorSwatch(name: 'CYAN', colors: Colors.cyan, accentColors: Colors.cyanAccent, threshold: 600),
new ColorSwatch(name: 'TEAL', colors: Colors.teal, accentColors: Colors.tealAccent, threshold: 400),
new ColorSwatch(name: 'GREEN', colors: Colors.green, accentColors: Colors.greenAccent, threshold: 500),
new ColorSwatch(name: 'LIGHT GREEN', colors: Colors.lightGreen, accentColors: Colors.lightGreenAccent, threshold: 600),
new ColorSwatch(name: 'LIME', colors: Colors.lime, accentColors: Colors.limeAccent, threshold: 800),
new ColorSwatch(name: 'YELLOW', colors: Colors.yellow, accentColors: Colors.yellowAccent),
new ColorSwatch(name: 'AMBER', colors: Colors.amber, accentColors: Colors.amberAccent),
new ColorSwatch(name: 'ORANGE', colors: Colors.orange, accentColors: Colors.orangeAccent, threshold: 700),
new ColorSwatch(name: 'DEEP ORANGE', colors: Colors.deepOrange, accentColors: Colors.deepOrangeAccent, threshold: 400),
new ColorSwatch(name: 'BROWN', colors: Colors.brown, threshold: 200),
new ColorSwatch(name: 'GREY', colors: Colors.grey, threshold: 500),
new ColorSwatch(name: 'BLUE GREY', colors: Colors.blueGrey, threshold: 500)
];
......@@ -102,20 +103,43 @@ class ColorSwatchTabView extends StatelessWidget {
}
return new ScrollableList(
scrollableKey: swatch.scrollableKey,
itemExtent: kColorItemHeight,
children: colorItems
);
}
}
class ColorsDemo extends StatelessWidget {
class ColorsDemo extends StatefulWidget {
ColorsDemo({ Key key }) : super(key: key);
static const String routeName = '/colors';
@override
_ColorsDemoState createState() => new _ColorsDemoState();
}
class _ColorsDemoState extends State<ColorsDemo> {
ColorSwatch _selectedSwatch;
@override
void initState() {
super.initState();
_selectedSwatch = colorSwatches.first;
}
@override
Widget build(BuildContext context) {
return new TabBarSelection<ColorSwatch>(
values: colorSwatches,
onChanged: (ColorSwatch value) {
setState(() {
_selectedSwatch = value;
});
},
child: new Scaffold(
scrollableKey: _selectedSwatch.scrollableKey,
appBar: new AppBar(
elevation: 0,
title: new Text('Colors'),
......
......@@ -80,7 +80,8 @@ class ContactsDemo extends StatefulWidget {
}
class ContactsDemoState extends State<ContactsDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
final double _appBarHeight = 256.0;
AppBarBehavior _appBarBehavior = AppBarBehavior.under;
......@@ -94,6 +95,7 @@ class ContactsDemoState extends State<ContactsDemo> {
),
child: new Scaffold(
key: _scaffoldKey,
scrollableKey: _scrollableKey,
appBarBehavior: _appBarBehavior,
appBar: new AppBar(
expandedHeight: _appBarHeight,
......@@ -151,6 +153,7 @@ class ContactsDemoState extends State<ContactsDemo> {
),
body: new Block(
padding: new EdgeInsets.only(top: _appBarHeight + statusBarHeight),
scrollableKey: _scrollableKey,
children: <Widget>[
new _ContactCategory(
icon: Icons.call,
......
......@@ -133,7 +133,8 @@ class GridListDemo extends StatefulWidget {
}
class GridListDemoState extends State<GridListDemo> {
GridDemoTileStyle tileStyle = GridDemoTileStyle.twoLine;
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
GridDemoTileStyle _tileStyle = GridDemoTileStyle.twoLine;
List<Photo> photos = <Photo>[
new Photo(
......@@ -200,7 +201,7 @@ class GridListDemoState extends State<GridListDemo> {
void changeTileStyle(GridDemoTileStyle value) {
setState(() {
tileStyle = value;
_tileStyle = value;
});
}
......@@ -211,6 +212,7 @@ class GridListDemoState extends State<GridListDemo> {
Widget build(BuildContext context) {
final Orientation orientation = MediaQuery.of(context).orientation;
return new Scaffold(
scrollableKey: _scrollableKey,
appBar: new AppBar(
title: new Text('Grid list'),
actions: <Widget>[
......@@ -237,6 +239,7 @@ class GridListDemoState extends State<GridListDemo> {
children: <Widget>[
new Flexible(
child: new ScrollableGrid(
scrollableKey: _scrollableKey,
delegate: new FixedColumnCountGridDelegate(
columnCount: (orientation == Orientation.portrait) ? 2 : 3,
rowSpacing: 4.0,
......@@ -247,7 +250,7 @@ class GridListDemoState extends State<GridListDemo> {
children: photos.map((Photo photo) {
return new GridDemoPhotoItem(
photo: photo,
tileStyle: tileStyle,
tileStyle: _tileStyle,
onBannerTap: (Photo photo) {
setState(() {
photo.isFavorite = !photo.isFavorite;
......
......@@ -38,7 +38,8 @@ class LeaveBehindDemo extends StatefulWidget {
}
class LeaveBehindDemoState extends State<LeaveBehindDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
DismissDirection _dismissDirection = DismissDirection.horizontal;
List<LeaveBehindItem> leaveBehindItems;
......@@ -131,6 +132,7 @@ class LeaveBehindDemoState extends State<LeaveBehindDemo> {
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
scrollableKey: _scrollableKey,
appBar: new AppBar(
title: new Text('Swipe items to dismiss'),
actions: <Widget>[
......@@ -161,7 +163,10 @@ class LeaveBehindDemoState extends State<LeaveBehindDemo> {
)
]
),
body: new Block(children: leaveBehindItems.map(buildItem).toList())
body: new Block(
scrollableKey: _scrollableKey,
children: leaveBehindItems.map(buildItem).toList()
)
);
}
}
......@@ -14,7 +14,8 @@ class ListDemo extends StatefulWidget {
}
class ListDemoState extends State<ListDemo> {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
PersistentBottomSheetController<Null> _bottomSheet;
MaterialListType _itemType = MaterialListType.threeLine;
......@@ -171,6 +172,7 @@ class ListDemoState extends State<ListDemo> {
return new Scaffold(
key: scaffoldKey,
scrollableKey: _scrollableKey,
appBar: new AppBar(
title: new Text('Scrolling list\n$itemTypeText$layoutText'),
actions: <Widget>[
......@@ -193,6 +195,7 @@ class ListDemoState extends State<ListDemo> {
),
body: new Scrollbar(
child: new MaterialList(
scrollableKey: _scrollableKey,
type: _itemType,
padding: new EdgeInsets.symmetric(vertical: _dense ? 4.0 : 8.0),
children: listItems
......
......@@ -90,6 +90,7 @@ class OverscrollDemoState extends State<OverscrollDemo> {
return new Scaffold(
key: _scaffoldKey,
scrollableKey: _scrollableKey,
appBar: new AppBar(
title: new Text('$indicatorTypeText'),
actions: <Widget>[
......
......@@ -51,6 +51,8 @@ class PestoDemo extends StatefulWidget {
class _PestoDemoState extends State<PestoDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
static final GlobalKey<ScrollableState> _homeScrollableKey = new GlobalKey<ScrollableState>();
static final GlobalKey<ScrollableState> _favoritesScrollableKey = new GlobalKey<ScrollableState>();
final TextStyle favoritesMessageStyle = _textStyle(16.0);
final TextStyle userStyle = _textStyle(12.0, FontWeight.bold);
final TextStyle emailStyle = _textStyle(12.0).copyWith(color: Colors.black54);
......@@ -61,6 +63,7 @@ class _PestoDemoState extends State<PestoDemo> {
data: _kTheme,
child: new Scaffold(
key: _scaffoldKey,
scrollableKey: config.showFavorites ? _favoritesScrollableKey : _homeScrollableKey,
appBarBehavior: AppBarBehavior.under,
appBar: _buildAppBar(context),
drawer: _buildDrawer(context),
......@@ -180,6 +183,7 @@ class _PestoDemoState extends State<PestoDemo> {
}
return new ScrollableGrid(
scrollableKey: config.showFavorites ? _favoritesScrollableKey : _homeScrollableKey,
delegate: new MaxTileWidthGridDelegate(
maxTileWidth: 500.0,
rowSpacing: 8.0,
......@@ -282,7 +286,8 @@ class _RecipePage extends StatefulWidget {
}
class _RecipePageState extends State<_RecipePage> {
static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
final TextStyle menuItemStyle = _textStyle(15.0).copyWith(color: Colors.black54, height: 24.0/15.0);
double _getAppBarHeight(BuildContext context) => MediaQuery.of(context).size.height * 0.3;
......@@ -291,6 +296,7 @@ class _RecipePageState extends State<_RecipePage> {
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
scrollableKey: _scrollableKey,
appBarBehavior: AppBarBehavior.scroll,
appBar: new AppBar(
expandedHeight: _getAppBarHeight(context),
......@@ -347,6 +353,7 @@ class _RecipePageState extends State<_RecipePage> {
new ClampOverscrolls(
value: true,
child: new ScrollableViewport(
scrollableKey: _scrollableKey,
child: new RepaintBoundary(
child: new Padding(
padding: new EdgeInsets.only(top: appBarHeight),
......
......@@ -293,6 +293,7 @@ class ShrineHome extends StatefulWidget {
class _ShrineHomeState extends State<ShrineHome> {
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: 'Order page');
static final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
static final GridDelegate gridDelegate = new ShrineGridDelegate();
void handleCompletedOrder(Order completedOrder) {
......@@ -323,9 +324,11 @@ class _ShrineHomeState extends State<ShrineHome> {
final Product featured = _products.firstWhere((Product product) => product.featureDescription != null);
return new ShrinePage(
scaffoldKey: scaffoldKey,
scrollableKey: scrollableKey,
products: _products,
shoppingCart: _shoppingCart,
body: new ScrollableViewport(
scrollableKey: scrollableKey,
child: new RepaintBoundary(
child: new Column(
children: <Widget>[
......
......@@ -137,6 +137,7 @@ class OrderPage extends StatefulWidget {
/// order to the shopping cart.
class _OrderPageState extends State<OrderPage> {
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: 'Order page');
static final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
Order get currentOrder => ShrineOrderRoute.of(context).order;
......@@ -162,6 +163,7 @@ class _OrderPageState extends State<OrderPage> {
Widget build(BuildContext context) {
return new ShrinePage(
scaffoldKey: scaffoldKey,
scrollableKey: scrollableKey,
products: config.products,
shoppingCart: config.shoppingCart,
floatingActionButton: new FloatingActionButton(
......@@ -180,6 +182,7 @@ class _OrderPageState extends State<OrderPage> {
)
),
body: new Block(
scrollableKey: scrollableKey,
children: <Widget>[
new OrderItem(
product: config.order.product,
......
......@@ -17,6 +17,7 @@ class ShrinePage extends StatefulWidget {
ShrinePage({
Key key,
this.scaffoldKey,
this.scrollableKey,
this.body,
this.floatingActionButton,
this.products,
......@@ -27,6 +28,7 @@ class ShrinePage extends StatefulWidget {
}
final GlobalKey<ScaffoldState> scaffoldKey;
final GlobalKey<ScrollableState> scrollableKey;
final Widget body;
final Widget floatingActionButton;
final List<Product> products;
......@@ -86,6 +88,7 @@ class ShrinePageState extends State<ShrinePage> {
final ShrineTheme theme = ShrineTheme.of(context);
return new Scaffold(
key: config.scaffoldKey,
scrollableKey: config.scrollableKey,
appBar: new AppBar(
elevation: _appBarElevation,
backgroundColor: theme.appBarBackgroundColor,
......
......@@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
class _Page {
_Page({ this.label });
final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
final String label;
String get id => label[0];
}
......@@ -111,14 +112,35 @@ class _CardDataItem extends StatelessWidget {
}
}
class TabsDemo extends StatelessWidget {
class TabsDemo extends StatefulWidget {
TabsDemo({ Key key }) : super(key: key);
static const String routeName = '/tabs';
@override
_TabsDemoState createState() => new _TabsDemoState();
}
class _TabsDemoState extends State<TabsDemo> {
_Page _selectedPage;
@override
void initState() {
super.initState();
_selectedPage = _allPages.keys.first;
}
@override
Widget build(BuildContext context) {
return new TabBarSelection<_Page>(
values: _allPages.keys.toList(),
onChanged: (_Page value) {
setState(() {
_selectedPage = value;
});
},
child: new Scaffold(
scrollableKey: _selectedPage.scrollableKey,
appBar: new AppBar(
title: new Text('Tabs and scrolling'),
bottom: new TabBar<_Page>(
......@@ -130,6 +152,7 @@ class TabsDemo extends StatelessWidget {
body: new TabBarView<_Page>(
children: _allPages.keys.map((_Page page) {
return new ScrollableList(
scrollableKey: _selectedPage.scrollableKey,
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
itemExtent: _CardDataItem.height,
children: _allPages[page].map((_CardData data) {
......
......@@ -97,7 +97,8 @@ class GalleryHome extends StatefulWidget {
}
class GalleryHomeState extends State<GalleryHome> {
final Key _homeKey = new ValueKey<String>("Gallery Home");
static final Key _homeKey = new ValueKey<String>("Gallery Home");
static final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
final List<Widget> _listItems = <Widget>[];
@override
......@@ -135,6 +136,7 @@ class GalleryHomeState extends State<GalleryHome> {
Widget build(BuildContext context) {
return new Scaffold(
key: _homeKey,
scrollableKey: _scrollableKey,
drawer: new GalleryDrawer(
useLightTheme: config.useLightTheme,
onThemeChanged: config.onThemeChanged,
......@@ -157,7 +159,10 @@ class GalleryHomeState extends State<GalleryHome> {
)
),
appBarBehavior: AppBarBehavior.under,
body: new Block(children: _listItems)
body: new Block(
scrollableKey: _scrollableKey,
children: _listItems
)
);
}
}
......@@ -16,6 +16,7 @@ import 'icon_button.dart';
import 'icons.dart';
import 'material.dart';
import 'snack_bar.dart';
import 'theme.dart';
const double _kFloatingActionButtonMargin = 16.0; // TODO(hmuller): should be device dependent
const Duration _kFloatingActionButtonSegue = const Duration(milliseconds: 200);
......@@ -52,12 +53,18 @@ enum _ScaffoldSlot {
snackBar,
floatingActionButton,
drawer,
statusBar,
}
class _ScaffoldLayout extends MultiChildLayoutDelegate {
_ScaffoldLayout({ this.padding, this.appBarBehavior: AppBarBehavior.anchor });
_ScaffoldLayout({
this.padding,
this.statusBarHeight,
this.appBarBehavior: AppBarBehavior.anchor
});
final EdgeInsets padding;
final double statusBarHeight;
final AppBarBehavior appBarBehavior;
@override
......@@ -120,6 +127,11 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
positionChild(_ScaffoldSlot.floatingActionButton, new Offset(fabX, fabY));
}
if (hasChild(_ScaffoldSlot.statusBar)) {
layoutChild(_ScaffoldSlot.statusBar, fullWidthConstraints.tighten(height: statusBarHeight));
positionChild(_ScaffoldSlot.statusBar, Offset.zero);
}
if (hasChild(_ScaffoldSlot.drawer)) {
layoutChild(_ScaffoldSlot.drawer, new BoxConstraints.tight(size));
positionChild(_ScaffoldSlot.drawer, Offset.zero);
......@@ -270,9 +282,7 @@ class Scaffold extends StatefulWidget {
this.scrollableKey,
this.appBarBehavior: AppBarBehavior.anchor,
this.resizeToAvoidBottomPadding: true
}) : super(key: key) {
assert(scrollableKey != null ? (appBarBehavior != AppBarBehavior.anchor) : true);
}
}) : super(key: key);
/// An app bar to display at the top of the scaffold.
final AppBar appBar;
......@@ -298,7 +308,7 @@ class Scaffold extends StatefulWidget {
///
/// Used to control scroll-linked effects, such as the collapse of the
/// [appBar].
final Key scrollableKey;
final GlobalKey<ScrollableState> scrollableKey;
/// How the [appBar] should respond to scrolling.
///
......@@ -663,6 +673,19 @@ class ScaffoldState extends State<Scaffold> {
return appBar;
}
// On iOS, tapping the status bar scrolls the app's primary scrollable to the top.
void _handleStatusBarTap() {
ScrollableState scrollable = config.scrollableKey?.currentState;
if (scrollable == null || scrollable.scrollBehavior is! ExtentScrollBehavior)
return;
ExtentScrollBehavior behavior = scrollable.scrollBehavior;
scrollable.scrollTo(
behavior.minScrollOffset,
duration: const Duration(milliseconds: 300)
);
}
@override
Widget build(BuildContext context) {
EdgeInsets padding = MediaQuery.of(context).padding;
......@@ -729,6 +752,16 @@ class ScaffoldState extends State<Scaffold> {
)
));
if (Theme.of(context).platform == TargetPlatform.iOS) {
children.add(new LayoutId(
id: _ScaffoldSlot.statusBar,
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: _handleStatusBarTap
)
));
}
if (config.drawer != null) {
children.add(new LayoutId(
id: _ScaffoldSlot.drawer,
......@@ -739,12 +772,12 @@ class ScaffoldState extends State<Scaffold> {
));
}
EdgeInsets appPadding = (config.appBarBehavior != AppBarBehavior.anchor) ?
EdgeInsets.zero : padding;
EdgeInsets appPadding = (config.appBarBehavior != AppBarBehavior.anchor) ? EdgeInsets.zero : padding;
Widget application = new CustomMultiChildLayout(
children: children,
delegate: new _ScaffoldLayout(
padding: appPadding,
statusBarHeight: padding.top,
appBarBehavior: config.appBarBehavior
)
);
......
......@@ -128,4 +128,72 @@ void main() {
RenderBox renderBox = tester.renderObject(find.byKey(appBarKey));
expect(renderBox.size.height, equals(appBarHeight));
});
testWidgets('Tapping the status bar scrolls to top on iOS', (WidgetTester tester) async {
final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
final Key appBarKey = new UniqueKey();
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(platform: TargetPlatform.iOS),
home: new MediaQuery(
data: new MediaQueryData(padding: const EdgeInsets.only(top: 25.0)), // status bar
child: new Scaffold(
scrollableKey: scrollableKey,
appBar: new AppBar(
key: appBarKey,
title: new Text('Title')
),
body: new Block(
scrollableKey: scrollableKey,
initialScrollOffset: 500.0,
children: new List<Widget>.generate(20,
(int index) => new SizedBox(height: 100.0, child: new Text('$index'))
)
)
)
)
)
);
expect(scrollableKey.currentState.scrollOffset, equals(500.0));
await tester.tapAt(const Point(100.0, 10.0));
await tester.pump();
await tester.pump(new Duration(seconds: 1));
expect(scrollableKey.currentState.scrollOffset, equals(0.0));
});
testWidgets('Tapping the status bar does not scroll to top on Android', (WidgetTester tester) async {
final GlobalKey<ScrollableState> scrollableKey = new GlobalKey<ScrollableState>();
final Key appBarKey = new UniqueKey();
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(platform: TargetPlatform.android),
home: new MediaQuery(
data: new MediaQueryData(padding: const EdgeInsets.only(top: 25.0)), // status bar
child: new Scaffold(
scrollableKey: scrollableKey,
appBar: new AppBar(
key: appBarKey,
title: new Text('Title')
),
body: new Block(
scrollableKey: scrollableKey,
initialScrollOffset: 500.0,
children: new List<Widget>.generate(20,
(int index) => new SizedBox(height: 100.0, child: new Text('$index'))
)
)
)
)
)
);
expect(scrollableKey.currentState.scrollOffset, equals(500.0));
await tester.tapAt(const Point(100.0, 10.0));
await tester.pump();
await tester.pump(new Duration(seconds: 1));
expect(scrollableKey.currentState.scrollOffset, equals(500.0));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment