Better error message when TextField is not in a Material (#16147)
Added a call to debugCheckHasMaterial() at the start of TextField's build method.
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 5d37747..7e7dab3 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -10,6 +10,7 @@
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
+import 'debug.dart';
import 'feedback.dart';
import 'ink_well.dart' show InteractiveInkFeature;
import 'input_decorator.dart';
@@ -42,7 +43,9 @@
/// extra padding introduced by the decoration to save space for the labels.
///
/// If [decoration] is non-null (which is the default), the text field requires
-/// one of its ancestors to be a [Material] widget.
+/// one of its ancestors to be a [Material] widget. When the [TextField] is
+/// tapped an ink splash that paints on the material is triggered, see
+/// [ThemeData.splashFactory].
///
/// To integrate the [TextField] into a [Form] with other [FormField] widgets,
/// consider using [TextFormField].
@@ -450,6 +453,7 @@
@override
Widget build(BuildContext context) {
super.build(context); // See AutomaticKeepAliveClientMixin.
+ assert(debugCheckHasMaterial(context));
final ThemeData themeData = Theme.of(context);
final TextStyle style = widget.style ?? themeData.textTheme.subhead;
final TextEditingController controller = _effectiveController;
diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart
index f9f70ff..7e62b4c 100644
--- a/packages/flutter/test/cupertino/tab_scaffold_test.dart
+++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart
@@ -132,14 +132,16 @@
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
- return new CupertinoTabScaffold(
- tabBar: _buildTabBar(),
- tabBuilder: (BuildContext context, int index) {
- return new TextField(
- focusNode: focusNodes[index],
- autofocus: true,
- );
- },
+ return new Material(
+ child: new CupertinoTabScaffold(
+ tabBar: _buildTabBar(),
+ tabBuilder: (BuildContext context, int index) {
+ return new TextField(
+ focusNode: focusNodes[index],
+ autofocus: true,
+ );
+ },
+ ),
);
},
);
diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart
index 44514eb..1800bf5 100644
--- a/packages/flutter/test/material/text_field_helper_text_test.dart
+++ b/packages/flutter/test/material/text_field_helper_text_test.dart
@@ -7,11 +7,11 @@
void main() {
testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async {
- await tester.pumpWidget(new MaterialApp(home: const TextField(decoration: const InputDecoration(helperText: 'Awesome'))));
+ await tester.pumpWidget(new MaterialApp(home: const Material(child: const TextField(decoration: const InputDecoration(helperText: 'Awesome')))));
expect(find.text('Awesome'), findsNWidgets(1));
await tester.pump(const Duration(milliseconds: 100));
expect(find.text('Awesome'), findsNWidgets(1));
- await tester.pumpWidget(new MaterialApp(home: const TextField(decoration: const InputDecoration(errorText: 'Awesome'))));
+ await tester.pumpWidget(new MaterialApp(home: const Material(child: const TextField(decoration: const InputDecoration(errorText: 'Awesome')))));
expect(find.text('Awesome'), findsNWidgets(2));
});
}
\ No newline at end of file
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 8e7ea20..926fdd3 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -2060,5 +2060,13 @@
semantics.dispose();
});
+ testWidgets('TextField throws when not descended from a Material widget', (WidgetTester tester) async {
+ const Widget textField = const TextField();
+ await tester.pumpWidget(textField);
+ final dynamic exception = tester.takeException();
+ expect(exception, isFlutterError);
+ expect(exception.toString(), startsWith('No Material widget found.'));
+ expect(exception.toString(), endsWith(':\n $textField\nThe ancestors of this widget were:\n [root]'));
+ });
}
diff --git a/packages/flutter/test/widgets/physical_model_test.dart b/packages/flutter/test/widgets/physical_model_test.dart
index f575d06..7578ac7 100644
--- a/packages/flutter/test/widgets/physical_model_test.dart
+++ b/packages/flutter/test/widgets/physical_model_test.dart
@@ -6,15 +6,16 @@
void main() {
testWidgets('PhysicalModel - creates a physical model layer when it needs compositing', (WidgetTester tester) async {
await tester.pumpWidget(new Directionality(
- textDirection: TextDirection.ltr,
- child: new PhysicalModel(
- shape: BoxShape.rectangle,
- color: Colors.grey,
- shadowColor: Colors.red,
- elevation: 1.0,
- child: new TextField(controller: new TextEditingController()),
+ textDirection: TextDirection.ltr,
+ child: new PhysicalModel(
+ shape: BoxShape.rectangle,
+ color: Colors.grey,
+ shadowColor: Colors.red,
+ elevation: 1.0,
+ child: new Material(child: new TextField(controller: new TextEditingController())),
+ ),
),
- ));
+ );
await tester.pump();
final RenderPhysicalModel renderPhysicalModel = tester.allRenderObjects.firstWhere((RenderObject object) => object is RenderPhysicalModel);