Merge pull request #485 from abarth/mimic
Add widgets for reparenting widgets
This commit is contained in:
commit
be75ee726d
90
packages/flutter/example/widgets/pop_out_and_expand.dart
Normal file
90
packages/flutter/example/widgets/pop_out_and_expand.dart
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:sky/painting/box_painter.dart';
|
||||
import 'package:sky/widgets.dart';
|
||||
|
||||
class Circle extends Component {
|
||||
Circle({ this.child });
|
||||
|
||||
Widget child;
|
||||
|
||||
Widget build() {
|
||||
return new Container(
|
||||
height: 100.0,
|
||||
margin: new EdgeDims.symmetric(horizontal: 20.0, vertical: 4.0),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: const Color(0xFF0000FF)
|
||||
),
|
||||
child: new Center(
|
||||
child: child
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CircleData {
|
||||
final GlobalKey key;
|
||||
final String content;
|
||||
|
||||
CircleData({ this.key, this.content });
|
||||
}
|
||||
|
||||
class ExampleApp extends App {
|
||||
ExampleApp() {
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
_data.add(new CircleData(
|
||||
key: new GlobalKey(),
|
||||
content: '$i'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
final List<CircleData> _data = new List<CircleData>();
|
||||
|
||||
GlobalKey _keyToMimic;
|
||||
|
||||
Widget _buildCircle(CircleData circleData) {
|
||||
return new Mimicable(
|
||||
key: circleData.key,
|
||||
child: new Listener(
|
||||
child: new Circle(
|
||||
child: new Text(circleData.content)
|
||||
),
|
||||
onGestureTap: (_) {
|
||||
setState(() {
|
||||
_keyToMimic = circleData.key;
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
List<Widget> circles = new List<Widget>();
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
circles.add(_buildCircle(_data[i]));
|
||||
}
|
||||
|
||||
List<Widget> layers = new List<Widget>();
|
||||
layers.add(new ScrollableBlock(circles));
|
||||
|
||||
if (_keyToMimic != null) {
|
||||
layers.add(
|
||||
new Positioned(
|
||||
top: 50.0,
|
||||
left: 50.0,
|
||||
child: new Mimic(
|
||||
original: _keyToMimic)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new Stack(layers);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
runApp(new ExampleApp());
|
||||
}
|
@ -21,11 +21,14 @@ export 'widgets/drawer_item.dart';
|
||||
export 'widgets/flat_button.dart';
|
||||
export 'widgets/floating_action_button.dart';
|
||||
export 'widgets/focus.dart';
|
||||
export 'widgets/icon_button.dart';
|
||||
export 'widgets/framework.dart';
|
||||
export 'widgets/icon.dart';
|
||||
export 'widgets/icon_button.dart';
|
||||
export 'widgets/ink_well.dart';
|
||||
export 'widgets/material_button.dart';
|
||||
export 'widgets/material.dart';
|
||||
export 'widgets/material_button.dart';
|
||||
export 'widgets/mimic.dart';
|
||||
export 'widgets/mimic.dart';
|
||||
export 'widgets/modal_overlay.dart';
|
||||
export 'widgets/navigator.dart';
|
||||
export 'widgets/popup_menu.dart';
|
||||
@ -41,4 +44,3 @@ export 'widgets/task_description.dart';
|
||||
export 'widgets/theme.dart';
|
||||
export 'widgets/tool_bar.dart';
|
||||
export 'widgets/transitions.dart';
|
||||
export 'widgets/framework.dart';
|
||||
|
@ -110,6 +110,11 @@ abstract class GlobalKey extends Key {
|
||||
assert(removed);
|
||||
}
|
||||
|
||||
static Widget getWidget(GlobalKey key) {
|
||||
assert(key != null);
|
||||
return _registry[key];
|
||||
}
|
||||
|
||||
static void _notifyListeners() {
|
||||
assert(!_inRenderDirtyComponents);
|
||||
assert(!Widget._notifyingMountStatus);
|
||||
|
131
packages/flutter/lib/widgets/mimic.dart
Normal file
131
packages/flutter/lib/widgets/mimic.dart
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:sky/widgets/basic.dart';
|
||||
|
||||
class Mimic extends StatefulComponent {
|
||||
Mimic({ Key key, this.original }) : super(key: key);
|
||||
|
||||
GlobalKey original;
|
||||
|
||||
void initState() {
|
||||
_requestToStartMimic();
|
||||
}
|
||||
|
||||
void syncFields(Mimic source) {
|
||||
if (original != source.original) {
|
||||
_stopMimic();
|
||||
original = source.original;
|
||||
_requestToStartMimic();
|
||||
}
|
||||
}
|
||||
|
||||
void didMount() {
|
||||
super.didMount();
|
||||
// TODO(abarth): Why is didMount being called without a call to didUnmount?
|
||||
if (_mimicable == null)
|
||||
_requestToStartMimic();
|
||||
}
|
||||
|
||||
void didUnmount() {
|
||||
super.didUnmount();
|
||||
_stopMimic();
|
||||
}
|
||||
|
||||
Mimicable _mimicable;
|
||||
Size _size;
|
||||
|
||||
void _requestToStartMimic() {
|
||||
assert(_mimicable == null);
|
||||
assert(_size == null);
|
||||
if (original == null)
|
||||
return;
|
||||
_mimicable = GlobalKey.getWidget(original) as Mimicable;
|
||||
assert(_mimicable != null);
|
||||
_mimicable._requestToStartMimic(this);
|
||||
}
|
||||
|
||||
void _startMimic(GlobalKey key, Size size) {
|
||||
assert(key == original);
|
||||
setState(() {
|
||||
_size = size;
|
||||
});
|
||||
}
|
||||
|
||||
void _stopMimic() {
|
||||
if (_mimicable != null)
|
||||
_mimicable._didStopMimic(this);
|
||||
_mimicable = null;
|
||||
_size = null;
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
if (_size == null || !_mimicable.mounted)
|
||||
return new Container();
|
||||
return new ConstrainedBox(
|
||||
constraints: new BoxConstraints.tight(_size),
|
||||
child: _mimicable.child
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Mimicable extends StatefulComponent {
|
||||
Mimicable({ GlobalKey key, this.child }) : super(key: key);
|
||||
|
||||
Widget child;
|
||||
|
||||
Size _size;
|
||||
Size get size => _size;
|
||||
|
||||
Mimic _mimic;
|
||||
bool _didStartMimic = false;
|
||||
|
||||
void syncFields(Mimicable source) {
|
||||
child = source.child;
|
||||
}
|
||||
|
||||
void _requestToStartMimic(Mimic mimic) {
|
||||
assert(mounted);
|
||||
if (_mimic != null)
|
||||
return;
|
||||
setState(() {
|
||||
_mimic = mimic;
|
||||
_didStartMimic = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _didStopMimic(Mimic mimic) {
|
||||
assert(_mimic != null);
|
||||
assert(mimic == _mimic);
|
||||
setState(() {
|
||||
_mimic = null;
|
||||
_didStartMimic = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleSizeChanged(Size size) {
|
||||
setState(() {
|
||||
_size = size;
|
||||
});
|
||||
}
|
||||
|
||||
void _startMimicIfNeeded() {
|
||||
if (_didStartMimic)
|
||||
return;
|
||||
assert(_mimic != null);
|
||||
_mimic._startMimic(key, _size);
|
||||
_didStartMimic = true;
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
if (_mimic != null) {
|
||||
_startMimicIfNeeded();
|
||||
return new ConstrainedBox(constraints: new BoxConstraints.tight(_size));
|
||||
}
|
||||
return new SizeObserver(
|
||||
callback: _handleSizeChanged,
|
||||
child: child
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user