App crashes when load a lot of data inside a gridview - flutter

Description
I'm using a gridview to show the products of a market and when a scroll the gridview nine times my app crashes.
The widget build of this screen return a SmartRefresher wrapped a GridView.
return SmartRefresher(
controller: controller.refreshController,
onLoading: controller.onLoading,
onRefresh: controller.onRefresh,
enablePullUp: true,
child: Observer(builder: (context) {
return GridView.builder(
padding: EdgeInsets.only(top: 10),
shrinkWrap: true,
cacheExtent: 100,
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 2
: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
childAspectRatio: 0.85,
),
itemCount:
controller.produtos == null ? 0 : controller.produtos.length,
itemBuilder: (context, index) {
Produto produto = controller.produtos[index];
//here I return my card
},
);
}),
);
Note: If I remove the SmartRefresher I can scroll the GridView with a lot of data.

Try to place the Observer above SmartRefresher, like this:
Observer(
builder: (context) {
return SmartRefresher(
controller: controller.refreshController,
onLoading: controller.onLoading,
onRefresh: controller.onRefresh,
enablePullUp: true,
child: GridView.builder(
padding: EdgeInsets.only(top: 10),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 2
: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
childAspectRatio: 0.85,
),
itemCount:
controller.produtos == null ? 0 : controller.produtos.length,
itemBuilder: (context, index) {
Produto produto = controller.produtos[index];
},
),
);
},
);

Related

Implementing flutter ui

I have been trying to recreate this ui where the gridview
This is what I have tried so far
GridView.builder(
shrinkWrap: true,
primary: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
mainAxisExtent: 300,
),
itemCount: snapshot.data!.length,
padding: const EdgeInsets.all(8.0),
itemBuilder: (BuildContext context, int index) {
final model = result[index];
return MyContainer(
loanProductModel: model,
);
},
)
This is the screenshot of what I have tried.
You can achieve it by using flutter_staggered_grid_view package and the below code
import 'package:flutter/material.dart';
class ScrollView extends StatelessWidget {
const ScrollView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverPadding(
padding: EdgeInsets.symmetric(horizontal: 12),
sliver: SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
mainAxisSpacing: 9.0,
crossAxisSpacing: 9.0,
staggeredTileBuilder: (int index) =>
StaggeredTile.count(1, index % 5 == 0 ? 1.5 : 1.2),
itemCount: snapshot.data!.length,
itemBuilder: (ctx, i) {
final model = result[index];
return MyContainer(
loanProductModel: model,
);
}),
),
],
),
);
}
}

Skip an item in gridview without leaving a hole

I'm building a gridview displaying thumbnails and do not want to show the items at index 0. I have a different widget where I show thumbnails using a listview with the Visibility widget. That works!
Like so:
ListView.separated(
separatorBuilder: (BuildContext context, int index) =>
SizedBox(
width: mainElementSize * 0.02,
),
scrollDirection: Axis.horizontal,
controller: paneController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
addAutomaticKeepAlives: true,
reverse: true,
itemCount: mainElementList.mainElementList.length,
//
itemBuilder: (BuildContext context, int index) {
return Visibility(
visible: index > 0,
child: UnconstrainedBox(
child: HistoryThumb(
index: index,
),
),
);
}),
The gridview does work with Visibility, but different. Instead of just skipping the object, it leaves a whole in the grid. Code:
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: gridheight * 0.015,
crossAxisSpacing: gridWidth * 0.015,
),
padding: EdgeInsets.symmetric(
horizontal: 0,
),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount:
Provider.of<MainElementList>(context).mainElementList.length,
//
itemBuilder: (context, index) => Visibility(
visible: index > 0,
child: UnconstrainedBox(
child: HistoryThumb(
index: index,
),
),
)),
Screenshot:
Any way to not have it do that? I found a similar topic here: How to skip build in item builder gridview.builder Flutter Firebase Stream Builder
But I do not want to build a seperate list and duplicate all my objects just to display the thumbnails. Isn't there something more elegant for skipping certain items?
Instead of using Visibility widget you can apply ternary operator and pass SizedBox at index 0:-
index == 0 ? SizedBox() : UnconstrainedBox(
child: HistoryThumb(
index: index,
),
),
Can you try like this:-
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: gridheight * 0.015,
crossAxisSpacing: gridWidth * 0.015,
),
padding: EdgeInsets.symmetric(
horizontal: 0,
),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount:
Provider.of<MainElementList>(context).mainElementList.length - 1,
//
itemBuilder: (context, index) => Visibility(
visible: index > 0,
child: UnconstrainedBox(
child: HistoryThumb(
index: index+1,
),
),
)),
subtract 1 from itemCount and add 1 in Index history Thumb. I think we can't skip an certain item in the build but we can achieve what you want from this!!
You can achieve your required behaviour by moving your particular item to the end of the list; then you can simply hide that last item in the grid view.
This way, you wont see any whitespace in middle of the grid view.
For example:
List<String> list = [
"mustafa",
"hawari",
"ravi",
"shyam"
];
int indexOfItem = list.indexOf("hawari");
String itemTobeAddedAtLast = list[indexOfItem];
list.removeAt(indexOfItem);
list.insert(list.length, itemTobeAddedAtLast);
print(list);
// this returns
// [mustafa, ravi, shyam, hawari]
You can use a condition on the builder
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: gridheight * 0.015,
crossAxisSpacing: gridWidth * 0.015,
),
padding: EdgeInsets.symmetric(
horizontal: 0,
),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount:
Provider.of<MainElementList>(context).mainElementList.length,
//
itemBuilder: (context, index) => {
if(index == 0) {
return --- What you want to return at index 0 --;
} else {
return --- the actual builder that you are using normally ---;
}
}

