mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
Add a persistent bottom sheet to the stocks demo
This commit is contained in:
parent
c49f07eec0
commit
5755b15bf5
|
@ -81,7 +81,7 @@ class StocksAppState extends State<StocksApp> {
|
|||
if (path.length != 3)
|
||||
return null;
|
||||
if (_stocks.containsKey(path[2]))
|
||||
return (RouteArguments args) => new StockSymbolViewer(stock: _stocks[path[2]]);
|
||||
return (RouteArguments args) => new StockSymbolPage(stock: _stocks[path[2]]);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -20,6 +20,7 @@ class StockHome extends StatefulComponent {
|
|||
class StockHomeState extends State<StockHome> {
|
||||
|
||||
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
|
||||
final GlobalKey<PlaceholderState> _bottomSheetPlaceholderKey = new GlobalKey<PlaceholderState>();
|
||||
bool _isSearching = false;
|
||||
String _searchQuery;
|
||||
|
||||
|
@ -188,13 +189,20 @@ class StockHomeState extends State<StockHome> {
|
|||
});
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
child: new StockSymbolViewer(stock: stock, showToolBar: false)
|
||||
child: new StockSymbolBottomSheet(stock: stock)
|
||||
);
|
||||
},
|
||||
onOpen: (Stock stock, Key arrowKey) {
|
||||
Set<Key> mostValuableKeys = new Set<Key>();
|
||||
mostValuableKeys.add(arrowKey);
|
||||
Navigator.of(context).pushNamed('/stock/${stock.symbol}', mostValuableKeys: mostValuableKeys);
|
||||
},
|
||||
onShow: (Stock stock, Key arrowKey) {
|
||||
showBottomSheet(
|
||||
placeholderKey: _bottomSheetPlaceholderKey,
|
||||
context: context,
|
||||
child: new StockSymbolBottomSheet(stock: stock)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -267,6 +275,7 @@ class StockHomeState extends State<StockHome> {
|
|||
toolBar: _isSearching ? buildSearchBar() : buildToolBar(),
|
||||
body: buildTabNavigator(),
|
||||
snackBar: new Placeholder(key: _snackBarPlaceholderKey),
|
||||
bottomSheet: new Placeholder(key: _bottomSheetPlaceholderKey),
|
||||
floatingActionButton: buildFloatingActionButton()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
part of stocks;
|
||||
|
||||
class StockList extends StatelessComponent {
|
||||
StockList({ Key key, this.stocks, this.onOpen, this.onAction }) : super(key: key);
|
||||
StockList({ Key key, this.stocks, this.onOpen, this.onShow, this.onAction }) : super(key: key);
|
||||
|
||||
final List<Stock> stocks;
|
||||
final StockRowActionCallback onOpen;
|
||||
final StockRowActionCallback onShow;
|
||||
final StockRowActionCallback onAction;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -19,6 +20,7 @@ class StockList extends StatelessComponent {
|
|||
return new StockRow(
|
||||
stock: stock,
|
||||
onPressed: onOpen,
|
||||
onDoubleTap: onShow,
|
||||
onLongPressed: onAction
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ class StockRow extends StatelessComponent {
|
|||
StockRow({
|
||||
Stock stock,
|
||||
this.onPressed,
|
||||
this.onDoubleTap,
|
||||
this.onLongPressed
|
||||
}) : this.stock = stock,
|
||||
_arrowKey = new StockRowPartKey(stock, StockRowPartKind.arrow),
|
||||
|
@ -34,22 +35,15 @@ class StockRow extends StatelessComponent {
|
|||
|
||||
final Stock stock;
|
||||
final StockRowActionCallback onPressed;
|
||||
final StockRowActionCallback onDoubleTap;
|
||||
final StockRowActionCallback onLongPressed;
|
||||
|
||||
final Key _arrowKey;
|
||||
|
||||
static const double kHeight = 79.0;
|
||||
|
||||
GestureTapCallback _getTapHandler(StockRowActionCallback callback) {
|
||||
if (callback == null)
|
||||
return null;
|
||||
return () => callback(stock, _arrowKey);
|
||||
}
|
||||
|
||||
GestureLongPressCallback _getLongPressHandler(StockRowActionCallback callback) {
|
||||
if (callback == null)
|
||||
return null;
|
||||
return () => callback(stock, _arrowKey);
|
||||
GestureTapCallback _getHandler(StockRowActionCallback callback) {
|
||||
return callback == null ? null : () => callback(stock, _arrowKey);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -58,8 +52,9 @@ class StockRow extends StatelessComponent {
|
|||
if (stock.percentChange > 0)
|
||||
changeInPrice = "+" + changeInPrice;
|
||||
return new InkWell(
|
||||
onTap: _getTapHandler(onPressed),
|
||||
onLongPress: _getLongPressHandler(onLongPressed),
|
||||
onTap: _getHandler(onPressed),
|
||||
onDoubleTap: _getHandler(onDoubleTap),
|
||||
onLongPress: _getHandler(onLongPressed),
|
||||
child: new Container(
|
||||
padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0),
|
||||
decoration: new BoxDecoration(
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
|
||||
part of stocks;
|
||||
|
||||
class StockSymbolViewer extends StatelessComponent {
|
||||
StockSymbolViewer({ this.stock, this.showToolBar: true });
|
||||
class StockSymbolView extends StatelessComponent {
|
||||
StockSymbolView({ this.stock});
|
||||
|
||||
final Stock stock;
|
||||
final bool showToolBar;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
|
||||
|
@ -17,11 +16,7 @@ class StockSymbolViewer extends StatelessComponent {
|
|||
changeInPrice = "+" + changeInPrice;
|
||||
|
||||
TextStyle headings = Theme.of(context).text.body2;
|
||||
Widget body = new Block(<Widget>[
|
||||
new Container(
|
||||
margin: new EdgeDims.all(20.0),
|
||||
child: new Card(
|
||||
child: new Container(
|
||||
return new Container(
|
||||
padding: new EdgeDims.all(20.0),
|
||||
child: new Column(<Widget>[
|
||||
new Row(<Widget>[
|
||||
|
@ -44,15 +39,19 @@ class StockSymbolViewer extends StatelessComponent {
|
|||
),
|
||||
new Text('Market Cap', style: headings),
|
||||
new Text('${stock.marketCap}'),
|
||||
])
|
||||
],
|
||||
justifyContent: FlexJustifyContent.collapse
|
||||
)
|
||||
)
|
||||
)
|
||||
]);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!showToolBar)
|
||||
return body;
|
||||
class StockSymbolPage extends StatelessComponent {
|
||||
StockSymbolPage({ this.stock });
|
||||
|
||||
final Stock stock;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new Scaffold(
|
||||
toolBar: new ToolBar(
|
||||
left: new IconButton(
|
||||
|
@ -63,8 +62,28 @@ class StockSymbolViewer extends StatelessComponent {
|
|||
),
|
||||
center: new Text(stock.name)
|
||||
),
|
||||
body: body
|
||||
body: new Block(<Widget>[
|
||||
new Container(
|
||||
margin: new EdgeDims.all(20.0),
|
||||
child: new Card(child: new StockSymbolView(stock: stock))
|
||||
)
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StockSymbolBottomSheet extends StatelessComponent {
|
||||
StockSymbolBottomSheet({ this.stock });
|
||||
|
||||
final Stock stock;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new Container(
|
||||
child: new StockSymbolView(stock: stock),
|
||||
padding: new EdgeDims.all(10.0),
|
||||
decoration: new BoxDecoration(
|
||||
border: new Border(top: new BorderSide(color: Colors.black26, width: 1.0))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ class InkWell extends StatefulComponent {
|
|||
Key key,
|
||||
this.child,
|
||||
this.onTap,
|
||||
this.onDoubleTap,
|
||||
this.onLongPress,
|
||||
this.onHighlightChanged,
|
||||
this.defaultColor,
|
||||
|
@ -36,6 +37,7 @@ class InkWell extends StatefulComponent {
|
|||
|
||||
final Widget child;
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onDoubleTap;
|
||||
final GestureLongPressCallback onLongPress;
|
||||
final _HighlightChangedCallback onHighlightChanged;
|
||||
final Color defaultColor;
|
||||
|
@ -54,6 +56,7 @@ class _InkWellState extends State<InkWell> {
|
|||
duration: _kInkWellHighlightFadeDuration,
|
||||
child: new _InkSplashes(
|
||||
onTap: config.onTap,
|
||||
onDoubleTap: config.onDoubleTap,
|
||||
onLongPress: config.onLongPress,
|
||||
onHighlightChanged: (bool value) {
|
||||
setState(() {
|
||||
|
@ -134,10 +137,12 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
_RenderInkSplashes({
|
||||
RenderBox child,
|
||||
GestureTapCallback onTap,
|
||||
GestureTapCallback onDoubleTap,
|
||||
GestureLongPressCallback onLongPress,
|
||||
this.onHighlightChanged
|
||||
}) : super(child) {
|
||||
this.onTap = onTap;
|
||||
this.onDoubleTap = onDoubleTap;
|
||||
this.onLongPress = onLongPress;
|
||||
}
|
||||
|
||||
|
@ -148,6 +153,13 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
_syncTapRecognizer();
|
||||
}
|
||||
|
||||
GestureTapCallback get onDoubleTap => _onDoubleTap;
|
||||
GestureTapCallback _onDoubleTap;
|
||||
void set onDoubleTap (GestureTapCallback value) {
|
||||
_onDoubleTap = value;
|
||||
_syncDoubleTapRecognizer();
|
||||
}
|
||||
|
||||
GestureTapCallback get onLongPress => _onLongPress;
|
||||
GestureTapCallback _onLongPress;
|
||||
void set onLongPress (GestureTapCallback value) {
|
||||
|
@ -161,6 +173,7 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
_InkSplash _lastSplash;
|
||||
|
||||
TapGestureRecognizer _tap;
|
||||
DoubleTapGestureRecognizer _doubleTap;
|
||||
LongPressGestureRecognizer _longPress;
|
||||
|
||||
void _removeSplash(_InkSplash splash) {
|
||||
|
@ -170,8 +183,9 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
}
|
||||
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event.type == 'pointerdown' && (onTap != null || onLongPress != null)) {
|
||||
if (event.type == 'pointerdown' && (onTap != null || onDoubleTap != null || onLongPress != null)) {
|
||||
_tap?.addPointer(event);
|
||||
_doubleTap?.addPointer(event);
|
||||
_longPress?.addPointer(event);
|
||||
}
|
||||
}
|
||||
|
@ -179,17 +193,19 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
void attach() {
|
||||
super.attach();
|
||||
_syncTapRecognizer();
|
||||
_syncDoubleTapRecognizer();
|
||||
_syncLongPressRecognizer();
|
||||
}
|
||||
|
||||
void detach() {
|
||||
_disposeTapRecognizer();
|
||||
_disposeDoubleTapRecognizer();
|
||||
_disposeLongPressRecognizer();
|
||||
super.detach();
|
||||
}
|
||||
|
||||
void _syncTapRecognizer() {
|
||||
if (onTap == null && onLongPress == null) {
|
||||
if (onTap == null && doubleTap == null && onLongPress == null) {
|
||||
_disposeTapRecognizer();
|
||||
} else {
|
||||
_tap ??= new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
|
||||
|
@ -204,6 +220,20 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
_tap = null;
|
||||
}
|
||||
|
||||
void _syncDoubleTapRecognizer() {
|
||||
if (onDoubleTap == null) {
|
||||
_disposeDoubleTapRecognizer();
|
||||
} else {
|
||||
_doubleTap ??= new DoubleTapGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
|
||||
..onDoubleTap = _handleDoubleTap;
|
||||
}
|
||||
}
|
||||
|
||||
void _disposeDoubleTapRecognizer() {
|
||||
_doubleTap?.dispose();
|
||||
_doubleTap = null;
|
||||
}
|
||||
|
||||
void _syncLongPressRecognizer() {
|
||||
if (onLongPress == null) {
|
||||
_disposeLongPressRecognizer();
|
||||
|
@ -241,6 +271,13 @@ class _RenderInkSplashes extends RenderProxyBox {
|
|||
onHighlightChanged(false);
|
||||
}
|
||||
|
||||
void _handleDoubleTap() {
|
||||
_lastSplash?.confirm();
|
||||
_lastSplash = null;
|
||||
if (onDoubleTap != null)
|
||||
onDoubleTap();
|
||||
}
|
||||
|
||||
void _handleLongPress() {
|
||||
_lastSplash?.confirm();
|
||||
_lastSplash = null;
|
||||
|
@ -269,18 +306,26 @@ class _InkSplashes extends OneChildRenderObjectWidget {
|
|||
Key key,
|
||||
Widget child,
|
||||
this.onTap,
|
||||
this.onDoubleTap,
|
||||
this.onLongPress,
|
||||
this.onHighlightChanged
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
final GestureTapCallback onTap;
|
||||
final GestureTapCallback onDoubleTap;
|
||||
final GestureLongPressCallback onLongPress;
|
||||
final _HighlightChangedCallback onHighlightChanged;
|
||||
|
||||
_RenderInkSplashes createRenderObject() => new _RenderInkSplashes(onTap: onTap, onLongPress: onLongPress, onHighlightChanged: onHighlightChanged);
|
||||
_RenderInkSplashes createRenderObject() => new _RenderInkSplashes(
|
||||
onTap: onTap,
|
||||
onDoubleTap: onDoubleTap,
|
||||
onLongPress: onLongPress,
|
||||
onHighlightChanged: onHighlightChanged
|
||||
);
|
||||
|
||||
void updateRenderObject(_RenderInkSplashes renderObject, _InkSplashes oldWidget) {
|
||||
renderObject.onTap = onTap;
|
||||
renderObject.onDoubleTap = onDoubleTap;
|
||||
renderObject.onLongPress = onLongPress;
|
||||
renderObject.onHighlightChanged = onHighlightChanged;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue