Fix InputDecorator
s suffix
and prefix
widgets are tappable when hidden (#143308)
fixes [The InputDecoration's suffix and prefix widget can be tapped even if it does not appear](https://github.com/flutter/flutter/issues/139916) This PR also updates two existing tests to pass the tests for this PR. These tests are trying to tap prefix and suffix widgets when they're hidden. While the linked issue had visible prefix and suffix widgets https://github.com/flutter/flutter/issues/39376 for reproduction. ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() { runApp(MainApp()); } class MainApp extends StatelessWidget { final _messangerKey = GlobalKey<ScaffoldMessengerState>(); MainApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( scaffoldMessengerKey: _messangerKey, home: Scaffold( body: Container( alignment: Alignment.center, padding: const EdgeInsets.all(16.0), child: TextField( decoration: InputDecoration( labelText: 'Something', prefix: GestureDetector( onTap: () { _messangerKey.currentState?.showSnackBar( const SnackBar(content: Text('A tap has occurred'))); }, child: const Icon(Icons.search), ), suffix: GestureDetector( onTap: () { _messangerKey.currentState?.showSnackBar( const SnackBar(content: Text('A tap has occurred'))); }, child: const Icon(Icons.search), ), ), ), ), ), ); } } ``` </details> ### Before  ### After 
This commit is contained in:
parent
e93a10d1fb
commit
1f8d110b8f
@ -1728,14 +1728,17 @@ class _AffixText extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTextStyle.merge(
|
||||
style: style,
|
||||
child: AnimatedOpacity(
|
||||
duration: _kTransitionDuration,
|
||||
curve: _kTransitionCurve,
|
||||
opacity: labelIsFloating ? 1.0 : 0.0,
|
||||
child: Semantics(
|
||||
sortKey: semanticsSortKey,
|
||||
tagForChildren: semanticsTag,
|
||||
child: child ?? (text == null ? null : Text(text!, style: style)),
|
||||
child: IgnorePointer(
|
||||
ignoring: !labelIsFloating,
|
||||
child: AnimatedOpacity(
|
||||
duration: _kTransitionDuration,
|
||||
curve: _kTransitionCurve,
|
||||
opacity: labelIsFloating ? 1.0 : 0.0,
|
||||
child: Semantics(
|
||||
sortKey: semanticsSortKey,
|
||||
tagForChildren: semanticsTag,
|
||||
child: child ?? (text == null ? null : Text(text!, style: style)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -307,6 +307,134 @@ void main() {
|
||||
// 4 - bottom padding
|
||||
expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0));
|
||||
}, variant: TargetPlatformVariant.desktop());
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/139916.
|
||||
testWidgets('Prefix ignores pointer when hidden', (WidgetTester tester) async {
|
||||
bool tapped = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'label',
|
||||
prefix: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
tapped = true;
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tapped, isFalse);
|
||||
|
||||
double prefixOpacity = tester.widget<AnimatedOpacity>(find.ancestor(
|
||||
of: find.byType(Icon),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
)).opacity;
|
||||
|
||||
// Initially the prefix icon should be hidden.
|
||||
expect(prefixOpacity, 0.0);
|
||||
|
||||
await tester.tap(find.byType(Icon), warnIfMissed: false); // Not expected to find the target.
|
||||
await tester.pump();
|
||||
|
||||
// The suffix icon should ignore pointer events when hidden.
|
||||
expect(tapped, isFalse);
|
||||
|
||||
// Tap the text field to show the prefix icon.
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
|
||||
prefixOpacity = tester.widget<AnimatedOpacity>(find.ancestor(
|
||||
of: find.byType(Icon),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
)).opacity;
|
||||
|
||||
// The prefix icon should be visible.
|
||||
expect(prefixOpacity, 1.0);
|
||||
|
||||
// Tap the prefix icon.
|
||||
await tester.tap(find.byType(Icon));
|
||||
await tester.pump();
|
||||
|
||||
// The prefix icon should be tapped.
|
||||
expect(tapped, isTrue);
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/139916.
|
||||
testWidgets('Suffix ignores pointer when hidden', (WidgetTester tester) async {
|
||||
bool tapped = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'label',
|
||||
suffix: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
tapped = true;
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tapped, isFalse);
|
||||
|
||||
double suffixOpacity = tester.widget<AnimatedOpacity>(find.ancestor(
|
||||
of: find.byType(Icon),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
)).opacity;
|
||||
|
||||
// Initially the suffix icon should be hidden.
|
||||
expect(suffixOpacity, 0.0);
|
||||
|
||||
await tester.tap(find.byType(Icon), warnIfMissed: false); // Not expected to find the target.
|
||||
await tester.pump();
|
||||
|
||||
// The suffix icon should ignore pointer events when hidden.
|
||||
expect(tapped, isFalse);
|
||||
|
||||
// Tap the text field to show the suffix icon.
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
|
||||
suffixOpacity = tester.widget<AnimatedOpacity>(find.ancestor(
|
||||
of: find.byType(Icon),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
)).opacity;
|
||||
|
||||
// The suffix icon should be visible.
|
||||
expect(suffixOpacity, 1.0);
|
||||
|
||||
// Tap the suffix icon.
|
||||
await tester.tap(find.byType(Icon));
|
||||
await tester.pump();
|
||||
|
||||
// The suffix icon should be tapped.
|
||||
expect(tapped, isTrue);
|
||||
});
|
||||
}
|
||||
|
||||
void runAllM2Tests() {
|
||||
|
@ -15570,10 +15570,12 @@ void main() {
|
||||
int prefixTapCount = 0;
|
||||
int suffixTapCount = 0;
|
||||
|
||||
final FocusNode focusNode = _focusNode();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: TextField(
|
||||
focusNode: focusNode,
|
||||
onTap: () { textFieldTapCount += 1; },
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Label',
|
||||
@ -15591,6 +15593,10 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
// Focus to show the prefix and suffix buttons.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
|
||||
TestGesture gesture =
|
||||
await tester.startGesture(
|
||||
tester.getRect(find.text('prefix')).center,
|
||||
@ -15622,10 +15628,12 @@ void main() {
|
||||
int prefixTapCount = 0;
|
||||
int suffixTapCount = 0;
|
||||
|
||||
final FocusNode focusNode = _focusNode();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: TextField(
|
||||
focusNode: focusNode,
|
||||
onTap: () { textFieldTapCount += 1; },
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Label',
|
||||
@ -15643,6 +15651,10 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
// Focus to show the prefix and suffix buttons.
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('prefix'));
|
||||
expect(textFieldTapCount, 0);
|
||||
expect(prefixTapCount, 1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user