Not able to get element index in a listview - Flutter - flutter

i'm trying to make operations on clicked elements in a listView in flutter. An alertDialog should appear once I click an element so I can update its value. My backend works perfectly using the put http method. The problem is that i'm able to read the input value in console but not able to read the index of the clicked element.
As it's mentionned above, i'm able to read the input value which means that my api works correctly, but not able to retrieve the clicked element's index in the listView.
Console output:
I/flutter ( 4120): ============================== null
I/flutter ( 4120): 33
here is my update function:
handleMeasurement(String iv_id, String value) async {
final response = await http.put(
Uri.parse('${baseUrl}/api/v1/measurements/update/' + iv_id),
body: <String, String>{
"input_value": value
});
}
and here is my ui:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Traitement des mesures',
style: TextStyle(color: Colors.black),
),
centerTitle: true,
),
body: Visibility(
visible: isLoaded,
replacement: Center(child: CircularProgressIndicator()),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(15),
itemCount: mesures?.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Mesure'),
content: TextField(
controller: _textFieldController,
decoration:
InputDecoration(hintText: "Entrez la valeur"),
),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => {
print(
"============================== ${mesures![index].measurement_id}"),
print(_textFieldController.text),
handleMeasurement(
"${mesures![index].measurement_id}",
_textFieldController.text),
Navigator.pop(context, 'OK')
},
child: const Text('OK'),
),
],
),
),
child: Container(
margin: EdgeInsets.only(bottom: 15),
child: Row(
children: [
SizedBox(
width: 70,
child: AspectRatio(
aspectRatio: 0.88,
child: Container(
decoration: BoxDecoration(
color: Color(0xFFF5F6F9),
borderRadius: BorderRadius.circular(15),
),
child: Image.asset(
'assets/note2.png',
),
),
),
),
SizedBox(width: 20),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Paramètre: ${mesures![index].param_name}",
style: TextStyle(
color: Colors.black, fontSize: 16),
maxLines: 2,
),
SizedBox(height: 10),
Text.rich(
TextSpan(
text:
"Description: ${mesures![index].description}",
style: TextStyle(
fontWeight: FontWeight.w600,
color: kPrimaryColor),
),
),
],
),
],
),
),
);
},
),
)
],
),
),
);
}
Can anyone help me out with it? thanks in advance!

Related

Dynamic listview in flutter

I'm new to Flutter, but I'm trying to make an app with a ListView. The ListView is a list of exercises, within each exercise the number of sets can be added. The problem comes when i press the button add exercise. The above exercise with sets is just copied. I would like a new exercise tab with 0 sets. Below the code can be found.
Here is a picture of the list.
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "null",
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
titleSection,
// ignore: unnecessary_new
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
Expanded(
// ignore: unnecessary_new
child: new ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: ExpansionTile(
initiallyExpanded: true,
title: Text(
litems[Index],
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(child: Text(" ")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
],
),
// ignore: sort_child_properties_last
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: sets.length,
itemBuilder:
(BuildContext context, int Index1) {
return Dismissible(
key: UniqueKey(),
// only allows the user swipe from right to left
direction:
DismissDirection.endToStart,
// Remove this product from the list
// In production enviroment, you may want to send some request to delete it on server side
onDismissed: (_) {
setState(() {
sets.removeAt(Index1);
});
},
// ignore: sort_child_properties_last
child: Card(
elevation: 0,
child: Padding(
padding: EdgeInsets.all(1),
child: ListTile(
title: Text(
" ",
style: const TextStyle(
fontSize: 10,
fontWeight:
FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(
child: Text(" "),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
],
),
))),
background: Container(
color: Colors.red,
margin:
const EdgeInsets.symmetric(
horizontal: 15,
),
alignment: Alignment.centerRight,
child: const Text(
"Delete",
style: TextStyle(
color: Colors.white,
),
)));
}),
Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {
sets.add('sets-test');
setState(() {});
},
child: const Text('+ Add Set')),
),
const SizedBox(height: 5),
],
leading: IconButton(
icon: const Icon(
Icons.close,
color: Colors.red,
),
onPressed: () {
litems.removeAt(Index);
setState(() {});
},
),
)));
})),
ElevatedButton(
onPressed: () {
litems.add("new");
setState(() {});
},
child: const Text('Add Exercises')),
ElevatedButton(
onPressed: () {
createUser(user1, "5");
exercise.setExerciseTotals();
//saveExercise(exercise);
final workout = Workout([exercise, exercise1], "Det gik fint",
"10", 60, "type", "name", true, 0, 0, 0);
//workout.setWorkoutTotals();
saveWorkout(workout, userID);
},
child: const Text('pop')),
bottomSection,
],
),
));
}
You are not copy the item, you logic is that add new Item with null value, change decoratedField to this:
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "0",
);

