Commit 2bb26849 authored by Adam Barth's avatar Adam Barth

Improve checkbox animation

This patch improves the checkbox animation as suggested by the design
team. The color transition now occurs earlier in the animation and there
are fewer components to the animation.

Fixes #1614
parent efa47a6f
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui show Gradient;
import 'dart:math' as math;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
......@@ -109,63 +109,40 @@ class _RenderCheckbox extends RenderToggleable {
paintRadialReaction(canvas, offset + const Offset(kRadialReactionRadius, kRadialReactionRadius));
// Choose a color between grey and the theme color
double t = position.value;
Color borderColor = inactiveColor;
if (onChanged != null)
borderColor = t >= 0.25 ? activeColor : Color.lerp(inactiveColor, activeColor, t * 4.0);
Paint paint = new Paint()
..strokeWidth = _kStrokeWidth
..color = inactiveColor;
..color = borderColor;
// The rrect contracts slightly during the transition animation from checked states.
// Because we have a stroke size of 2, we should have a minimum 1.0 inset.
double inset = 2.0 - (position.value - _kMidpoint).abs() * 2.0;
double inset = 1.0 - (t - 0.5).abs() * 2.0;
double rectSize = _kEdgeSize - inset * _kStrokeWidth;
Rect rect = new Rect.fromLTWH(offsetX + inset, offsetY + inset, rectSize, rectSize);
// Create an inner rectangle to cover inside of rectangle. This is needed to avoid
// painting artefacts caused by overlayed paintings.
Rect innerRect = rect.deflate(1.0);
RRect rrect = new RRect.fromRectXY(rect, _kEdgeRadius, _kEdgeRadius);
// Outline of the empty rrect
paint.style = PaintingStyle.stroke;
canvas.drawRRect(rrect, paint);
// Radial gradient that changes size
if (!position.isDismissed) {
paint
..style = PaintingStyle.fill
..shader = new ui.Gradient.radial(
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
_kEdgeSize * (_kMidpoint - position.value) * 8.0,
<Color>[
const Color(0x00000000),
inactiveColor
]
);
canvas.drawRect(innerRect, paint);
}
if (position.value > _kMidpoint) {
double t = (position.value - _kMidpoint) / (1.0 - _kMidpoint);
if (onChanged != null) {
// First draw a rounded rect outline then fill inner rectangle with the active color
paint
..color = activeColor.withAlpha((t * 255).floor())
..style = PaintingStyle.stroke;
canvas.drawRRect(rrect, paint);
paint.style = PaintingStyle.fill;
canvas.drawRect(innerRect, paint);
}
RRect outer = new RRect.fromRectXY(rect, _kEdgeRadius, _kEdgeRadius);
if (t <= 0.5) {
// Outline
RRect inner = outer.deflate(math.min(rectSize / 2.0, _kStrokeWidth + rectSize * t));
canvas.drawDRRect(outer, inner, paint);
} else {
// Background
canvas.drawRRect(outer, paint);
// White inner check
double value = (t - 0.5) * 2.0;
paint
..color = const Color(0xFFFFFFFF)
..style = PaintingStyle.stroke;
..style = PaintingStyle.stroke
..strokeWidth = _kStrokeWidth;
Path path = new Path();
Point start = new Point(_kEdgeSize * 0.15, _kEdgeSize * 0.45);
Point mid = new Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
Point end = new Point(_kEdgeSize * 0.85, _kEdgeSize * 0.25);
Point drawStart = Point.lerp(start, mid, 1.0 - t);
Point drawEnd = Point.lerp(mid, end, t);
Point drawStart = Point.lerp(start, mid, 1.0 - value);
Point drawEnd = Point.lerp(mid, end, value);
path.moveTo(offsetX + drawStart.x, offsetY + drawStart.y);
path.lineTo(offsetX + mid.x, offsetY + mid.y);
path.lineTo(offsetX + drawEnd.x, offsetY + drawEnd.y);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment