提交 8758e72d 编写于 作者: C Collin Jackson

Really basic Switch implementation in Sky. Could definitely use some polish

R=abarth@chromium.org, abarth

Review URL: https://codereview.chromium.org/1185173002.
上级 f8efd9c9
......@@ -120,6 +120,8 @@ dart_pkg("sdk") {
"lib/widgets/raised_button.dart",
"lib/widgets/scaffold.dart",
"lib/widgets/scrollable.dart",
"lib/widgets/switch.dart",
"lib/widgets/toggleable.dart",
"lib/widgets/tool_bar.dart",
"lib/widgets/ui_node.dart",
"pubspec.yaml",
......
......@@ -6,130 +6,79 @@ import 'dart:sky' as sky;
import 'package:sky/theme2/colors.dart' as colors;
import '../framework/animation/animated_value.dart';
import '../framework/animation/curves.dart';
import '../rendering/box.dart';
import 'animated_component.dart';
import 'basic.dart';
typedef void ValueChanged(value);
import 'toggleable.dart';
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;
class Checkbox extends AnimatedComponent {
class Checkbox extends Toggleable {
Checkbox({
Object key,
this.checked,
this.onChanged
}) : super(key: key) {
_checkedAnimation = new AnimatedValue(checked ? 1.0 : 0.0);
}
bool checked;
AnimatedValue _checkedAnimation;
ValueChanged onChanged;
void syncFields(Checkbox source) {
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();
Curve curve;
if (targetValue > _checkedAnimation.value) {
curve = easeIn;
} else {
curve = easeOut;
}
_checkedAnimation.animateTo(targetValue, duration, curve: curve);
}
bool value,
ValueChanged onChanged
}) : super(key: key, value: value, onChanged: onChanged);
Size get size => const Size(_kEdgeSize + 2.0, _kEdgeSize + 2.0);
void customPaintCallback(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;
// The rrect contracts slightly during the animation
double inset = 2.0 - (toggleAnimation.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);
// Outline of the empty rrect
paint.setStyle(sky.PaintingStyle.stroke);
canvas.drawRRect(rrect, paint);
// Radial gradient that changes size
if (toggleAnimation.value > 0) {
paint.setStyle(sky.PaintingStyle.fill);
paint.setShader(
new sky.Gradient.radial(
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
_kEdgeSize * (_kMidpoint - toggleAnimation.value) * 8.0,
[const sky.Color(0x00000000), _kUncheckedColor]
)
);
canvas.drawRRect(rrect, paint);
}
super.syncFields(source);
}
void _handleClick(sky.Event e) {
onChanged(!checked);
}
UINode build() {
return new EventListenerNode(
new Container(
margin: const EdgeDims.symmetric(horizontal: 5.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;
// 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);
// Outline of the empty rrect
paint.setStyle(sky.PaintingStyle.stroke);
canvas.drawRRect(rrect, paint);
// 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();
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);
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);
}
}
)
),
onGestureTap: _handleClick
);
if (toggleAnimation.value > _kMidpoint) {
double t = (toggleAnimation.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();
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);
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);
}
}
}
// 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 'dart:sky' as sky;
import 'package:sky/theme2/colors.dart' as colors;
import 'package:sky/theme2/shadows.dart';
import '../painting/shadows.dart';
import '../rendering/box.dart';
import 'basic.dart';
import 'toggleable.dart';
// TODO(jackson): This should change colors with the theme
sky.Color _kThumbOnColor = colors.Purple[500];
const sky.Color _kThumbOffColor = const sky.Color(0xFFFAFAFA);
sky.Color _kTrackOnColor = new sky.Color(_kThumbOnColor.value & (0x80 << 24));
const sky.Color _kTrackOffColor = const sky.Color(0x42000000);
const double _kSwitchWidth = 35.0;
const double _kThumbRadius = 10.0;
const double _kSwitchHeight = _kThumbRadius * 2.0;
const double _kTrackHeight = 14.0;
const double _kTrackRadius = _kTrackHeight / 2.0;
const double _kTrackWidth = _kSwitchWidth - (_kThumbRadius - _kTrackRadius) * 2.0;
class Switch extends Toggleable {
// TODO(jackson): Hit-test the switch so that it can respond to both taps and swipe gestures
Switch({
Object key,
bool value,
ValueChanged onChanged
}) : super(key: key, value: value, onChanged: onChanged);
Size get size => const Size(_kSwitchWidth + 2.0, _kSwitchHeight + 2.0);
void customPaintCallback(sky.Canvas canvas, Size size) {
sky.Color thumbColor = value ? _kThumbOnColor : _kThumbOffColor;
sky.Color trackColor = value ? _kTrackOnColor : _kTrackOffColor;
// Draw the track rrect
sky.Paint paint = new sky.Paint()..color = trackColor;
paint.setStyle(sky.PaintingStyle.fill);
sky.Rect rect = new sky.Rect.fromLTRB(
0.0,
_kSwitchHeight / 2.0 - _kTrackHeight / 2.0,
_kTrackWidth,
_kSwitchHeight / 2.0 + _kTrackHeight / 2.0
);
sky.RRect rrect = new sky.RRect()..setRectXY(rect, _kTrackRadius, _kTrackRadius);
canvas.drawRRect(rrect, paint);
// Draw the raised thumb with a shadow
paint.color = thumbColor;
var builder = new ShadowDrawLooperBuilder();
for (BoxShadow boxShadow in shadows[1])
builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blur);
paint.setDrawLooper(builder.build());
// The thumb contracts slightly during the animation
double inset = 2.0 - (toggleAnimation.value - 0.5).abs() * 2.0;
Point thumbPos = new Point(
_kTrackRadius + toggleAnimation.value * (_kTrackWidth - _kTrackRadius * 2),
_kSwitchHeight / 2.0
);
canvas.drawCircle(thumbPos.x, thumbPos.y, _kThumbRadius - inset, paint);
}
}
// 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 'dart:sky' as sky;
import 'animated_component.dart';
import 'basic.dart';
import '../framework/animation/animated_value.dart';
import '../framework/animation/curves.dart';
typedef void ValueChanged(value);
const double _kCheckDuration = 200.0;
abstract class Toggleable extends AnimatedComponent {
Toggleable({
Object key,
this.value,
this.onChanged
}) : super(key: key) {
toggleAnimation = new AnimatedValue(value ? 1.0 : 0.0);
}
bool value;
AnimatedValue toggleAnimation;
ValueChanged onChanged;
void syncFields(Toggleable source) {
onChanged = source.onChanged;
if (value != source.value) {
value = source.value;
double targetValue = value ? 1.0 : 0.0;
double difference = (toggleAnimation.value - targetValue).abs();
if (difference > 0) {
toggleAnimation.stop();
double t = difference * duration;
Curve curve = targetValue > toggleAnimation.value ? curveUp : curveDown;
toggleAnimation.animateTo(targetValue, t, curve: curve);
}
}
super.syncFields(source);
}
void _handleClick(sky.Event e) {
onChanged(!value);
}
// Override these methods to draw yourself
void customPaintCallback(sky.Canvas canvas, Size size) {
assert(false);
}
Size get size => const Size.zero;
EdgeDims get margin => const EdgeDims.symmetric(horizontal: 5.0);
double get duration => 200.0;
Curve get curveUp => easeIn;
Curve get curveDown => easeOut;
UINode build() {
return new EventListenerNode(
new Container(
margin: margin,
width: size.width,
height: size.height,
child: new CustomPaint(
token: toggleAnimation.value,
callback: customPaintCallback
)
),
onGestureTap: _handleClick
);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册