Commit 13b8777f authored by Ian Hickson's avatar Ian Hickson

Merge pull request #2230 from Hixie/size-obs-7

SizeObserver crusade: Heroes
parents 6ecbd548 8f2ef237
...@@ -111,14 +111,13 @@ class Hero extends StatefulComponent { ...@@ -111,14 +111,13 @@ class Hero extends StatefulComponent {
final Map<Key, HeroState> tagHeroes = heroes.putIfAbsent(tag, () => <Key, HeroState>{}); final Map<Key, HeroState> tagHeroes = heroes.putIfAbsent(tag, () => <Key, HeroState>{});
assert(() { assert(() {
if (tagHeroes.containsKey(key)) { if (tagHeroes.containsKey(key)) {
debugPrint('Tag: $tag Key: $key'); new WidgetError(
assert(() { 'There are multiple heroes that share the same key within the same subtree.\n'
'There are multiple heroes that share the same key within the same subtree. ' 'Within each subtree for which heroes are to be animated (typically a PageRoute subtree),\n'
'Within each subtree for which heroes are to be animated (typically a PageRoute subtree), ' 'either each Hero must have a unique tag, or, all the heroes with a particular tag must\n'
'either each Hero must have a unique tag, or, all the heroes with a particular tag must ' 'have different keys.\n'
'have different keys. The relevant tag and key were dumped above. '; 'In this case, the tag "$tag" had multiple heroes with the key "$key".'
return false; );
});
} }
return true; return true;
}); });
...@@ -149,86 +148,64 @@ class Hero extends StatefulComponent { ...@@ -149,86 +148,64 @@ class Hero extends StatefulComponent {
HeroState createState() => new HeroState(); HeroState createState() => new HeroState();
} }
enum _HeroMode { constructing, initialized, measured, taken }
class HeroState extends State<Hero> implements HeroHandle { class HeroState extends State<Hero> implements HeroHandle {
void initState() { GlobalKey _key = new GlobalKey();
assert(_mode == _HeroMode.constructing); Size _placeholderSize;
super.initState();
_key = new GlobalKey();
_mode = _HeroMode.initialized;
}
GlobalKey _key;
_HeroMode _mode = _HeroMode.constructing;
Size _size;
bool get alwaysAnimate => config.alwaysAnimate; bool get alwaysAnimate => config.alwaysAnimate;
_HeroManifest _takeChild(Rect animationArea, Animation<double> currentAnimation) { _HeroManifest _takeChild(Rect animationArea, Animation<double> currentAnimation) {
assert(_mode == _HeroMode.measured || _mode == _HeroMode.taken); assert(mounted);
final RenderBox renderObject = context.findRenderObject(); final RenderBox renderObject = context.findRenderObject();
assert(renderObject != null);
assert(!renderObject.needsLayout);
assert(renderObject.hasSize);
if (_placeholderSize == null) {
// We are a "from" hero, about to depart on a quest.
// Remember our size so that we can leave a placeholder.
_placeholderSize = renderObject.size;
}
final Point heroTopLeft = renderObject.localToGlobal(Point.origin); final Point heroTopLeft = renderObject.localToGlobal(Point.origin);
final Point heroBottomRight = renderObject.localToGlobal(renderObject.size.bottomRight(Point.origin)); final Point heroBottomRight = renderObject.localToGlobal(renderObject.size.bottomRight(Point.origin));
final Rect heroArea = new Rect.fromLTRB(heroTopLeft.x, heroTopLeft.y, heroBottomRight.x, heroBottomRight.y); final Rect heroArea = new Rect.fromLTRB(heroTopLeft.x, heroTopLeft.y, heroBottomRight.x, heroBottomRight.y);
final RelativeRect startRect = new RelativeRect.fromRect(heroArea, animationArea); final RelativeRect startRect = new RelativeRect.fromRect(heroArea, animationArea);
_HeroManifest result = new _HeroManifest( _HeroManifest result = new _HeroManifest(
key: _key, key: _key, // might be null, e.g. if the hero is returning to us
config: config, config: config,
sourceStates: new HashSet<HeroState>.from(<HeroState>[this]), sourceStates: new HashSet<HeroState>.from(<HeroState>[this]),
currentRect: startRect, currentRect: startRect,
currentTurns: config.turns.toDouble() currentTurns: config.turns.toDouble()
); );
setState(() { if (_key != null)
_key = null; setState(() { _key = null; });
_mode = _HeroMode.taken;
});
return result; return result;
} }
void _setChild(GlobalKey value) { void _setChild(GlobalKey value) {
assert(_mode == _HeroMode.taken);
assert(_key == null); assert(_key == null);
assert(_size != null); assert(_placeholderSize != null);
if (mounted) assert(mounted);
setState(() { _key = value; }); setState(() {
_size = null; _key = value;
_mode = _HeroMode.initialized; _placeholderSize = null;
});
} }
void _resetChild() { void _resetChild() {
assert(_mode == _HeroMode.taken);
assert(_key == null);
assert(_size != null);
if (mounted) if (mounted)
setState(() { _key = new GlobalKey(); }); _setChild(null);
_size = null;
_mode = _HeroMode.initialized;
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
switch (_mode) { if (_placeholderSize != null) {
case _HeroMode.constructing: assert(_key == null);
assert(false); return new SizedBox(width: _placeholderSize.width, height: _placeholderSize.height);
return null;
case _HeroMode.initialized:
case _HeroMode.measured:
return new SizeObserver(
onSizeChanged: (Size size) {
assert(_mode == _HeroMode.initialized || _mode == _HeroMode.measured);
_size = size;
_mode = _HeroMode.measured;
},
child: new KeyedSubtree(
key: _key,
child: config.child
)
);
case _HeroMode.taken:
return new SizedBox(width: _size.width, height: _size.height);
} }
return new KeyedSubtree(
key: _key,
child: config.child
);
} }
} }
......
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