RangeError (index): Valid value range is empty: 0 - flutter

I am trying to display data from an api in a ListView.builder, I want to set the itemCount to 20 but when I do that, before the data is displayed I get the following error RangeError (index): Valid value range is empty: 0 the '0' is incremented in each card until '20'. If anyone can help me, thanks.
import 'dart:typed_data';
import 'package:badges/badges.dart';
import 'package:banner_carousel/banner_carousel.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:kaomini/Pages/accueil.dart';
import 'package:kaomini/Pages/detail_article.dart';
import 'package:kaomini/Pages/panier.dart';
import 'package:kaomini/widgets/drawer_menu.dart';
import 'package:kaomini/widgets/images.dart';
class PromoArticle extends StatefulWidget {
const PromoArticle({Key? key}) : super(key: key);
_PromoArticleState createState() => _PromoArticleState();
}
class _PromoArticleState extends State<PromoArticle> {
List userdata = [];
int _count = 20;
Future<void> getrecord() async {
var uri = Uri.parse(
My api;
try {
var response = await http.get(
uri,
);
setState(() {
userdata = jsonDecode(response.body);
});
} catch (e) {
print(e);
}
}
void increment(){
setState((){
_count = _count + 10;
});
}
#override
void initState() {
getrecord();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: const IconThemeData(color: Colors.black, size: 33.0),
backgroundColor: Colors.white,
shadowColor: Colors.white,
elevation: 0,
actions: [
Container(
padding: const EdgeInsets.only(right: 19.0),
child: Badge(
badgeColor: Colors.amberAccent,
badgeContent: Text("${Panier.art.length}"),
animationType: BadgeAnimationType.fade,
child: IconButton(onPressed: () => Navigator.push(context, MaterialPageRoute(
builder: (context) => Panier(products: <Product> [
//Product(nom: widget.mail, mail: widget.mail)
],)
)
),
icon: const Icon(Icons.shopping_cart_outlined))),
)
],
bottom: PreferredSize(
child: Container(
alignment: Alignment.bottomLeft,
margin: const EdgeInsets.only(left: 50.0),
child: const Text("Produits en promo",
style: TextStyle(
fontSize: 19.0,
fontWeight: FontWeight.w500,
color: Colors.blue
),
),
),
preferredSize: const Size.fromHeight(20.0),
),
),
body: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 20.0,),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: userdata == null ? 0 : _count,
itemBuilder: (context, index) {
debugPrint(userdata[index]['photo'].toString());
return userdata == null ? const Center(child: Text('Aucune donnees !'),)
: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => DetailArticle(
id: userdata[index]['id'],
titre: userdata[index]['title'],
description: userdata[index]['description'],
prix: userdata[index]['realPrice'],
image: userdata[index]['pictures'],
prixPromo: userdata[index]["discountPrice"],
//.toString() == null ?
//"https://www.kaomini.ne/uploads/images/logo.png" :
//userdata[index]['photo'],
)
)
),
child: Card(
margin: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//Image.network(userdata[index]['photo'].toString()),
Expanded(
flex: 2,
child: userdata[index]["pictures"] == null ? MyAssetImage.logo1 :
Image.network("https://kaomini.ne/uploads/productPictures/"+userdata[index]["pictures"]),//MyAssetImage.img2
),
Expanded(
child: ListTile(
enabled: false,
title: Row(
children: [
Expanded(
flex: 2,
child: Text(userdata[index]["discountPrice"]+' FCFA',
style: const TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500,
fontSize: 17.0
),
textAlign: TextAlign.center,
),
),
Expanded(
child: Text(userdata[index]["realPrice"],
style: const TextStyle(
color: Colors.grey,
decoration: TextDecoration.lineThrough,
fontWeight: FontWeight.w300,
fontSize: 15.0
),
textAlign: TextAlign.center,
),
),
],
),
subtitle: Text(userdata[index]["title"],
style: const TextStyle(
fontWeight: FontWeight.w300,
fontSize: 15.0
),
textAlign: TextAlign.center,
),
),
),
],
),
),
);
},
),
ElevatedButton(onPressed: increment,
style: ElevatedButton.styleFrom(
minimumSize: const Size(400, 50),
primary: Colors.blue[100],
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),)
),
child: const Text("Voir plus", style: TextStyle(color: Colors.white, fontSize: 16),)
),
],
),
),
endDrawer: const MyMenu(),
);
}
} ```

Change
itemCount: userdata == null ? 0 : _count,
to
itemCount: userdata.isEmpty ? 0 : _count,
or
itemCount: userdata.length,

Related

How can I fix the renderflex overflow of a card in Flutter?

How can I fix the RenderFlex overflowed pixel in my card Flutter? I cant seem to find a tutorial regarding this kind of problem. All of the tutorials in StackOverflow teach you to use the listview and SingleChildScrollView but that is not the case for me. The error shows in the card itself and I don't want the card to be using a singlechildscrollview.
I already tried fixing it by lowering the height and width but I will still need a proper tutorial that can help me fix this kind of issues.
This is the card.dart for the application
import 'package:flutter/material.dart';
class ListViewCard extends StatelessWidget {
final String title;
final void Function()? onTap;
final String imageOfPlant; //Change to String
const ListViewCard({
super.key,
required this.title,
required this.onTap,
required this.imageOfPlant,
});
#override
Widget build(BuildContext context) {
return Card(
color: const Color.fromARGB(255, 75, 175, 78),
elevation: 1,
margin: const EdgeInsets.all(8),
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: InkWell(
splashColor: Colors.lightGreenAccent.withAlpha(30),
onTap: onTap,
//sizedBox of the card
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//image of the card
Image.asset(
imageOfPlant,
height: 200,
width: 150,
fit: BoxFit.cover,
),
SizedBox(
height: 50,
width: 150,
child: Center(
child: Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 19,
fontFamily: 'RobotoMedium',
color: Color(0xffeeeeee)), // textstyle
),
),
), //text //SizedBox
], // <widget>[]
), // column
), //inkwell
); // card
}
}
This is the home.dart where the card will be called.
import 'package:flutter/material.dart';
import 'package:picleaf/nav_pages/plant.dart';
import '../widgets/card.dart';
class homePage extends StatefulWidget {
const homePage({super.key});
#override
State<homePage> createState() => _HomePageState();
}
List<String> plants = [
"Bell Pepper",
"Cassava",
"Grape",
"Potato",
"Strawberry",
"Tomato",
];
class CustomSearchDelegate extends SearchDelegate {
// Demo list to show querying
CustomSearchDelegate({String hinttext = "Search plants here"})
: super(searchFieldLabel: hinttext);
// first overwrite to
// clear the search text
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(Icons.clear),
),
];
}
// second overwrite to pop out of search menu
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
close(context, null);
},
icon: const Icon(Icons.arrow_back),
);
}
// third overwrite to show query result
#override
Widget buildResults(BuildContext context) {
List<String> matchQuery = [];
for (var fruit in plants) {
if (fruit.toLowerCase().contains(query.toLowerCase())) {
matchQuery.add(fruit);
}
}
return ListView.builder(
itemCount: matchQuery.length,
itemBuilder: (context, index) {
var result = matchQuery[index];
return ListTile(
title: Text(
result,
style: const TextStyle(fontFamily: 'RobotoMedium'),
),
);
},
);
}
// last overwrite to show the
// querying process at the runtime
#override
Widget buildSuggestions(BuildContext context) {
List<String> matchQuery = [];
for (var fruit in plants) {
if (fruit.toLowerCase().contains(query.toLowerCase())) {
matchQuery.add(fruit);
}
}
return ListView.builder(
itemCount: matchQuery.length,
itemBuilder: (context, index) {
var result = matchQuery[index];
return ListTile(
title: Text(
result,
style: const TextStyle(fontFamily: 'RobotoMedium'),
),
);
},
);
}
}
class _HomePageState extends State<homePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
"PicLeaf",
style: TextStyle(
color: Color.fromRGBO(102, 204, 102, 1.0),
fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
shadowColor: const Color.fromARGB(255, 95, 94, 94),
actions: [
IconButton(
onPressed: () {
// method to show the search bar
showSearch(
context: context,
// delegate to customize the search bar
delegate: CustomSearchDelegate());
},
icon: const Icon(Icons.search, color: Colors.black),
)
],
),
backgroundColor: const Color(0xffeeeeee),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 10,
),
Container(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 10),
child: const Text(
'Take a pic!',
style: TextStyle(
fontSize: 35,
fontFamily: 'RobotoBold',
color: Colors.black),
textAlign: TextAlign.left,
),
),
Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
child: const Text('Find out what is wrong with your plant!',
style: TextStyle(
fontSize: 18,
fontFamily: 'RobotoMedium',
color: Color.fromRGBO(102, 124, 138, 1.0)),
textAlign: TextAlign.left),
),
const SizedBox(
height: 10,
),
Container(
color: const Color.fromRGBO(102, 204, 102, 1.0),
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 0),
margin: const EdgeInsets.symmetric(horizontal: 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Expanded(
child: Text('List of Plants',
style: TextStyle(
fontSize: 30,
fontFamily: 'RobotoBold',
color: Color(0xffeeeeee)),
textAlign: TextAlign.center),
),
],
),
),
GridView.count(
physics: const ScrollPhysics(),
shrinkWrap: true,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
children: <Widget>[
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
],
),
],
),
),
],
),
),
);
}
}
Your gridView's Item give you a specific size but you are setting more than that for your container and text, I suggest you try this:
child: Stack(
children: <Widget>[
//image of the card
Image.asset(
imageOfPlant,
height: double.infinity,
width: 150,
fit: BoxFit.cover,
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: SizedBox(
height: 50,
width: 150,
child: Center(
child: Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 19,
fontFamily: 'RobotoMedium',
color: Color(0xffeeeeee)), // textstyle
),
),
),
), //text //SizedBox
], // <widget>[]
),
and If you want to change item's AspectRatio you can do this:
GridView.count(
physics: const ScrollPhysics(),
shrinkWrap: true,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
childAspectRatio: 2 / 3, <--- add this
children: <Widget>[
...
]
)

RangeError (index): Invalid value: Valid value range is empty: 0 Failed assertion: line 'url != null': is not true

I'm facing this error in Image.network I don't get why I get the message
"RangeError (index): Invalid value: Valid value range is empty: 0"
And from current snippet
"error: The argument type 'Widget' can't be assigned to the parameter type 'String'. "
import 'package:flutter/material.dart';
import 'post_model.dart';
class SearchPage extends StatefulWidget {
final List<Post> posts;
const SearchPage({required this.posts});
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
List<Post> _searchedPost = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
hintText: 'Cerca Articolo',
hintStyle: TextStyle(color: Colors.white),
border: InputBorder.none),
onChanged: (val) {
setState(() {
_searchedPost =
widget.posts.where((el) => el.title.contains(val)).toList();
});
},
),
),
body: _searchedPost.isEmpty
? Center(
child: Text(
'Nessun articolo disponibile',
// //snapshot.data!= null ? snapshot.data![i]["_embedded"]["wp:featuredmedia"][0]["source_url"] : "Nessun articolo",
style: Theme.of(context).textTheme.headline3,
),
)
: ListView.builder(
itemCount: _searchedPost.length,
itemBuilder: (context, i) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Card(
margin: const EdgeInsets.all(10),
elevation: 5,
shadowColor: Colors.black26,
color: Colors.white,
child: InkWell(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(_searchedPost[i].urlImage == null ? const Text("could not found") : Image.network(""),
width: double.infinity,
height: 220,
fit: BoxFit.cover,
),
// Title article
Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 16, top: 16, bottom: 16),
child: Row(
children: [
Expanded(
child: Text(_searchedPost[i].title,
maxLines: 3,
overflow: TextOverflow.clip,
softWrap: true,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: "Raleway",
),
),
),
],
),
)
],
),
],
),
),
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
// ArticlePage(data: snapshot.data?[i]),
// ),
// );
},
),
),
const Divider(
height: 1,
)
// ListTile(
// title: Text(_searchedPost[i].title),
// ),
],
);
},
),
);
}
}
Error place
Do like this for image
_searchedPost[i].urlImage == null
? const Text("could not found")
: Image.network(
_searchedPost[i].urlImage,
width: double.infinity,
height: 220,
fit: BoxFit.cover,
),

Flutter: Textfield controller on a nested listview.builder

hello can someone help me on nested listview.
as you can see from the image below, i made two listview.builders.
first listview.builder(context, i) is for the headers "ChildWO:" and a description below.
Than another listview.builder(context, index) for under it that contains data about it (shown in card widgets).
My problem is, whenever I input a value inside the textfield.
every textfield that have the same position will be filled up.
for example "55". every first card of it will be filled with "55".
Is there a way wherein I can set the controller of the textfield to have it like,
"controller: _qtyInputtedList[i][index]"?
for now, my controller is set at controller: _qtyInputtedList[index].
Thank you.
Expanded(
child: Container(
decoration: BoxDecoration(color: Colors.white),
child: ListView.separated(
physics: const AlwaysScrollableScrollPhysics(),
separatorBuilder: (context, index) => SizedBox(
height: 1,
),
itemCount: mainParent.CHILDREN?.length ?? 0,
itemBuilder: (context, i) {
// _qtyInputtedList.add(new TextEditingController());
return Padding(
padding: EdgeInsets.fromLTRB(2, 10, 2, 0),
child: Column(
children: <Widget>[
Text(
'Child WO: ${mainParent.CHILDREN![i].WONUM}',
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
fontWeight: FontWeight.bold,
fontFamily: 'NunitoLight'),
),
Padding(
padding:
EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Text(
'${mainParent.CHILDREN![i].WODESC}',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 15.0,
color: Colors.black,
fontWeight: FontWeight.bold,
fontFamily: 'NunitoLight'),
),
),
ListView.builder(
itemCount: mainParent
.CHILDREN![i].MATERIALS!.length,
itemBuilder: (context, index) {
_qtyInputtedList.add(new TextEditingController());
final post = mainParent
.CHILDREN![i].MATERIALS![index];
//tileKey.add(GlobalKey(debugLabel: "index :$i"));
return Padding(
padding: mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"1"
? const EdgeInsets.fromLTRB(
10, 4, 10, 4)
: const EdgeInsets.fromLTRB(
20, 4, 10, 4),
child: GestureDetector(
onLongPress: () {
//itemNum will be used for component list endpoint
itemNum =
'${mainParent.CHILDREN![i].MATERIALS![index].ITEMNUM}';
mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"1"
? _displayDialogListMaterials(
context)
: null;
},
child: ExpansionTileCard(
//key: tileKey[i],
//key: tileKey[i],
//baseColor: Colors.grey[800],
baseColor: mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"1"
? Color(0xff3A3845)
: Color(0xff826F66),
// baseColor: Colors.red[700],
expandedTextColor:
Colors.black,
expandedColor: mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"1"
? Color(0xff3A3845)
: Colors.grey[600],
trailing: Transform.scale(
scale: 2.5,
child: Theme(
data: ThemeData(
unselectedWidgetColor:
Colors.grey[
700], // Your color
),
child: Container(
margin:
EdgeInsets.all(10),
width: 14,
height: 14,
color: Colors.white,
child: Checkbox(
hoverColor:
Colors.white,
activeColor: Colors
.green[700],
value:
selectedItems.contains(mainParent
.CHILDREN![i]
.MATERIALS![index]),
onChanged:
(bool? value) {
if(selectedItems.contains(mainParent
.CHILDREN![i]
.MATERIALS![index])) {
selectedItems.remove(mainParent
.CHILDREN![i]
.MATERIALS![index]);
selectedItems.remove(mainParent
.CHILDREN![i]
.MATERIALS![index].ITEMNUM);
selectedItems.remove(mainParent
.CHILDREN![i]
.WONUM);
selectedItems.remove(_qtyInputtedList[index].text);
} else {
selectedItems.add(mainParent
.CHILDREN![i]
.MATERIALS![index]);
selectedItems.add(mainParent
.CHILDREN![i]
.MATERIALS![index].ITEMNUM);
selectedItems.add(mainParent
.CHILDREN![i]
.WONUM);
selectedItems.add(_qtyInputtedList[index].text);
}
setState(() {
print(selectedItems.toString());
//if you want to reload loadparent2
// dataFuture = loadParent2();
});
}),
),
),
),
// leading: Icon(
// Icons.warning_amber,
// color: Colors.white,
// size: 60.0,
// ),
leading: mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"0"
? Container(
width: 60.0,
child: TextField(
controller: _qtyInputtedList[index],
keyboardType:
TextInputType
.number,
style: TextStyle(
fontSize: 20),
decoration:
InputDecoration(
filled: true,
fillColor:
Colors.white,
border:
InputBorder
.none,
),
),
)
: null,
title: Text(
'${mainParent.CHILDREN![i].MATERIALS![index].ITEMNUM}',
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(
fontSize: 25,
color: Colors.white,
fontWeight:
FontWeight
.bold),
),
subtitle: Text(
'${mainParent.CHILDREN![i].MATERIALS![index].ITEMDESCRIPTION}',
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(
fontSize: 16,
color:
Colors.white),
),
children: mainParent
.CHILDREN![i]
.MATERIALS![index]
.STRUCTURE ==
"0"
? <Widget>[
Divider(
thickness: 3.0,
height: 3.0,
),
Align(
alignment: Alignment
.centerLeft,
child: Padding(
padding:
const EdgeInsets
.symmetric(
horizontal:
16.0,
vertical: 5.0,
),
child: Text(
"Planned QTY: ${mainParent.CHILDREN![i].MATERIALS![index].QUANTITYPLAN}"
"\n"
"Warehouse Balance: 30",
style: Theme.of(
context)
.textTheme
.bodyText2!
.copyWith(
fontSize:
22),
),
),
),
ButtonBar(
alignment:
MainAxisAlignment
.start,
buttonHeight: 52.0,
buttonMinWidth:
90.0,
children: <
Widget>[],
),
]
: <Widget>[])),
);
},
shrinkWrap: true,
physics: ClampingScrollPhysics(),
)
],
),
);
}),
),
),
I recommend you to split your code to reuseable widgets, by this way you don't need to care about controller and how to declare it they are differences, code look short and clearly, below is example.
Example:
import 'package:flutter/material.dart';
class Student {
int id;
String name;
Student(this.id, this.name);
}
class Class {
String name;
List<Student> students;
Class(this.name, [this.students = const []]);
}
class RenderStudent extends StatefulWidget {
const RenderStudent({required this.student, Key? key}) : super(key: key);
final Student student;
#override
RenderStudentState createState() => RenderStudentState();
}
class RenderStudentState extends State<RenderStudent> {
Student get student => widget.student;
late TextEditingController controller;
#override
void initState() {
controller = TextEditingController(text: widget.student.name);
controller.addListener(() => setState(() {}));
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return TextField(
controller: controller,
decoration: InputDecoration(
labelText: "Student id: ${student.id}",
border: const OutlineInputBorder(),
),
);
}
}
class RenderClass extends StatelessWidget {
const RenderClass({required this.clas, Key? key}) : super(key: key);
final Class clas;
#override
Widget build(BuildContext context) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("Class ${clas.name}", style: const TextStyle(fontSize: 40)),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: clas.students.length,
itemBuilder: (context, i) => Padding(
padding: const EdgeInsets.all(4),
child: RenderStudent(
student: clas.students[i],
),
),
),
],
),
);
}
}
void main() {
final items = [
Class('A1', [Student(1, "Carter")]),
Class('B1', [Student(2, "Join"), Student(2, "Smith"), Student(2, "Lara")]),
];
return runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, i) => RenderClass(clas: items[i]),
),
),
),
);
}

Flutter : Is there a way to make a gridview wait until I load all the data

I am reading from the local DB (SqlLite) and my gridview doesn't render when I press restart. However, when I do a hot reload the grid renders just fine with the data. I am guessing during the init since the data is still being loaded and the gridview doesn't wait. Is there any way I can manage that?
Here is my code.
class BookShelfList extends StatefulWidget {
const BookShelfList({Key? key}) : super(key: key);
#override
State<BookShelfList> createState() => _BookShelfListState();
}
class _BookShelfListState extends State<BookShelfList> {
late List<BookShelf> data = [];
#override
void initState() {
// TODO: implement initState
super.initState();
_getBooks();
}
#override
Widget build(BuildContext context) {
return Container(
height: 300,
child: Column(
children: [
Text("You have ${data.length} books "),
Flexible(child: buildGridList(data)),
],
),
);
}
Widget buildGridList(List<BookShelf> data) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
itemCount: data.length,
itemBuilder: (BuildContext context, index) {
return Card(
margin: EdgeInsets.all(5),
child: GridTile(
header: GridTileBar(
backgroundColor: Colors.white,
title: Text(
data[index].author,
style: TextStyle(color: Colors.black),
),
subtitle: Text(data[index].dateAdded,
style: TextStyle(color: Colors.grey)),
trailing: IconButton(
onPressed: () {},
icon: const Icon(
Icons.more_vert_rounded,
color: Colors.black54,
)),
),
child: Image.network(
data[index].thumbnail,
height: 60,
width: 70,
fit: BoxFit.fill,
),
footer: GridTileBar(
backgroundColor: Colors.white,
title: Row(
children: const [
Icon(
Icons.favorite_outline,
color: Colors.grey,
),
Text('20', style: TextStyle(color: Colors.black)),
SizedBox(
width: 20,
),
Icon(
Icons.chat_bubble_outline,
color: Colors.grey,
),
Text(
'5',
style: TextStyle(color: Colors.black),
),
],
),
trailing: const Icon(
Icons.bookmark_outline,
color: Colors.black,
),
)),
);
},
);
_getBooks() async {
data = await BookShelfDbProvider().fetchBook();
}}
Try calling setState() in _getBooks() right after the data = await BookShelfDbProvider().fetchBook();
Make Gridview.builder a child of future builder and pass future to _getBooks()
What happens is, while the _getBooks() function is running, you could show a CircularProgressBar, and as soon as the data is received, GridView.builderis triggered.
And calling _getBooks() in initState() is not necessary in this case.
Here's your updated code:
_getBooks() async {
data = await BookShelfDbProvider().fetchBook();
}
class BookShelfList extends StatefulWidget {
const BookShelfList({Key? key}) : super(key: key);
#override
State<BookShelfList> createState() => _BookShelfListState();
}
class _BookShelfListState extends State<BookShelfList> {
late List<BookShelf> data = [];
#override
Widget build(BuildContext context) {
return Container(
height: 300,
child: Column(
children: [
Text("You have ${data.length} books "),
Flexible(child: buildGridList(data)),
],
),
);
}
Widget buildGridList(List<BookShelf> data) {
return FutureBuilder(
future: _getBooks(),
builder: (context, snapshot){
if(snapshot!=null){
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
),
itemCount: data.length,
itemBuilder: (BuildContext context, index) {
return Card(
margin: EdgeInsets.all(5),
child: GridTile(
header: GridTileBar(
backgroundColor: Colors.white,
title: Text(
data[index].author,
style: TextStyle(color: Colors.black),
),
subtitle: Text(data[index].dateAdded,
style: TextStyle(color: Colors.grey)),
trailing: IconButton(
onPressed: () {},
icon: const Icon(
Icons.more_vert_rounded,
color: Colors.black54,
)),
),
child: Image.network(
data[index].thumbnail,
height: 60,
width: 70,
fit: BoxFit.fill,
),
footer: GridTileBar(
backgroundColor: Colors.white,
title: Row(
children: const [
Icon(
Icons.favorite_outline,
color: Colors.grey,
),
Text('20', style: TextStyle(color: Colors.black)),
SizedBox(
width: 20,
),
Icon(
Icons.chat_bubble_outline,
color: Colors.grey,
),
Text(
'5',
style: TextStyle(color: Colors.black),
),
],
),
trailing: const Icon(
Icons.bookmark_outline,
color: Colors.black,
),
)),
);
},
);
} else {
return CircularProgressIndicator();
}
}
);
Please adjust the {}'s as necessary.

how to store the name of the container in an array

hi i am new to flutter can anyone tell me how to save the preferences in an array
what are the methods used in storing the value
class PrefPage extends StatefulWidget {
#override
_PrefPageState createState() => _PrefPageState();
}
class _PrefPageState extends State<PrefPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: Container(
color: Theme.of(context).backgroundColor,
padding: EdgeInsets.fromLTRB(10, 10, 30, 10),
height: 80,
child: Spring.bubbleButton(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Home()));
},
child: Text(
"👉",
style: TextStyle(fontSize: 30),
textAlign: TextAlign.end,
),
),
),
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
centerTitle: false,
leadingWidth: 0,
elevation: 0,
backgroundColor: Theme.of(context).backgroundColor,
title: Text(
"Swoken",
style: GoogleFonts.niconne(
textStyle: TextStyle(
fontSize: 30,
color: Theme.of(context).primaryColor,
),
),
),
),
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
" What are your",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.w100),
),
Text(
" Interests ?",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
GridView.count(
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
childAspectRatio: 2.3,
crossAxisCount: 2,
padding: EdgeInsets.all(5),
shrinkWrap: true,
children: List.generate(
intr.length,
(index) {
return PrefCont(
child: AutoSizeText(
intr[index]["icon"] + " " + intr[index]["title"],
minFontSize: 16,
maxLines: 1,
style: TextStyle(fontSize: 40),
),
);
},
),
),
],
),
),
),
);
}
}
class PrefCont extends StatefulWidget {
PrefCont({this.child});
final child;
#override
_PrefContState createState() => _PrefContState();
}
class _PrefContState extends State<PrefCont> {
List<String> sel = [];
bool isSelected = false;
#override
Widget build(BuildContext context) {
var themeId = DynamicTheme.of(context)!.themeId;
var kContColor = Color(0Xfff6f6f6);
themeId == 0
? kContColor = Color(0Xfff6f6f6)
: kContColor = Color(0xff272727);
return InkWell(
onTap: () {
setState(() {
isSelected = !isSelected;
});
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected ? kContInactColor : kContColor,
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: widget.child,
),
);
}
}
...........................................................................................................................................................................................................................................................................
First you need to modelize your elements as objects then, you need to create a data set containing all of your tiles:
class PreferencesData {
final String name;
final String assetName;
PreferencesData({required this.name, required this.assetName});
}
list _dataSet = [
PreferencesData(name: "Football", assetName: "/assets/icons/football.png"),
PreferencesData(name: "Food", assetName: "/assets/icons/food.png"),
...
];
Now that you have all your objects in a dataset you can use it in your grid to display them correctly:
children: [for (PreferencesData pref in _dataSet)
PrefCont(...) // access your data with pref.name
]