Commit f6bd20ff authored by Ian Hickson's avatar Ian Hickson

Merge pull request #2241 from Hixie/size-obs-8

SizeObserver crusade: Mimcable
parents 0dd7285d 157ac752
...@@ -27,14 +27,14 @@ class MimicableHandle { ...@@ -27,14 +27,14 @@ class MimicableHandle {
/// An overlay entry that is mimicking another widget. /// An overlay entry that is mimicking another widget.
class MimicOverlayEntry { class MimicOverlayEntry {
MimicOverlayEntry._(this._key) { MimicOverlayEntry._(this._handle) {
_overlayEntry = new OverlayEntry(builder: _build); _overlayEntry = new OverlayEntry(builder: _build);
_initialGlobalBounds = _key.globalBounds; _initialGlobalBounds = _handle.globalBounds;
} }
Rect _initialGlobalBounds; Rect _initialGlobalBounds;
MimicableHandle _key; MimicableHandle _handle;
OverlayEntry _overlayEntry; OverlayEntry _overlayEntry;
// Animation state // Animation state
...@@ -53,7 +53,7 @@ class MimicOverlayEntry { ...@@ -53,7 +53,7 @@ class MimicOverlayEntry {
Duration duration, Duration duration,
Curve curve: Curves.linear Curve curve: Curves.linear
}) { }) {
assert(_key != null); assert(_handle != null);
assert(_overlayEntry != null); assert(_overlayEntry != null);
assert(targetKey != null); assert(targetKey != null);
assert(duration != null); assert(duration != null);
...@@ -84,14 +84,14 @@ class MimicOverlayEntry { ...@@ -84,14 +84,14 @@ class MimicOverlayEntry {
_curve = null; _curve = null;
_controller?.stop(); _controller?.stop();
_controller = null; _controller = null;
_key.stopMimic(); _handle.stopMimic();
_key = null; _handle = null;
_overlayEntry.remove(); _overlayEntry.remove();
_overlayEntry = null; _overlayEntry = null;
} }
Widget _build(BuildContext context) { Widget _build(BuildContext context) {
assert(_key != null); assert(_handle != null);
assert(_overlayEntry != null); assert(_overlayEntry != null);
Rect globalBounds = _initialGlobalBounds; Rect globalBounds = _initialGlobalBounds;
Point globalPosition = globalBounds.topLeft; Point globalPosition = globalBounds.topLeft;
...@@ -117,7 +117,7 @@ class MimicOverlayEntry { ...@@ -117,7 +117,7 @@ class MimicOverlayEntry {
top: localPosition.y, top: localPosition.y,
width: globalBounds.width, width: globalBounds.width,
height: globalBounds.height, height: globalBounds.height,
child: new Mimic(original: _key) child: new Mimic(original: _handle)
); );
} }
} }
...@@ -130,7 +130,7 @@ class Mimic extends StatelessComponent { ...@@ -130,7 +130,7 @@ class Mimic extends StatelessComponent {
final MimicableHandle original; final MimicableHandle original;
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (original != null && original._state._beingMimicked) if (original != null && original._state.mounted && original._state._placeholderSize != null)
return original._state.config.child; return original._state.config.child;
return new Container(); return new Container();
} }
...@@ -149,29 +149,49 @@ class Mimicable extends StatefulComponent { ...@@ -149,29 +149,49 @@ class Mimicable extends StatefulComponent {
/// ///
/// Exposes an API for starting and stopping mimicking. /// Exposes an API for starting and stopping mimicking.
class MimicableState extends State<Mimicable> { class MimicableState extends State<Mimicable> {
Size _size; Size _placeholderSize;
bool _beingMimicked = false;
Rect get _globalBounds {
assert(mounted);
RenderBox box = context.findRenderObject();
assert(box != null);
assert(box.hasSize);
assert(!box.needsLayout);
// TODO(abarth): The bounds will be wrong if there's a scale or rotation transform involved
return box.localToGlobal(Point.origin) & box.size;
}
/// Start the mimicking process. /// Start the mimicking process.
/// ///
/// The child of this object will no longer be built at this location in the /// The child of this object will no longer be built at this
/// tree. Instead, this widget will build a transparent placeholder with the /// location in the tree. Instead, this widget will build a
/// same dimensions as the widget had when the mimicking process started. /// transparent placeholder with the same dimensions as the widget
/// had when the mimicking process started.
///
/// If you use startMimic(), it is your responsibility to do
/// something with the returned [MimicableHandle]; typically,
/// passing it to a [Mimic] widget. To mimic the child in the
/// [Overlay], consider using [liftToOverlay()] instead.
MimicableHandle startMimic() { MimicableHandle startMimic() {
assert(!_beingMimicked); assert(_placeholderSize == null);
assert(_size != null); RenderBox box = context.findRenderObject();
assert(box != null);
assert(box.hasSize);
assert(!box.needsLayout);
setState(() { setState(() {
_beingMimicked = true; _placeholderSize = box.size;
}); });
return new MimicableHandle._(this); return new MimicableHandle._(this);
} }
/// Mimic this object in the enclosing overlay. /// Start the mimicking process and mimic this object in the
/// enclosing [Overlay].
/// ///
/// The child of this object will no longer be built at this location in the /// The child of this object will no longer be built at this
/// tree. Instead, (1) this widget will build a transparent placeholder with /// location in the tree. Instead, (1) this widget will build a
/// the same dimensions as the widget had when the mimicking process started /// transparent placeholder with the same dimensions as the widget
/// and (2) the child will be placed in the enclosing overlay. /// had when the mimicking process started and (2) the child will be
/// placed in the enclosing overlay.
MimicOverlayEntry liftToOverlay() { MimicOverlayEntry liftToOverlay() {
OverlayState overlay = Overlay.of(context); OverlayState overlay = Overlay.of(context);
assert(overlay != null); // You need an overlay to lift into. assert(overlay != null); // You need an overlay to lift into.
...@@ -181,36 +201,20 @@ class MimicableState extends State<Mimicable> { ...@@ -181,36 +201,20 @@ class MimicableState extends State<Mimicable> {
} }
void _stopMimic() { void _stopMimic() {
assert(_beingMimicked); assert(_placeholderSize != null);
if (!mounted) { if (mounted) {
_beingMimicked = false; setState(() {
return; _placeholderSize = null;
});
} }
setState(() {
_beingMimicked = false;
});
}
Rect get _globalBounds {
RenderBox box = context.findRenderObject();
return box.localToGlobal(Point.origin) & box.size;
}
void _handleSizeChanged(Size size) {
setState(() {
_size = size;
});
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_beingMimicked) { if (_placeholderSize != null) {
return new ConstrainedBox( return new ConstrainedBox(
constraints: new BoxConstraints.tight(_size) constraints: new BoxConstraints.tight(_placeholderSize)
); );
} }
return new SizeObserver( return config.child;
onSizeChanged: _handleSizeChanged,
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