Merge pull request #2241 from Hixie/size-obs-8
SizeObserver crusade: Mimcable
This commit is contained in:
commit
f6bd20ff64
@ -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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
///
|
///
|
||||||
/// 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> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user