From dca4e4aaa480d7bc9b2bfbce41816fb1826b0987 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Wed, 30 Mar 2016 23:58:21 -0700 Subject: [PATCH] Polish selection controls The touch ripple now starts at the touch location instead of being centered on the widget. Fixes #2652 --- .../flutter/lib/src/material/checkbox.dart | 2 +- packages/flutter/lib/src/material/radio.dart | 2 +- packages/flutter/lib/src/material/switch.dart | 17 +++++++------ .../flutter/lib/src/material/toggleable.dart | 24 +++++++++++-------- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart index c9e47b6fee6..7cf75ae68d2 100644 --- a/packages/flutter/lib/src/material/checkbox.dart +++ b/packages/flutter/lib/src/material/checkbox.dart @@ -112,7 +112,7 @@ class _RenderCheckbox extends RenderToggleable { final double offsetX = _kOffset + offset.dx; final double offsetY = _kOffset + offset.dy; - paintRadialReaction(canvas, offset + const Offset(kRadialReactionRadius, kRadialReactionRadius)); + paintRadialReaction(canvas, offset, const Point(kRadialReactionRadius, kRadialReactionRadius)); double t = position.value; diff --git a/packages/flutter/lib/src/material/radio.dart b/packages/flutter/lib/src/material/radio.dart index 440e1b6bb50..08991d97da1 100644 --- a/packages/flutter/lib/src/material/radio.dart +++ b/packages/flutter/lib/src/material/radio.dart @@ -112,7 +112,7 @@ class _RenderRadio extends RenderToggleable { void paint(PaintingContext context, Offset offset) { final Canvas canvas = context.canvas; - paintRadialReaction(canvas, offset + const Offset(kRadialReactionRadius, kRadialReactionRadius)); + paintRadialReaction(canvas, offset, const Point(kRadialReactionRadius, kRadialReactionRadius)); Point center = (offset & size).center; Color radioColor = onChanged != null ? activeColor : inactiveColor; diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index 7dc0a7d5af3..1d4f3d1c30e 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -135,7 +135,6 @@ class _RenderSwitch extends RenderToggleable { activeColor: activeColor, inactiveColor: inactiveColor, onChanged: onChanged, - minRadialReactionRadius: _kThumbRadius, size: const Size(_kSwitchWidth, _kSwitchHeight) ) { _drag = new HorizontalDragGestureRecognizer() @@ -248,12 +247,12 @@ class _RenderSwitch extends RenderToggleable { RRect trackRRect = new RRect.fromRectXY(trackRect, _kTrackRadius, _kTrackRadius); canvas.drawRRect(trackRRect, paint); - Offset thumbOffset = new Offset( - offset.dx + kRadialReactionRadius + currentPosition * _trackInnerLength, - offset.dy + size.height / 2.0 + Point thumbPosition = new Point( + kRadialReactionRadius + currentPosition * _trackInnerLength, + size.height / 2.0 ); - paintRadialReaction(canvas, thumbOffset); + paintRadialReaction(canvas, offset, thumbPosition); BoxPainter thumbPainter; if (_inactiveThumbDecoration == null && _activeThumbDecoration == null) { @@ -272,10 +271,10 @@ class _RenderSwitch extends RenderToggleable { // The thumb contracts slightly during the animation double inset = 2.0 - (currentPosition - 0.5).abs() * 2.0; double radius = _kThumbRadius - inset; - Rect thumbRect = new Rect.fromLTRB(thumbOffset.dx - radius, - thumbOffset.dy - radius, - thumbOffset.dx + radius, - thumbOffset.dy + radius); + Rect thumbRect = new Rect.fromLTRB(thumbPosition.x + offset.dx - radius, + thumbPosition.y + offset.dy - radius, + thumbPosition.x + offset.dx + radius, + thumbPosition.y + offset.dy + radius); thumbPainter.paint(canvas, thumbRect); } } diff --git a/packages/flutter/lib/src/material/toggleable.dart b/packages/flutter/lib/src/material/toggleable.dart index 1260701f33f..31203795c0e 100644 --- a/packages/flutter/lib/src/material/toggleable.dart +++ b/packages/flutter/lib/src/material/toggleable.dart @@ -9,6 +9,7 @@ import 'package:flutter/rendering.dart'; import 'constants.dart'; const Duration _kToggleDuration = const Duration(milliseconds: 200); +final Tween _kRadialReactionRadiusTween = new Tween(begin: 0.0, end: kRadialReactionRadius); // RenderToggleable is a base class for material style toggleable controls with // toggle animations. It handles storing the current value, dispatching @@ -20,8 +21,7 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic Size size, Color activeColor, Color inactiveColor, - ValueChanged onChanged, - double minRadialReactionRadius: 0.0 + ValueChanged onChanged }) : _value = value, _activeColor = activeColor, _inactiveColor = inactiveColor, @@ -46,13 +46,10 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic ..addStatusListener(_handlePositionStateChanged); _reactionController = new AnimationController(duration: kRadialReactionDuration); - _reaction = new Tween( - begin: minRadialReactionRadius, - end: kRadialReactionRadius - ).animate(new CurvedAnimation( + _reaction = new CurvedAnimation( parent: _reactionController, curve: Curves.ease - ))..addListener(markNeedsPaint); + )..addListener(markNeedsPaint); } bool get value => _value; @@ -118,6 +115,7 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic Animation _reaction; TapGestureRecognizer _tap; + Point _downPosition; void _handlePositionStateChanged(AnimationStatus status) { if (isInteractive) { @@ -129,8 +127,10 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic } void _handleTapDown(Point globalPosition) { - if (isInteractive) + if (isInteractive) { + _downPosition = globalToLocal(globalPosition); _reactionController.forward(); + } } void _handleTap() { @@ -139,11 +139,13 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic } void _handleTapUp(Point globalPosition) { + _downPosition = null; if (isInteractive) _reactionController.reverse(); } void _handleTapCancel() { + _downPosition = null; if (isInteractive) _reactionController.reverse(); } @@ -157,11 +159,13 @@ abstract class RenderToggleable extends RenderConstrainedBox implements Semantic _tap.addPointer(event); } - void paintRadialReaction(Canvas canvas, Offset offset) { + void paintRadialReaction(Canvas canvas, Offset offset, Point origin) { if (!_reaction.isDismissed) { // TODO(abarth): We should have a different reaction color when position is zero. Paint reactionPaint = new Paint()..color = activeColor.withAlpha(kRadialReactionAlpha); - canvas.drawCircle(offset.toPoint(), _reaction.value, reactionPaint); + Point center = Point.lerp(_downPosition ?? origin, origin, _reaction.value); + double radius = _kRadialReactionRadiusTween.evaluate(_reaction); + canvas.drawCircle(center + offset, radius, reactionPaint); } }