Unable to remove the padding in Expanded Widget

I can't seem to find why after the first Text Widget, there is a big gap of space. I didn't put any Padding or SizedBox but somehow, the Expanded seem to have its own padding. Please help on how can I adjust that space in between the text and numbers. Thanks!
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Text'),
Expanded(
child: GridView.builder(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, childAspectRatio: 5 / 1),
itemCount: 6,
itemBuilder: (BuildContext ctx, index) {
return Text('$index');
}),
),
],
);
}
Output:
Text
0 1 2
3 4 5
Expected output:
Text
0 1 2
3 4 5
Note: This is the minimized code in order to show the essential.
Change your GridView.builder to this:
Expanded(
child: GridView.builder(
padding: const EdgeInsets.only(top: 0),
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, childAspectRatio: 5 / 1),
itemCount: 6,
itemBuilder: (BuildContext ctx, index) {
return Text('$index');
}),
)

How to get data from the StreamBuilder into the GridView directly in flutter?

Hello I'm setting a profile page and I'm trying to get the data from Firestore, so I set up a StreamBuilder<List> and gave it the stream to get the data but the problem is how to I use that data to display it into my GridView?
My code:
StreamBuilder<List<UserModel>>(
stream: userProviderData.user,
builder: (context, snapshot) {
return GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
primary: false,
shrinkWrap: true,
children: [
Text(
'How Do I get the FullName here?' ?? fullNameOnNullText,
style: Theme.of(context).textTheme.subtitle2.copyWith(fontWeight:
FontWeight.w600),
),
],
);
You can get the data from the StreamBuilder by using the .data property of the snapshot in the builder.
And since your data is a list, you can map that into a list of child widgets in the GridView.
See below:
StreamBuilder<List<UserModel>>(
stream: userProviderData.user,
builder: (context, snapshot) {
List<UserModel> userModelList = snapshot.data;
return GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
primary: false,
shrinkWrap: true,
children: userModelList.map((UserModel userModel) =>
Text(
userModel.name,
style: Theme.of(context).textTheme.subtitle2.copyWith(fontWeight:
FontWeight.w600),)
.toList()
,
);
Before returning the widget, you should check first if the stream has finished loading.
After getting the data, the best way is to use List<Widget>.generate() for the child creation.
You can try this:
StreamBuilder<List<UserModel>>(
stream: userProviderData.user,
builder: (context, snapshot) {
if (!snapshot.hasData) { // Check the status here
return Center(child: CircularProgressIndicator());
}
return GridView(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
primary: false,
shrinkWrap: true,
children: List<Widget>.generate(
snapshot.data.length, // same length as the data
(index) => Text(
snapshot.data[index].fullName, // Use the fullName property of each item
style: Theme.of(context)
.textTheme
.subtitle2
.copyWith(fontWeight: FontWeight.w600),
),
),
);
},
);

The getter was called on null

I am trying to display the list of hobbies of the user from firestore and I get the value from there as it gets print in console but not able to display it.
Error:-
The getter 'hobbies' was called on null.
Receiver: null
Tried calling: hobbies
Create account data is model class:-
Future<CreateAccountData> getUser() async {
final User user = auth.currentUser;
return _reference.doc(user.uid).get().then((m) => CreateAccountData.fromDocument(m));
}
getting data this way and it gets print also in console:-
List hobbies;
void initState() {
super.initState();
getUser().then((value) {
if (!mounted) return;
setState(() {
accountData = value;
hobbies = value.hobbies;
print("hobbies"+ hobbies.toString());
});
});
}
Error takes me to the line I commented:-
child:GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: accountData.hobbies.length, // Error take me to hobbies.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 5, crossAxisSpacing: 5,),
itemBuilder: (BuildContext context, int index){
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(accountData.hobbies[index]),
);
}
),
On suggestions updated to this(wrapped in future builder):-
child: FutureBuilder(
future: getUser(),
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
} if(snapshot.data.docs.isEmpty){
return Align(
alignment: FractionalOffset.centerLeft,
child: Text("Add what you love to do.....",textAlign: TextAlign.left,style: TextStyle(fontSize: 17),),
);
}
return GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: accountData?.hobbies?.length ?? 0,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 5,
crossAxisSpacing: 5,),
itemBuilder: (BuildContext context,
int index) {
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(accountData.hobbies[index]),
);
}
);
},
),
Now getting NoSuchMethodError error:-
Class 'CreateAccountData' has no instance getter 'docs'.
Receiver: Instance of 'CreateAccountData'
Tried calling: docs
check hobbies is null
itemCount: accountData?.hobbies?.length ?? 0,
In flutter 2.0, we have null safety. We need to check if value is null or not using an ! mark after the variable. I will post the code in a few minutes since Im in school rn
Wrap GridView.builder in a FutureBuilder passing getUser() as the future.
child: FutureBuilder(
future: getUser(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
if (snapshot.hasData)
return GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount:
snapshot.data.hobbies.length, // Error take me to hobbies.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 5,
crossAxisSpacing: 5,
),
itemBuilder: (BuildContext context, int index) {
//DocumentSnapshot interestList = snapshot.data.docs[index]['hobbies'];
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(snapshot.data.hobbies[index]),
);
});
return Text('No data.');
},
),