Reputation: 31
Hi everyone i am new to flutter and I was trying do a menu where you can add and remove some players. The issue is that I get a "No Material widget found." error. What am I doing wrong ? Thank you.
Code:
import 'package:flutter/material.dart';
class PlayerList extends StatefulWidget {
const PlayerList({
this.initialCount = 5,
});
// also allow for a dynamic number of starting players
final int initialCount;
@override
_PlayerListState createState() => _PlayerListState();
}
class _PlayerListState extends State<PlayerList> {
int fieldCount = 0;
int nextIndex = 0;
// you must keep track of the TextEditingControllers if you want the values to persist correctly
List<TextEditingController> controllers = <TextEditingController>[];
// create the list of TextFields, based off the list of TextControllers
List<Widget> _buildList() {
int i;
// fill in keys if the list is not long enough (in case we added one)
if (controllers.length < fieldCount) {
for (i = controllers.length; i < fieldCount; i++) {
controllers.add(TextEditingController());
}
}
i = 0;
// cycle through the controllers, and recreate each, one per available controller
return controllers.map<Widget>((TextEditingController controller) {
int displayNumber = i + 1;
i++;
return TextField(
controller: controller,
maxLength: 20,
decoration: InputDecoration(
labelText: "Player $displayNumber",
counterText: "",
prefixIcon: const Icon(Icons.person),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
// when removing a TextField, you must do two things:
// 1. decrement the number of controllers you should have (fieldCount)
// 2. actually remove this field's controller from the list of controllers
setState(() {
fieldCount--;
controllers.remove(controller);
});
},
),
),
);
}).toList(); // convert to a list
}
@override
Widget build(BuildContext context) {
// generate the list of TextFields
final List<Widget> children = _buildList();
// append an 'add player' button to the end of the list
children.add(
GestureDetector(
onTap: () {
// when adding a player, we only need to inc the fieldCount, because the _buildList()
// will handle the creation of the new TextEditingController
setState(() {
fieldCount++;
});
},
child: Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Spieler hinzufügen',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
);
// build the ListView
return ListView(
padding: EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: children,
);
}
@override
void initState() {
super.initState();
// upon creation, copy the starting count to the current count
fieldCount = widget.initialCount;
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(PlayerList oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
}
This is the error stack:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building TextField(controller: TextEditingController#ecada(TextEditingValue(text: ┤├, selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))), decoration: InputDecoration(labelText: "Player 1", prefixIcon: Icon(IconData(U+0E7FD)), suffixIcon: IconButton(Icon, padding: EdgeInsets.all(8.0)), counterText: ), maxLength: 20, dirty, state: _TextFieldState#edbe3):
No Material widget found.
TextField widgets require a Material widget ancestor.
In material design, most widgets are conceptually "printed" on a sheet of material. In Flutter's material library, that material is represented by the Material widget. It is the Material widget that renders ink splashes, for instance. Because of this, many material library widgets require that there be a Material widget in the tree above them.
To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, such as a Card, Dialog, Drawer, or Scaffold.
The specific widget that could not find a Material ancestor was: TextField
controller: TextEditingController#ecada(TextEditingValue(text: ┤├, selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1)))
decoration: InputDecoration(labelText: "Player 1", prefixIcon: Icon(IconData(U+0E7FD)), suffixIcon: IconButton(Icon, padding: EdgeInsets.all(8.0)), counterText: )
maxLength: 20
dirty
state: _TextFieldState#edbe3
The ancestors of this widget were:
: ListView
scrollDirection: vertical
primary: using primary controller
NeverScrollableScrollPhysics
shrinkWrap: shrink-wrapping
padding: EdgeInsets.zero
: PlayerList
state: _PlayerListState#89cb2
: MaterialApp
state: _MaterialAppState#2ca5b
: MyApp
...
The relevant error-causing widget was:
TextField file:///C:/Flutter%20Project/flutter_app/flutter_app/lib/Pages/HomeTrinkspiel.dart:184:14
When the exception was thrown, this was the stack:
#0 debugCheckHasMaterial.<anonymous closure> (package:flutter/src/material/debug.dart:28:7)
#1 debugCheckHasMaterial (package:flutter/src/material/debug.dart:50:4)
#2 _TextFieldState.build (package:flutter/src/material/text_field.dart:898:12)
#3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4334:27)
#4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4223:15)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
Upvotes: 3
Views: 2612
Reputation: 681
To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, such as a Card(), Dialog(), Drawer, or Scaffold().
Upvotes: 0
Reputation: 1695
I had a similar error except that it was produced by a ListTile widget and it said The following assertion was thrown building ListTile(dirty): No Material widget found. ListTile widgets require a Material widget ancestor. ... and the solution is this, To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, such as a Card, Dialog, Drawer, or Scaffold. Therefore, if your app crashes after you use a Card, Dialog, Drawer, or Scaffold as the parent of the widget tree, then wrap the entire widget tree with a Material widget and the exception will disappear.
Upvotes: 0
Reputation: 3050
Let's have a read on the error message: TextField widgets require a Material widget ancestor.
This indicates that your TextField widget rendering from List<Widget> _buildList()
is missing a Material widget ancestor, meaning your parent methods require MaterialApp
and a Scaffold
(usually).
Perhaps this existing question/answer may help you.
Upvotes: 2