RangeError (end): Invalid value: Not in inclusive range 0..17: 18

I know there are alot of similar questions in the platoform but i just cant find similar soulitions to mine.
So my listview.builder in my streambuilder is working fine when I do not update the details of an item. But when i access the item detail page and update my item using a function i created in the item detail page. The details will get updated but when i return to the item list page with listview.builder in streambuilder. The error occurs ("RangeError (end): Invalid value: Not in inclusive range 0..17: 18"). I am not sure why this happens. Please help me.
This is my streambuilder page
Widget build(BuildContext context) {
return StreamProvider<List <Announcement>>.value(
value: DatabaseService(uid: ' ', docID: ' ', sort: '${isOldToNew}',aLevel: widget.selectionLevel,aType: widget.selectionType).announcementList,
initialData: [],
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
elevation: 0.0,
centerTitle: true,
),
body: Column(
children: <Widget>[
Expanded(
child: AnnouncementListForAll(),
),
],
),
),
);
}
My listview.builder is in the AnnouncementListForAll class in the expanded widget.
Below is my AnnouncementListForAll code.
Widget build(BuildContext context) {
final announcementList = Provider.of<List <Announcement>>(context);
return Scrollbar(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: announcementList.length,
itemBuilder: (context, index){
return announcementTileForAll(announcementlist: announcementList[index]);
},
),
);
}
This is my tile class in the listview.builder
class announcementTileForAll extends StatelessWidget {
final Announcement announcementlist;
announcementTileForAll({ required this.announcementlist });
#override
Widget build(BuildContext context) {
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(
horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(
color: Color.fromRGBO(64, 75, 96, .5)),
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => announcementDetailForAll(announcementlist.id),
),
);
},
contentPadding: EdgeInsets.symmetric(
horizontal: 10.0, vertical: 10.0
),
title: Text(
announcementlist.title.length > 15 ? '${announcementlist.title.substring (0,18)} ...' : announcementlist.title, // limit the words that will be displayed out on screen
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
// subtitle: Text("10.07.2020", style: TextStyle(color: Colors.white)),
subtitle: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0,2.0,0.0,0.0),
child: Text(announcementlist.content.length > 20 ? '${announcementlist.content.substring (0,20)} ... ' : announcementlist.content), // limit the words that will be displayed out on screen
),
),
Row(
children: <Widget>[
Icon(Icons.linear_scale,
color: Colors.yellowAccent),
Text(announcementlist.dateTime,
style: TextStyle(color: Colors.white)),
],
),
],
),
trailing: Icon(Icons.keyboard_arrow_right,
color: Colors.white, size: 30.0)),
),
);
}
}
Apparently i found out it is the substring issue, how can i solve this problem ?

How to fix a non-null String must be provided to a Text widget

