From 7734c0b0e0a8d43ff981d5b891a121bb4921fd83 Mon Sep 17 00:00:00 2001 From: Hixie Date: Fri, 2 Oct 2015 10:20:08 -0700 Subject: [PATCH] Groundwork for heroes transition in Stocks app Identify specific parts of a Stock row with a Global Key that can be regenerated later, and pass that key back to event handlers so they can use them to do the transition. --- examples/stocks/lib/stock_home.dart | 4 +- examples/stocks/lib/stock_list.dart | 12 ++-- examples/stocks/lib/stock_row.dart | 86 ++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 35 deletions(-) diff --git a/examples/stocks/lib/stock_home.dart b/examples/stocks/lib/stock_home.dart index 0fc8f4a72f..523b668468 100644 --- a/examples/stocks/lib/stock_home.dart +++ b/examples/stocks/lib/stock_home.dart @@ -186,13 +186,13 @@ class StockHomeState extends State { Widget buildStockList(BuildContext context, Iterable stocks) { return new StockList( stocks: stocks.toList(), - onAction: (Stock stock) { + onAction: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) { setState(() { stock.percentChange = 100.0 * (1.0 / stock.lastSale); stock.lastSale += 1.0; }); }, - onOpen: (Stock stock) { + onOpen: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) { config.navigator.pushNamed('/stock/${stock.symbol}'); } ); diff --git a/examples/stocks/lib/stock_list.dart b/examples/stocks/lib/stock_list.dart index 4b48f7061b..54c55c0885 100644 --- a/examples/stocks/lib/stock_list.dart +++ b/examples/stocks/lib/stock_list.dart @@ -4,14 +4,12 @@ part of stocks; -typedef void StockActionListener(Stock stock); - class StockList extends StatelessComponent { - StockList({ Key key, this.stocks, this.onAction, this.onOpen }) : super(key: key); + StockList({ Key key, this.stocks, this.onOpen, this.onAction }) : super(key: key); final List stocks; - final StockActionListener onAction; - final StockActionListener onOpen; + final StockRowActionCallback onOpen; + final StockRowActionCallback onAction; Widget build(BuildContext context) { return new Material( @@ -22,8 +20,8 @@ class StockList extends StatelessComponent { itemBuilder: (BuildContext context, Stock stock) { return new StockRow( stock: stock, - onPressed: () { onAction(stock); }, - onLongPressed: () { onOpen(stock); } + onPressed: onOpen, + onLongPressed: onAction ); } ) diff --git a/examples/stocks/lib/stock_row.dart b/examples/stocks/lib/stock_row.dart index 4b8f47a65d..c985f82e12 100644 --- a/examples/stocks/lib/stock_row.dart +++ b/examples/stocks/lib/stock_row.dart @@ -4,47 +4,60 @@ part of stocks; +enum StockRowPartKind { arrow, symbol, price } + +class StockRowPartGlobalKey extends GlobalKey { + const StockRowPartGlobalKey(this.stock, this.part) : super.constructor(); + final Stock stock; + final StockRowPartKind part; + String toString() => '[StockRowPartGlobalKey ${stock.symbol}:${part.toString().split(".")[1]})]'; + bool operator==(other) => other is StockRowPartGlobalKey && identical(other.stock, stock) && identical(other.part, part); + int get hashCode => 37 * (37 * (373) + identityHashCode(stock)) + identityHashCode(part); +} + +typedef void StockRowActionCallback(Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey); + class StockRow extends StatelessComponent { StockRow({ Stock stock, this.onPressed, this.onLongPressed - }) : this.stock = stock, super(key: new Key(stock.symbol)); + }) : this.stock = stock, + arrowKey = new StockRowPartGlobalKey(stock, StockRowPartKind.arrow), + symbolKey = new StockRowPartGlobalKey(stock, StockRowPartKind.symbol), + priceKey = new StockRowPartGlobalKey(stock, StockRowPartKind.price), + super(key: new GlobalObjectKey(stock)); final Stock stock; - final GestureTapListener onPressed; - final GestureLongPressListener onLongPressed; + final StockRowActionCallback onPressed; + final StockRowActionCallback onLongPressed; + final GlobalKey arrowKey; + final GlobalKey symbolKey; + final GlobalKey priceKey; static const double kHeight = 79.0; + GestureTapListener _getTapHandler(StockRowActionCallback callback) { + if (callback == null) + return null; + return () => callback(stock, key, arrowKey, symbolKey, priceKey); + } + + GestureLongPressListener _getLongPressHandler(StockRowActionCallback callback) { + if (callback == null) + return null; + return () => callback(stock, key, arrowKey, symbolKey, priceKey); + } + Widget build(BuildContext context) { String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}"; String changeInPrice = "${stock.percentChange.toStringAsFixed(2)}%"; if (stock.percentChange > 0) changeInPrice = "+" + changeInPrice; - List children = [ - new Flexible( - child: new Text(stock.symbol), - flex: 2 - ), - new Flexible( - child: new Text( - lastSale, - style: const TextStyle(textAlign: TextAlign.right) - ) - ), - new Flexible( - child: new Text( - changeInPrice, - style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right) - ) - ) - ]; - return new GestureDetector( - onTap: onPressed, - onLongPress: onLongPressed, + onTap: _getTapHandler(onPressed), + onLongPress: _getLongPressHandler(onLongPressed), child: new InkWell( child: new Container( padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0), @@ -55,12 +68,33 @@ class StockRow extends StatelessComponent { ), child: new Row([ new Container( + key: arrowKey, child: new StockArrow(percentChange: stock.percentChange), margin: const EdgeDims.only(right: 5.0) ), new Flexible( - child: new Row( - children, + child: new Row([ + new Flexible( + flex: 2, + child: new Text( + stock.symbol, + key: symbolKey + ) + ), + new Flexible( + child: new Text( + lastSale, + style: const TextStyle(textAlign: TextAlign.right), + key: priceKey + ) + ), + new Flexible( + child: new Text( + changeInPrice, + style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right) + ) + ), + ], alignItems: FlexAlignItems.baseline, textBaseline: DefaultTextStyle.of(context).textBaseline )