From 4d32c085ed01d889063e4522db076629c7216286 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Wed, 21 Mar 2018 14:38:06 -0700 Subject: [PATCH] InputDecorator should clip fill color to its border (#15795) --- .../lib/src/material/input_decorator.dart | 41 +++++++++++++----- .../test/material/input_decorator_test.dart | 42 +++++++++++++++++++ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index a5798dca72..1038c97610 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -68,6 +68,7 @@ class _InputBorderPainter extends CustomPainter { this.gapAnimation, this.gap, this.textDirection, + this.fillColor, }) : super(repaint: repaint); final Animation borderAnimation; @@ -75,12 +76,25 @@ class _InputBorderPainter extends CustomPainter { final Animation gapAnimation; final _InputBorderGap gap; final TextDirection textDirection; + final Color fillColor; @override void paint(Canvas canvas, Size size) { - border.evaluate(borderAnimation).paint( + final InputBorder borderValue = border.evaluate(borderAnimation); + final Rect canvasRect = Offset.zero & size; + + if (fillColor.alpha > 0) { + canvas.drawPath( + borderValue.getOuterPath(canvasRect, textDirection: textDirection), + new Paint() + ..color = fillColor + ..style = PaintingStyle.fill, + ); + } + + borderValue.paint( canvas, - Offset.zero & size, + canvasRect, gapStart: gap.start, gapExtent: gap.extent, gapPercentage: gapAnimation.value, @@ -108,14 +122,17 @@ class _BorderContainer extends StatefulWidget { @required this.border, @required this.gap, @required this.gapAnimation, + @required this.fillColor, this.child, }) : assert(border != null), assert(gap != null), + assert(fillColor != null), super(key: key); final InputBorder border; final _InputBorderGap gap; final Animation gapAnimation; + final Color fillColor; final Widget child; @override @@ -174,6 +191,7 @@ class _BorderContainerState extends State<_BorderContainer> with SingleTickerPro gapAnimation: widget.gapAnimation, gap: widget.gap, textDirection: Directionality.of(context), + fillColor: widget.fillColor, ), child: widget.child, ); @@ -1518,15 +1536,16 @@ class _InputDecoratorState extends State with TickerProviderStat ), ); - final Widget containerFill = new DecoratedBox( - decoration: new BoxDecoration(color: _getFillColor(themeData)), - ); - final Widget container = border == null ? containerFill : new _BorderContainer( - border: border, - gap: _borderGap, - gapAnimation: _floatingLabelController.view, - child: containerFill, - ); + final Widget container = border == null + ? new DecoratedBox( + decoration: new BoxDecoration(color: _getFillColor(themeData)) + ) + : new _BorderContainer( + border: border, + gap: _borderGap, + gapAnimation: _floatingLabelController.view, + fillColor: _getFillColor(themeData), + ); final TextStyle inlineLabelStyle = inlineStyle.merge(decoration.labelStyle); final Widget label = decoration.labelText == null ? null : new _Shaker( diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index cbc5d5c747..d088675f68 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/mock_canvas.dart'; + Widget buildInputDecorator({ InputDecoration decoration: const InputDecoration(), InputDecorationTheme inputDecorationTheme, @@ -1188,4 +1190,44 @@ void main() { expect(decoration.fillColor, Colors.blue); expect(decoration.border, const OutlineInputBorder()); }); + + testWidgets('InputDecorator fillColor is clipped by border', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/15742 + + await tester.pumpWidget( + buildInputDecorator( + // isEmpty: false (default) + // isFocused: false (default) + decoration: new InputDecoration( + filled: true, + fillColor: const Color(0xFF00FF00), + border: new OutlineInputBorder( + borderRadius: new BorderRadius.circular(12.0), + ), + ), + ), + ); + + final RenderBox box = tester.renderObject(find.byType(InputDecorator)); + + // Fill is the border's outer path, a rounded rectangle + expect(box, paints..path( + style: PaintingStyle.fill, + color: const Color(0xFF00FF00), + includes: [const Offset(800.0/2.0, 56/2.0)], + excludes: [ + const Offset(1.0, 6.0), // outside the rounded corner, top left + const Offset(800.0 - 1.0, 6.0), // top right + const Offset(1.0, 56.0 - 6.0), // bottom left + const Offset(800 - 1.0, 56.0 - 6.0), // bottom right + ], + )); + + // Border outline. The rrect is the -center- of the 1.0 stroked outline. + expect(box, paints..rrect( + style: PaintingStyle.stroke, + strokeWidth: 1.0, + rrect: new RRect.fromLTRBR(0.5, 0.5, 799.5, 55.5, const Radius.circular(11.5)), + )); + }); }