this is part of my code, I keep getting a non-null String must be provided to a Text widget.
Still new to flutter, so I'm not sure on how to fix this. I tried putting the ??"" on child: Text(myQuiz[0][i.toString()] but then it gave me an error on The method '[]' was called on null.
Receiver: null
Tried calling:
Widget optionButton(String k) {
return Padding(
padding: EdgeInsets.only(
top: 10
),
child: MaterialButton(
onPressed: () => checkAns(k),
child: Text(
myQuiz[1][i.toString()][k],
style: TextStyle(
color: Colors.black,
fontFamily: "Open Sans",
fontSize: 16.0,
),
maxLines: 1,
),
color: buttonColor[k],
minWidth: 200.0,
height: 45.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Color(0xffb0dab9))),
),
);
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]);
return WillPopScope(
onWillPop: () {
return showDialog(
context: context,
builder: (context) => AlertDialog(
content: Text("You must finish this quiz :)"),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Ok',
),
)
],
));
},
child: Scaffold(
appBar: AppBar(title: Text('Quiz'),backgroundColor: Color(0xffb0dab9)),
backgroundColor: Colors.yellow[100],
body: Container(
padding: EdgeInsets.all(50),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
alignment: Alignment.center,
child: Text(myQuiz[0][i.toString()],
style: TextStyle(fontSize: 20.0, color: Colors.black),
),
),
AbsorbPointer(
absorbing: disableAnswer,
child: Container(
padding: EdgeInsets.only(top: 30),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
optionButton('a'),
optionButton('b'),
optionButton('c'),
optionButton('d'),
],
),
),
),
Container(
padding: EdgeInsets.only(top: 30),
alignment: Alignment.topCenter,
child: Center(
child: Text(
showTimer ,
style: TextStyle(
fontSize: 20.0,
),
),
),
),
],
),
),
),
)
);
}
}
It is because a null value is being provide to your Text widget
From your code.. one or more of the following is null and not a string
myQuiz[1][i.toString()][k]
showTimer
Try
...
#override
Widget build(BuildContext context) {
print(myQuiz[1][i.toString()][k]);
print(showTimer);
to find out which is the null value
Try this.
Text(
myQuiz[1]?[i?.toString()]?[k] ?? "Default Value",
style: TextStyle(
color: Colors.black,
fontFamily: "Open Sans",
fontSize: 16.0,
),
maxLines: 1,
),
Thanks for helping, I have found the answer, it was in the getRandom, as the json does not have a 0, so when the quiz runs and hit 0, it causes the error

Flutter: How can i put Textfield input into a list to build a ListView.builder

Im trying to build a listviewbuilder since a few days. For that i need the textfield input from another screen. I looked a lot of tutorials and question but it doesnt work.Im trying to put the input from multiple textfields into multiple lists to build a Listview builder. It would be the best if i can save all Textfield input when i press on flatbutton. I hope someone can help me.
First page
List<String> time = ["8:00"];List<String>
List<String> where = ["Am See"];
List<String> who = ["Eric"];
List<String> when = ["Donnerstag 21.4.21"];
body: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(children: [
Upperscreen(size: size),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: where.length,
itemBuilder: (BuildContext context, int Index) {
return Column(children: [
SizedBox(
height: 40,
),
Container(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Meet1()));
},
child: Container(
width: size.width * 0.9,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(70)),
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomRight,
colors: [
Colors.green,
Colors.orange,
],
),
),
child: Column(children: <Widget>[
SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Text(
time[Index],
style: TextStyle(
color: Colors.white,
fontSize: 40,
fontWeight:
FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(
who[Index],
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight:
FontWeight.bold),
),
Text(
when[Index],
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight:
FontWeight.bold),
),
Text(
where[Index],
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight:
FontWeight.bold),
Second page
child: Column(children: <Widget>[
SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
TextField(decoration: InputDecoration(hintText: " Time ")),
SizedBox(
height: 10,
),
TextField(
decoration: InputDecoration(hintText: " Who "),
),
SizedBox(
height: 10,
),
TextField(
decoration: InputDecoration(hintText: " Date "),
),
SizedBox(
height: 10,
),
TextField(
decoration: InputDecoration(hintText: " Where "),
),
SizedBox(height: 10)
],
),
),
]));
Here the Flatbutton to add all.
return FlatButton(
child: Icon(
Icons.check_circle_outline_rounded,
color: Colors.green,
size: 120,
),
onPressed: () {
Navigator.of(context).popUntil((route) => route.isFirst);
},
Use a TextEditingController(), just like this -
TextEditingController() myController = TextEditingController();
Then assign this controller to controller property in TextField() -
TextField(
controller: myController,
),
Then use myController.text to retrieve the text from TextField(), and pass it to other pages as a String parameter -
Example -
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
//....
body: FlatButton(
child: Icon(
Icons.check_circle_outline_rounded,
color: Colors.green,
size: 120,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (builder) {
return Screen2(text: myController.text);
}));
},
//....
),
);
}
}
Second Page -
class Screen2 extends StatelessWidget {
String text;
Screen2({this.text});
#override
Widget build(BuildContext context) {
return Scaffold(
//....
body: Text(text),
);
}
}
Go to this link to see another example
Now, here I used only 1 parameter "text". You can use multiple parameters like - "text1", "text2", "text3" and so on, as per your requirement, and use as many TextEditingController() for this.
*****Also Note that use of FlatButton() is depreciated, you can use a TextButton() instead

