From 612117a690e3e1c27d0d53a7a4e5d8e5c420c61e Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 25 Aug 2023 17:47:08 +0300 Subject: [PATCH] Fix `Chip.shape`'s side is not used when provided in Material 3 (#132941) fixes [Chip border side color not working in Material3](https://github.com/flutter/flutter/issues/132922) ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( useMaterial3: true, chipTheme: const ChipThemeData( // shape: RoundedRectangleBorder( // side: BorderSide(color: Colors.amber), // borderRadius: BorderRadius.all(Radius.circular(12)), // ), // side: BorderSide(color: Colors.red), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return const Scaffold( body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), // side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ); } } ```
--- ### Before When `RawChip.shape` is provided with a `BorderSide`. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 54 54](https://github.com/flutter/flutter/assets/48603081/89e2c9b5-44c2-432e-97ff-8bb95b0d0fb1) When `RawChip.shape` is provided with a `BorderSide` and also `RawChip.side` is provided. The `RawChip.side` overrides the shape's side. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 55 37](https://github.com/flutter/flutter/assets/48603081/938803cc-d514-464b-b06b-e4841b9ad040) --- ### After When `RawChip.shape` is provided with a `BorderSide`. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 51 29](https://github.com/flutter/flutter/assets/48603081/d6fcaaa9-8f5d-4180-ad14-062dd459ec45) When `RawChip.shape` is provided with a `BorderSide` and also `RawChip.side` is provided. The `RawChip.side` overrides the shape's side. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 52 31](https://github.com/flutter/flutter/assets/48603081/3fa46341-43f0-4fe7-a922-f1d8ba34028c) --- --- dev/tools/gen_defaults/lib/chip_template.dart | 11 ++-- packages/flutter/lib/src/material/chip.dart | 12 ++-- packages/flutter/test/material/chip_test.dart | 54 +++++++++++++++++ .../test/material/chip_theme_test.dart | 58 +++++++++++++++++++ 4 files changed, 127 insertions(+), 8 deletions(-) diff --git a/dev/tools/gen_defaults/lib/chip_template.dart b/dev/tools/gen_defaults/lib/chip_template.dart index 4d9383399d..cdbe10362c 100644 --- a/dev/tools/gen_defaults/lib/chip_template.dart +++ b/dev/tools/gen_defaults/lib/chip_template.dart @@ -19,7 +19,6 @@ class _${blockName}DefaultsM3 extends ChipThemeData { _${blockName}DefaultsM3(this.context, this.isEnabled) : super( elevation: ${elevation("$tokenGroup$variant.container")}, - shape: ${shape("$tokenGroup.container")}, showCheckmark: true, ); @@ -47,9 +46,13 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get deleteIconColor => ${color("$tokenGroup.with-icon.selected.icon.color")}; @override - BorderSide? get side => isEnabled - ? ${border('$tokenGroup$variant.outline')} - : ${border('$tokenGroup$variant.disabled.outline')}; + OutlinedBorder? get shape { + return ${shape("$tokenGroup.container")}.copyWith( + side: isEnabled + ? ${border('$tokenGroup$variant.outline')} + : ${border('$tokenGroup$variant.disabled.outline')}, + ); + } @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 3e1eb6d7ba..65ee8909eb 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -997,6 +997,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs(widget.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipTheme.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipDefaults.shape, materialStates) + // TODO(tahatesser): Remove this fallback when Material 2 is deprecated. ?? const StadiumBorder(); return resolvedShape.copyWith(side: resolvedSide); } @@ -2234,7 +2235,6 @@ class _ChipDefaultsM3 extends ChipThemeData { _ChipDefaultsM3(this.context, this.isEnabled) : super( elevation: 0.0, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), showCheckmark: true, ); @@ -2262,9 +2262,13 @@ class _ChipDefaultsM3 extends ChipThemeData { Color? get deleteIconColor => null; @override - BorderSide? get side => isEnabled - ? BorderSide(color: _colors.outline) - : BorderSide(color: _colors.onSurface.withOpacity(0.12)); + OutlinedBorder? get shape { + return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))).copyWith( + side: isEnabled + ? BorderSide(color: _colors.outline) + : BorderSide(color: _colors.onSurface.withOpacity(0.12)), + ); + } @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index d098936aa1..9f369c2ffa 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -3503,6 +3503,60 @@ void main() { expect(calledDelete, isTrue); }); + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: RawChip( + shape: shape, + side: side, + label: const Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 2303b56478..4ff0c5c317 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -928,6 +928,64 @@ void main() { )), ); }); + + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData( + useMaterial3: true, + chipTheme: ChipThemeData( + shape: shape, + side: side, + ), + ), + home: const Material( + child: Center( + child: RawChip( + label: Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); } class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {