Unverified Commit 1f8d110b authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

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
![ScreenRecording2024-02-12at18 40 34-ezgif com-video-to-gif-converter](https://github.com/flutter/flutter/assets/48603081/c101e0d6-ce5a-4b28-9626-28bcb83d2a5c)

### After
![ScreenRecording2024-02-12at18 40 10-ezgif com-video-to-gif-converter](https://github.com/flutter/flutter/assets/48603081/923b348e-8adf-4d64-9dc3-e75d30e3e2fb)
parent e93a10d1
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment