Fix Chips with Tooltip throw an assertion when enabling or disabling (#138799)
fixes [Enabling or disabling a `Chip`/`RawChip` with a tooltip throws an exception](https://github.com/flutter/flutter/issues/138287) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { bool isEnabled = true; return MaterialApp( home: Material( child: Center( child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return Column( mainAxisSize: MainAxisSize.min, children: [ RawChip( tooltip: 'This is a tooltip', isEnabled: isEnabled, label: const Text('RawChip'), onPressed: isEnabled ? () {} : null, ), const SizedBox(height: 20), ElevatedButton( onPressed: () { setState(() { isEnabled = !isEnabled; }); }, child: Text('${isEnabled ? 'Disable' : 'Enable'} Chip'), ) ], ); }), ), ), ); } } ``` </details>
This commit is contained in:
@@ -1554,12 +1554,7 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
||||
required this.enableAnimation,
|
||||
this.avatarBorder,
|
||||
}) : _theme = theme,
|
||||
_textDirection = textDirection {
|
||||
checkmarkAnimation.addListener(markNeedsPaint);
|
||||
avatarDrawerAnimation.addListener(markNeedsLayout);
|
||||
deleteDrawerAnimation.addListener(markNeedsLayout);
|
||||
enableAnimation.addListener(markNeedsPaint);
|
||||
}
|
||||
_textDirection = textDirection;
|
||||
|
||||
bool? value;
|
||||
bool? isEnabled;
|
||||
@@ -2099,6 +2094,24 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void attach(PipelineOwner owner) {
|
||||
super.attach(owner);
|
||||
checkmarkAnimation.addListener(markNeedsPaint);
|
||||
avatarDrawerAnimation.addListener(markNeedsLayout);
|
||||
deleteDrawerAnimation.addListener(markNeedsLayout);
|
||||
enableAnimation.addListener(markNeedsPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
void detach() {
|
||||
checkmarkAnimation.removeListener(markNeedsPaint);
|
||||
avatarDrawerAnimation.removeListener(markNeedsLayout);
|
||||
deleteDrawerAnimation.removeListener(markNeedsLayout);
|
||||
enableAnimation.removeListener(markNeedsPaint);
|
||||
super.detach();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_childOpacityLayerHandler.layer = null;
|
||||
|
||||
@@ -3604,6 +3604,55 @@ void main() {
|
||||
expect(getIconData(tester).color, const Color(0xff112233));
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/138287.
|
||||
testWidgetsWithLeakTracking("Enabling and disabling Chip with Tooltip doesn't throw an exception", (WidgetTester tester) async {
|
||||
bool isEnabled = true;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
tooltip: 'tooltip',
|
||||
isEnabled: isEnabled,
|
||||
onPressed: isEnabled ? () {} : null,
|
||||
label: const Text('RawChip'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isEnabled = !isEnabled;
|
||||
});
|
||||
},
|
||||
child: Text('${isEnabled ? 'Disable' : 'Enable'} Chip'),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// Tap the elevated button to disable the chip with a tooltip.
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'Disable Chip'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// No exception should be thrown.
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
// Tap the elevated button to enable the chip with a tooltip.
|
||||
await tester.tap(find.widgetWithText(ElevatedButton, 'Enable Chip'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// No exception should be thrown.
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
group('Material 2', () {
|
||||
// These tests are only relevant for Material 2. Once Material 2
|
||||
// support is deprecated and the APIs are removed, these tests
|
||||
|
||||
Reference in New Issue
Block a user