use ShapeBorder to draw avatar check on chip (#25984)
Adds avatarBorder property to SelectableChipAttributes and uses the outer path to draw the darkened layer.
diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart
index 41a3bf1..af83b4e 100644
--- a/packages/flutter/lib/src/material/chip.dart
+++ b/packages/flutter/lib/src/material/chip.dart
@@ -304,6 +304,14 @@
/// Tooltip string to be used for the body area (where the label and avatar
/// are) of the chip.
String get tooltip;
+
+ /// The shape of the translucent highlight painted over the avatar when the
+ /// [selected] property is true.
+ ///
+ /// Only the outer path of the shape is used.
+ ///
+ /// Defaults to [CircleBorder].
+ ShapeBorder get avatarBorder;
}
/// An interface for material design chips that can be enabled and disabled.
@@ -604,6 +612,7 @@
this.backgroundColor,
this.padding,
this.materialTapTargetSize,
+ this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(isEnabled != null),
assert(label != null),
@@ -652,6 +661,8 @@
final EdgeInsetsGeometry padding;
@override
final MaterialTapTargetSize materialTapTargetSize;
+ @override
+ final ShapeBorder avatarBorder;
@override
Widget build(BuildContext context) {
@@ -679,6 +690,7 @@
padding: padding,
materialTapTargetSize: materialTapTargetSize,
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
+ avatarBorder: avatarBorder,
);
}
}
@@ -762,6 +774,7 @@
this.backgroundColor,
this.padding,
this.materialTapTargetSize,
+ this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
@@ -797,6 +810,8 @@
final EdgeInsetsGeometry padding;
@override
final MaterialTapTargetSize materialTapTargetSize;
+ @override
+ final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@@ -824,6 +839,7 @@
padding: padding,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
+ avatarBorder: avatarBorder,
);
}
}
@@ -939,6 +955,7 @@
this.backgroundColor,
this.padding,
this.materialTapTargetSize,
+ this.avatarBorder = const CircleBorder(),
}) : assert(selected != null),
assert(label != null),
assert(clipBehavior != null),
@@ -974,6 +991,8 @@
final EdgeInsetsGeometry padding;
@override
final MaterialTapTargetSize materialTapTargetSize;
+ @override
+ final ShapeBorder avatarBorder;
@override
bool get isEnabled => onSelected != null;
@@ -998,6 +1017,7 @@
padding: padding,
isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize,
+ avatarBorder: avatarBorder,
);
}
}
@@ -1190,6 +1210,7 @@
this.clipBehavior = Clip.none,
this.backgroundColor,
this.materialTapTargetSize,
+ this.avatarBorder = const CircleBorder(),
}) : assert(label != null),
assert(isEnabled != null),
assert(clipBehavior != null),
@@ -1239,6 +1260,8 @@
final EdgeInsetsGeometry padding;
@override
final MaterialTapTargetSize materialTapTargetSize;
+ @override
+ final CircleBorder avatarBorder;
/// Whether or not to show a check mark when [selected] is true.
///
@@ -1544,6 +1567,7 @@
avatarDrawerAnimation: avatarDrawerAnimation,
deleteDrawerAnimation: deleteDrawerAnimation,
isEnabled: widget.isEnabled,
+ avatarBorder: widget.avatarBorder,
),
),
),
@@ -1624,6 +1648,7 @@
this.avatarDrawerAnimation,
this.deleteDrawerAnimation,
this.enableAnimation,
+ this.avatarBorder,
}) : assert(theme != null),
super(key: key);
@@ -1634,6 +1659,7 @@
final Animation<double> avatarDrawerAnimation;
final Animation<double> deleteDrawerAnimation;
final Animation<double> enableAnimation;
+ final ShapeBorder avatarBorder;
@override
_RenderChipElement createElement() => _RenderChipElement(this);
@@ -1648,7 +1674,8 @@
..checkmarkAnimation = checkmarkAnimation
..avatarDrawerAnimation = avatarDrawerAnimation
..deleteDrawerAnimation = deleteDrawerAnimation
- ..enableAnimation = enableAnimation;
+ ..enableAnimation = enableAnimation
+ ..avatarBorder = avatarBorder;
}
@override
@@ -1662,6 +1689,7 @@
avatarDrawerAnimation: avatarDrawerAnimation,
deleteDrawerAnimation: deleteDrawerAnimation,
enableAnimation: enableAnimation,
+ avatarBorder: avatarBorder,
);
}
}
@@ -1849,6 +1877,7 @@
this.avatarDrawerAnimation,
this.deleteDrawerAnimation,
this.enableAnimation,
+ this.avatarBorder,
}) : assert(theme != null),
assert(textDirection != null),
_theme = theme,
@@ -1870,6 +1899,7 @@
Animation<double> avatarDrawerAnimation;
Animation<double> deleteDrawerAnimation;
Animation<double> enableAnimation;
+ ShapeBorder avatarBorder;
RenderBox _updateChild(RenderBox oldChild, RenderBox newChild, _ChipSlot slot) {
if (oldChild != null) {
@@ -2357,7 +2387,8 @@
final Paint darkenPaint = Paint()
..color = selectionScrimTween.evaluate(checkmarkAnimation)
..blendMode = BlendMode.srcATop;
- context.canvas.drawRect(avatarRect, darkenPaint);
+ final Path path = avatarBorder.getOuterPath(avatarRect);
+ context.canvas.drawPath(path, darkenPaint);
}
// Need to make the check mark be a little smaller than the avatar.
final double checkSize = avatar.size.height * 0.75;
diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart
index f73e2fd..6bef5b8 100644
--- a/packages/flutter/test/material/chip_test.dart
+++ b/packages/flutter/test/material/chip_test.dart
@@ -1596,4 +1596,27 @@
await tester.pumpWidget(_wrapForChip(child: const InputChip(label: label, clipBehavior: Clip.antiAlias)));
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
+
+ testWidgets('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async {
+ await tester.pumpWidget(_wrapForChip(child: const FilterChip(
+ avatar: CircleAvatar(child: Text('t')),
+ label: Text('test'),
+ selected: true,
+ onSelected: null,
+ )));
+ final RenderBox rawChip = tester.firstRenderObject<RenderBox>(
+ find.descendant(
+ of: find.byType(RawChip),
+ matching: find.byWidgetPredicate((Widget widget) {
+ return widget.runtimeType.toString() == '_ChipRenderWidget';
+ })
+ )
+ );
+ const Color selectScrimColor = Color(0x60191919);
+ expect(rawChip, paints..path(color: selectScrimColor, includes: <Offset>[
+ const Offset(10, 10),
+ ], excludes: <Offset>[
+ const Offset(4, 4),
+ ]));
+ });
}