Chromium Code Reviews| Index: sky/sdk/lib/framework/widgets/checkbox.dart |
| diff --git a/sky/sdk/lib/framework/widgets/checkbox.dart b/sky/sdk/lib/framework/widgets/checkbox.dart |
| index 1d2630c48487e9f77f3d34126202361c8a9c698e..2c143754d5d96dd65e8041d8fafc1d3f54d712aa 100644 |
| --- a/sky/sdk/lib/framework/widgets/checkbox.dart |
| +++ b/sky/sdk/lib/framework/widgets/checkbox.dart |
| @@ -6,22 +6,50 @@ import 'dart:sky' as sky; |
| import 'package:sky/framework/theme2/colors.dart' as colors; |
| +import '../animation/animated_value.dart'; |
| +import '../animation/curves.dart'; |
| import '../rendering/box.dart'; |
| -import 'button_base.dart'; |
| import 'wrappers.dart'; |
| +import 'animated_component.dart'; |
|
abarth-chromium
2015/06/12 13:35:14
Please sort these alphabetically.
|
| typedef void ValueChanged(value); |
| -class Checkbox extends ButtonBase { |
| +const Curve _kAnimationCurve = parabolicRise; |
| +const double _kMidpoint = 0.5; |
| +const double _kCheckDuration = 200.0; |
| +const sky.Color _kUncheckedColor = const sky.Color(0x8A000000); |
| +// TODO(jackson): This should change colors with the theme |
| +sky.Color _kCheckedColor = colors.Purple[500]; |
| +const double _kEdgeSize = 20.0; |
| +const double _kEdgeRadius = 1.0; |
| - Checkbox({ Object key, this.onChanged, this.checked }) : super(key: key); |
| +class Checkbox extends AnimatedComponent { |
| + |
| + Checkbox({ |
| + Object key, |
| + this.checked, |
| + this.onChanged |
| + }) : super(key: key) { |
| + checkedAnimation = new AnimatedValue(checked ? 1.0 : 0.0); |
|
abarth-chromium
2015/06/12 13:35:13
checkedAnimation -> _checkedAnimation ?
|
| + } |
| bool checked; |
| + AnimatedValue checkedAnimation; |
| ValueChanged onChanged; |
| void syncFields(Checkbox source) { |
| - checked = source.checked; |
| onChanged = source.onChanged; |
| + if (checked != source.checked) { |
| + checked = source.checked; |
| + double targetValue = checked ? 1.0 : 0.0; |
| + double difference = (checkedAnimation.value - targetValue).abs(); |
| + if (difference > 0) { |
| + double duration = difference * _kCheckDuration; |
| + checkedAnimation.stop(); |
| + checkedAnimation.animateTo(targetValue, duration, curve: _kAnimationCurve); |
| + } else { |
|
abarth-chromium
2015/06/12 13:35:13
remove?
|
| + } |
| + } |
| super.syncFields(source); |
| } |
| @@ -29,37 +57,68 @@ class Checkbox extends ButtonBase { |
| onChanged(!checked); |
| } |
| - UINode buildContent() { |
| - // TODO(jackson): This should change colors with the theme |
| - sky.Color color = highlight ? colors.Purple[500] : const sky.Color(0x8A000000); |
| - const double kEdgeSize = 20.0; |
| - const double kEdgeRadius = 1.0; |
| + UINode build() { |
| return new EventListenerNode( |
| new Container( |
| margin: const EdgeDims.symmetric(horizontal: 5.0), |
| - width: kEdgeSize + 2.0, |
| - height: kEdgeSize + 2.0, |
| + width: _kEdgeSize + 2.0, |
| + height: _kEdgeSize + 2.0, |
| child: new CustomPaint( |
| + token: checkedAnimation.value, |
| callback: (sky.Canvas canvas, Size size) { |
| + // Choose a color between grey and the theme color |
| + sky.Paint paint = new sky.Paint()..strokeWidth = 2.0 |
| + ..color = _kUncheckedColor; |
| - sky.Paint paint = new sky.Paint()..color = color |
| - ..strokeWidth = 2.0; |
| + // The rrect contracts slightly during the animation |
| + double inset = 2.0 - (checkedAnimation.value - _kMidpoint).abs() * 2.0; |
| + sky.Rect rect = new sky.Rect.fromLTRB(inset, inset, _kEdgeSize - inset, _kEdgeSize - inset); |
| + sky.RRect rrect = new sky.RRect()..setRectXY(rect, _kEdgeRadius, _kEdgeRadius); |
| - // Draw the outer rrect |
| - paint.setStyle(checked ? sky.PaintingStyle.strokeAndFill : sky.PaintingStyle.stroke); |
| - sky.Rect rect = new sky.Rect.fromLTRB(0.0, 0.0, kEdgeSize, kEdgeSize); |
| - sky.RRect rrect = new sky.RRect()..setRectXY(rect, kEdgeRadius, kEdgeRadius); |
| + |
| + // Outline of the empty rrect |
| + paint.setStyle(sky.PaintingStyle.stroke); |
| canvas.drawRRect(rrect, paint); |
| - // Draw the inner check |
| - if (checked) { |
| - // TODO(jackson): Use the theme color |
| + // Radial gradient that changes size |
| + if (checkedAnimation.value > 0) { |
| + paint.setStyle(sky.PaintingStyle.fill); |
| + paint.setShader( |
| + new sky.Gradient.radial( |
| + new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0), |
| + _kEdgeSize * (_kMidpoint - checkedAnimation.value) * 8.0, |
| + [const sky.Color(0x00000000), _kUncheckedColor], |
| + [0.0, 1.0] |
| + ) |
| + ); |
| + canvas.drawRRect(rrect, paint); |
| + } |
| + |
| + if (checkedAnimation.value > _kMidpoint) { |
| + double t = (checkedAnimation.value - _kMidpoint) / (1.0 - _kMidpoint); |
| + |
| + // Solid filled rrect |
| + paint.setStyle(sky.PaintingStyle.strokeAndFill); |
| + paint.color = new Color.fromARGB((t * 255).floor(), |
| + _kCheckedColor.red, |
| + _kCheckedColor.green, |
| + _kCheckedColor.blue); |
| + canvas.drawRRect(rrect, paint); |
| + |
| + // White inner check |
| paint.color = const sky.Color(0xFFFFFFFF); |
| paint.setStyle(sky.PaintingStyle.stroke); |
| sky.Path path = new sky.Path(); |
| - path.moveTo(kEdgeSize * 0.2, kEdgeSize * 0.5); |
| - path.lineTo(kEdgeSize * 0.4, kEdgeSize * 0.7); |
| - path.lineTo(kEdgeSize * 0.8, kEdgeSize * 0.3); |
| + sky.Point start = new sky.Point(_kEdgeSize * 0.2, _kEdgeSize * 0.5); |
| + sky.Point mid = new sky.Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7); |
| + sky.Point end = new sky.Point(_kEdgeSize * 0.8, _kEdgeSize * 0.3); |
| + Point lerp(Point p1, Point p2, double t) |
| + => new Point(p1.x * (1.0 - t) + p2.x * t, p1.y * (1.0 - t) + p2.y * t); |
|
abarth-chromium
2015/06/12 13:35:14
Should this function be in the animations folder s
jackson
2015/06/12 19:45:03
Let's wait to see if we use it again somewhere
|
| + sky.Point drawStart = lerp(start, mid, 1.0 - t); |
| + sky.Point drawEnd = lerp(mid, end, t); |
| + path.moveTo(drawStart.x, drawStart.y); |
| + path.lineTo(mid.x, mid.y); |
| + path.lineTo(drawEnd.x, drawEnd.y); |
| canvas.drawPath(path, paint); |
| } |
| } |