I got stuck with a problem in Flutter: The following assertion was thrown building TextField, it flesh me a strange problem just for a brief moment!
For any clarification on the code or errors, comment below and I will reply in a few minutes, because I can not wait to solve this problem and move forward without too many thoughts!!
I am an Italian boy who has been very close to programming in Flutter and I started with this course. You are the only people I can address. I will offer a pizza Margherita to anyone who can solve this "problem";) !!!
The error that Andoid Studio returns me is like this:
I/flutter (26182): The following assertion was thrown building
TextField(controller: I/flutter (26182):
TextEditingController#e1688(TextEditingValue(text: ┤├, selection:
TextSelection(baseOffset: -1, I/flutter (26182): extentOffset: -1,
affinity: TextAffinity.downstream, isDirectional: false), composing:
I/flutter (26182): TextRange(start: -1, end: -1))), enabled: true,
decoration: InputDecoration(hintText: "Materia"), I/flutter (26182):
autocorrect: true, max length enforced, onTap: null, dirty, state:
_TextFieldState#73fdb): I/flutter (26182): No Material widget found. I/flutter (26182): TextField widgets require a Material widget
ancestor. I/flutter (26182): In material design, most widgets are
conceptually "printed" on a sheet of material. In Flutter's I/flutter
(26182): material library, that material is represented by the
Material widget. It is the Material widget I/flutter (26182): that
renders ink splashes, for instance. Because of this, many material
library widgets require that I/flutter (26182): there be a Material
widget in the tree above them. I/flutter (26182): To introduce a
Material widget, you can either directly include one, or use a widget
that contains I/flutter (26182): Material itself, such as a Card,
Dialog, Drawer, or Scaffold. I/flutter (26182): The specific widget
that could not find a Material ancestor was: I/flutter (26182):
TextField(controller:
TextEditingController#e1688(TextEditingValue(text: ┤├, selection:
I/flutter (26182): TextSelection(baseOffset: -1, extentOffset: -1,
affinity: TextAffinity.downstream, isDirectional: I/flutter (26182):
false), composing: TextRange(start: -1, end: -1))), enabled: true,
decoration: I/flutter (26182): InputDecoration(hintText: "Materia"),
autocorrect: true, max length enforced, onTap: null) I/flutter
(26182): The ancestors of this widget were:
… and a long list of widgets
This is my code, a very simple input form with 2 forms, "materia" and "description" and the page from where it is loaded into one TabBarView called "AssegnoPage". I use the scoped model, below you will find it. ù
Focus on the tab of AssegnoPage: AssegnoListPage and AggiungiAssegno
The AssegnoPage:
import 'package:flutter/material.dart';
import 'package:prova_app_book/assegno/page/aggiungi_assegno.dart'; import 'package:prova_app_book/widget/drawer.dart'; import 'assegno_list.dart'; //import '../../models/assegno.dart';
class AssegnoPage extends StatelessWidget {
@override Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
drawer: Drawer(child: DrawerWidget(),),
appBar: AppBar(
title: Text('Gestione Assegno'),
bottom: TabBar(
tabs: <Widget>[
Tab(
icon: Icon(Icons.edit),
text: 'Aggiungi Assegno',
),
Tab(
icon: Icon(Icons.book),
text: 'Il tuo assegno',
),
],
),
),
body: TabBarView(children: <Widget> [
AggiungiAssegno(),
AssegnoListPage()
]),
),
); } }
The simply form with a submitbutton at the end:
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import '../../scoped_models/assegno.dart';
import '../../models/assegno.dart';
class AggiungiAssegno extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AggiungiAssegnoState();
}
}
class _AggiungiAssegnoState extends State<AggiungiAssegno> {
final Map<String, dynamic> _formData = {
'materia': null,
'assegno': null,
};
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Widget _buildTitoloMateria(Assegno assegno) {
return TextFormField(
decoration: InputDecoration(hintText: 'Materia'),
initialValue: assegno == null ? '' : assegno.materia,
validator: (String value) {
if (value.isEmpty) {
return 'Il nome della materia è necessario';
}
},
onSaved: (String value) {
_formData['materia'] = value;
},
);
}
Widget _buildAssegno(Assegno assegno) {
return TextFormField(
decoration: InputDecoration(hintText: 'Assegno'),
maxLines: 3,
initialValue: assegno == null ? '' : assegno.assegno,
validator: (String value) {
if (value.isEmpty) {
return 'L\'assegno è necessario';
}
},
onSaved: (String value) {
_formData['assegno'] = value;
},
);
}
void _submitForm(Function aggiungiAssegno, Function aggiornaAssegno, [int selectedAssegnoIndex]) {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
if (selectedAssegnoIndex == null) {
aggiungiAssegno(Assegno(
materia: _formData['materia'], assegno: _formData['assegno']));
} else {
aggiornaAssegno(
Assegno(
materia: _formData['materia'], assegno: _formData['assegno']));
}
Navigator.pushReplacementNamed(context, '/panoramica');
}
Widget _buildSubmitButton() {
return ScopedModelDescendant<AssegnoModel>(
builder: (BuildContext context, Widget child, AssegnoModel model) {
return RaisedButton(
child: Text('Fatto'),
textColor: Colors.white,
onPressed: () =>
_submitForm(model.aggiungiAssegno, model.aggiornaAssegno, model.selectesAssegnoIndex),
);
},
);
}
Widget _buildPageContent(BuildContext context, Assegno assegno) {
final double deviceWidth = MediaQuery.of(context).size.width;
final double targetWidth = deviceWidth > 550.0 ? 500.0 : deviceWidth * 0.95;
final double targetPadding = deviceWidth - targetWidth;
return Container(
margin: EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: ListView(
padding: EdgeInsets.symmetric(horizontal: targetPadding / 2),
children: <Widget>[
_buildTitoloMateria(assegno),
SizedBox(
height: 20.0,
),
_buildAssegno(assegno),
SizedBox(
height: 20.0,
),
_buildSubmitButton(),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<AssegnoModel>(
builder: (BuildContext context, Widget child, AssegnoModel model) {
final Widget pageContent = _buildPageContent(context, model.selectedAssegno);
return model.selectesAssegnoIndex == null
? pageContent
: Scaffold(
appBar: AppBar(
title: Text('Aggiungi Assegno'),
),
body: pageContent,
);
},
);
}
}
The AssegnoListPage, Here, I returned the previous page, pressing the button, flutter gives me the error above!:
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
//import '../../models/assegno.dart';
import 'aggiungi_assegno.dart';
import '../../scoped_models/assegno.dart';
class AssegnoListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<AssegnoModel>(
builder: (BuildContext context, Widget child, AssegnoModel model) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.book),
title: Text(model.assegno[index].materia),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
model.selectAssegno(index);
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return AggiungiAssegno();
},
),
);
}),
),
Divider(),
],
);
},
itemCount: model.assegno.length,
);
},
);
}
}
The scope model used in the form:
import 'package:scoped_model/scoped_model.dart';
import '../models/assegno.dart';
class AssegnoModel extends Model{
List <Assegno> _assegno = [];
int _selectesAssegnoIndex;
List<Assegno> get assegno{
return List.from(_assegno);
}
int get selectesAssegnoIndex {
return _selectesAssegnoIndex;
}
Assegno get selectedAssegno{
if(_selectesAssegnoIndex == null){
return null;
}
return _assegno[_selectesAssegnoIndex];
}
void aggiungiAssegno(Assegno assegno) {
_assegno.add(assegno);
_selectesAssegnoIndex = null;
//print(_assegno);
}
void aggiornaAssegno(Assegno assegno) {
_assegno[_selectesAssegnoIndex] = assegno;
_selectesAssegnoIndex = null;
}
void eliminaAssegno() {
_assegno.removeAt(_selectesAssegnoIndex);
_selectesAssegnoIndex = null;
}
void selectAssegno(int index){
_selectesAssegnoIndex = index;
}
}
Best Answer
The exception explains what happens:
To introduce such
Material
widget, you have multiple possibilities:Example: