diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 09a0e0c6506..5cc8b265b2c 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -196,6 +196,7 @@ class CupertinoTextField extends StatefulWidget { this.scrollPadding = const EdgeInsets.all(20.0), this.dragStartBehavior = DragStartBehavior.start, this.enableInteractiveSelection, + this.onTap, this.scrollController, this.scrollPhysics, }) : assert(textAlign != null), @@ -458,6 +459,9 @@ class CupertinoTextField extends StatefulWidget { return enableInteractiveSelection ?? !obscureText; } + /// {@macro flutter.material.textfield.onTap} + final GestureTapCallback onTap; + @override _CupertinoTextFieldState createState() => _CupertinoTextFieldState(); @@ -584,6 +588,9 @@ class _CupertinoTextFieldState extends State with AutomaticK _renderEditable.selectWordEdge(cause: SelectionChangedCause.tap); } _requestKeyboard(); + if (widget.onTap != null) { + widget.onTap(); + } } void _handleSingleLongTapStart(LongPressStartDetails details) { diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index e8061e2061f..cce50a12caf 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -432,7 +432,8 @@ class TextField extends StatefulWidget { return enableInteractiveSelection ?? !obscureText; } - /// Called when the user taps on this text field. + /// {@template flutter.material.textfield.onTap} + /// Called for each distinct tap except for every second tap of a double tap. /// /// The text field builds a [GestureDetector] to handle input events like tap, /// to trigger focus requests, to move the caret, adjust the selection, etc. @@ -450,6 +451,7 @@ class TextField extends StatefulWidget { /// /// To listen to arbitrary pointer events without competing with the /// text field's internal gesture detector, use a [Listener]. + /// {@endtemplate} final GestureTapCallback onTap; /// Callback that generates a custom [InputDecorator.counter] widget. diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 3ac4098acfd..7183fdbcdee 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -2512,6 +2512,90 @@ void main() { }, ); + testWidgets('onTap is called upon tap', (WidgetTester tester) async { + int tapCount = 0; + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + onTap: () => tapCount++, + ), + ), + ), + ); + + expect(tapCount, 0); + await tester.tap(find.byType(CupertinoTextField)); + await tester.pump(); + expect(tapCount, 1); + + // Wait out the double tap interval so the next tap doesn't end up being + // recognized as a double tap. + await tester.pump(const Duration(seconds: 1)); + + // Double tap count as one single tap. + await tester.tap(find.byType(CupertinoTextField)); + await tester.pump(const Duration(milliseconds: 100)); + await tester.tap(find.byType(CupertinoTextField)); + await tester.pump(); + expect(tapCount, 2); + }); + + testWidgets('onTap does not work when the text field is disabled', + (WidgetTester tester) async { + int tapCount = 0; + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + enabled: false, + onTap: () => tapCount++, + ), + ), + ), + ); + + expect(tapCount, 0); + await tester.tap(find.byType(CupertinoTextField)); + await tester.pump(); + expect(tapCount, 0); + + // Wait out the double tap interval so the next tap doesn't end up being + // recognized as a double tap. + await tester.pump(const Duration(seconds: 1)); + + // Enabling the text field, now it should accept taps. + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + onTap: () => tapCount++, + ), + ), + ), + ); + + await tester.tap(find.byType(CupertinoTextField)); + expect(tapCount, 1); + + await tester.pump(const Duration(seconds: 1)); + + // Disable it again. + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + enabled: false, + onTap: () => tapCount++, + ), + ), + ), + ); + await tester.tap(find.byType(CupertinoTextField)); + await tester.pump(); + expect(tapCount, 1); + }); + testWidgets( 'text field respects theme', (WidgetTester tester) async {