flutter/examples/fn/widgets/drawer.dart
Adam Barth 65592c41cd Add constants for material colors and shadows
This CL removes the hard-coded colors and shadows from the fn widgets and
replaces them with compile-time constants. The color values are from the
material spec:

http://www.google.com/design/spec/style/color.html#color-color-palette

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/983733003
2015-03-05 09:58:23 -08:00

188 lines
4.5 KiB
Dart

part of widgets;
const double _kWidth = 256.0;
const double _kMinFlingVelocity = 0.4;
const double _kMinAnimationDurationMS = 246.0;
const double _kMaxAnimationDurationMS = 600.0;
const Cubic _kAnimationCurve = easeOut;
class DrawerAnimation {
Stream<double> get onPositionChanged => _controller.stream;
StreamController _controller;
AnimationGenerator _animation;
double _position;
bool get _isAnimating => _animation != null;
bool get _isMostlyClosed => _position <= -_kWidth / 2;
DrawerAnimation() {
_controller = new StreamController(sync: true);
_setPosition(-_kWidth);
}
void toggle(_) => _isMostlyClosed ? _open() : _close();
void handleMaskTap(_) => _close();
void handlePointerDown(_) => _cancelAnimation();
void handlePointerMove(sky.PointerEvent event) {
assert(_animation == null);
_setPosition(_position + event.dx);
}
void handlePointerUp(_) {
if (!_isAnimating)
_settle();
}
void handlePointerCancel(_) {
if (!_isAnimating)
_settle();
}
void _open() => _animateToPosition(0.0);
void _close() => _animateToPosition(-_kWidth);
void _settle() => _isMostlyClosed ? _close() : _open();
void _setPosition(double value) {
_position = math.min(0.0, math.max(value, -_kWidth));
_controller.add(_position);
}
void _cancelAnimation() {
if (_animation != null) {
_animation.cancel();
_animation = null;
}
}
void _animate(double duration, double begin, double end, Curve curve) {
_cancelAnimation();
_animation = new AnimationGenerator(duration, begin: begin, end: end,
curve: curve);
_animation.onTick.listen(_setPosition, onDone: () {
_animation = null;
});
}
void _animateToPosition(double targetPosition) {
double distance = (targetPosition - _position).abs();
double duration = math.max(
_kMinAnimationDurationMS,
_kMaxAnimationDurationMS * distance / _kWidth);
_animate(duration, _position, targetPosition, _kAnimationCurve);
}
void handleFlingStart(event) {
double direction = event.velocityX.sign;
double velocityX = event.velocityX.abs() / 1000;
if (velocityX < _kMinFlingVelocity)
return;
double targetPosition = direction < 0.0 ? -_kWidth : 0.0;
double distance = (targetPosition - _position).abs();
double duration = distance / velocityX;
_animate(duration, _position, targetPosition, linear);
}
}
class Drawer extends Component {
static Style _style = new Style('''
position: absolute;
z-index: 2;
top: 0;
left: 0;
bottom: 0;
right: 0;
box-shadpw: ${Shadow[3]};'''
);
static Style _maskStyle = new Style('''
background-color: black;
will-change: opacity;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;'''
);
static Style _contentStyle = new Style('''
background-color: ${Grey[50]};
will-change: transform;
position: absolute;
z-index: 3;
width: 256px;
top: 0;
left: 0;
bottom: 0;'''
);
DrawerAnimation animation;
List<Node> children;
Drawer({
Object key,
this.animation,
this.children
}) : super(key: key);
double _position = -_kWidth;
bool _listening = false;
void _ensureListening() {
if (_listening)
return;
_listening = true;
animation.onPositionChanged.listen((position) {
setState(() {
_position = position;
});
});
}
Node render() {
_ensureListening();
bool isClosed = _position <= -_kWidth;
String inlineStyle = 'display: ${isClosed ? 'none' : ''}';
String maskInlineStyle = 'opacity: ${(_position / _kWidth + 1) * 0.25}';
String contentInlineStyle = 'transform: translateX(${_position}px)';
Container mask = new Container(
key: 'Mask',
style: _maskStyle,
inlineStyle: maskInlineStyle
)..events.listen('gesturetap', animation.handleMaskTap)
..events.listen('gestureflingstart', animation.handleFlingStart);
Container content = new Container(
key: 'Content',
style: _contentStyle,
inlineStyle: contentInlineStyle,
children: children
);
return new Container(
style: _style,
inlineStyle: inlineStyle,
children: [ mask, content ]
)..events.listen('pointerdown', animation.handlePointerDown)
..events.listen('pointermove', animation.handlePointerMove)
..events.listen('pointerup', animation.handlePointerUp)
..events.listen('pointercancel', animation.handlePointerCancel);
}
}