Flutter - Issues when I try to filter the results (using SearchDelegate)

I got some problems to filter the results into the SearchDelegate.
Here is my code:
class CustomSearchDelegate extends SearchDelegate<String> {
List<DropdownMenuItem<String>> _listaItensDropCategorias;
List<DropdownMenuItem<String>> _listaItensDropEstados;
String _itemSelecionadoCategoria;
String _itemSelecionadoEstado;
_carregarItensDropdown(){
//Categorias
_listaItensDropCategorias = Configuracoes.getCategorias();
//Estados
_listaItensDropEstados = Configuracoes.getEstados();
}
_abrirDialog(BuildContext context) async {
_carregarItensDropdown();
return showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context){
return StatefulBuilder(
builder: (BuildContext context,StateSetter setState){
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10, bottom: 20),
child: Text("Filtrar", style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 27),),
),
Padding(
padding: EdgeInsets.only(bottom: 5),
child: Row(
children: <Widget>[
Text("Categoria", style: TextStyle(color: Colors.grey, fontSize: 20),),
Expanded(
child: Wrap(
alignment: WrapAlignment.end,
children: <Widget>[
DropdownButton(
value: _itemSelecionadoCategoria,
items: _listaItensDropCategorias,
style: TextStyle(
fontSize: 20,
color: Colors.black
),
onChanged: (categoria){
setState(() {
_itemSelecionadoCategoria = categoria;
});
},
),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.only(bottom: 5),
child: Row(
children: <Widget>[
Text("Estado", style: TextStyle(color: Colors.grey, fontSize: 20),),
Expanded(
child: Wrap(
alignment: WrapAlignment.end,
children: <Widget>[
DropdownButton(
value: _itemSelecionadoEstado,
items: _listaItensDropEstados,
style: TextStyle(
fontSize: 20,
color: Colors.black
),
onChanged: (estado){
setState(() {
_itemSelecionadoEstado = estado;
});
},
),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.only(top: 30),
child: Row(
children: <Widget>[
Expanded(
child: Wrap(
alignment: WrapAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 30),
child: GestureDetector(
child: Text(
"Aplicar",
style: TextStyle(color: Colors.lightBlue),
),
onTap: (){ //************************************Here is my problem
showResults(context);
Navigator.pop(context);
},
),
),
GestureDetector(
child: Text(
"Cancelar",
style: TextStyle(color: Colors.lightBlue),
),
onTap: (){
Navigator.pop(context);
},
),
],
),
),
],
),
),
],),
);
},
);
}
);
}
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
},
),
IconButton(
icon: Icon(Icons.tune),
onPressed: () {
_abrirDialog(context);
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, "");
},
);
}
#override
Widget buildResults(BuildContext context) {
return Pesquisar(query.toUpperCase(),_itemSelecionadoCategoria,_itemSelecionadoEstado);
}
}
As you can see, I build an "alertDialog" where the user can choose the filters (Categoria and Estado), and I put a GestureDetector "Aplicar" (see the image below) to apply automatically the filters and show results, but nothing happens when I press it.
But when I select the filters, type in the Search Field (see the image below) and press the search button (magnifying glass), the filters are applied.
P.S.: I know why it works when I press the search button, 'cause I passed the parameters ("_itemSelecionadoCategoria" , "_itemSelecionadoEstado") to the buildResults, where it answer when the search button is pressed.
So, my doubt is: What can I put in the onTap from GestureDetector "Aplicar" to give me the results with the filters applied? (I thought that putting "showResults(context)" in the "onTap" would solve my problem, but it didn't work).