Flutter: Wrap multiple GridViews - flutter

In the case of two GridViews where the first has 1 item, and the second has 7 items:
// GridView 1
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: 1,
shrinkWrap: true,
physics: ScrollPhysics(),
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
itemBuilder: (BuildContext context, int index) {
return Container(...)
},
),
// GridView 2
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: 7,
shrinkWrap: true,
physics: ScrollPhysics(),
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
itemBuilder: (BuildContext context, int index) {
return Container(...)
},
),
Is it possible to wrap them so that the layout consists of 4 equal rows (2 items per row)? At the moment, the rows will consist of: 1 item, 2 items, 2 items, 2 items, 1 item.
I know it's possible to combine a list or map into one GridView - but in the case that you needed two separate GridViews (ie, unique styling), is the above possible?

you can save both items in List
List <dynamic> itemsList = [];
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: itemsList.length,
shrinkWrap: true,
physics: ScrollPhysics(),
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
itemBuilder: (BuildContext context, int index) {
return Container(...)
},
),

Related

how can I make a custom sort order in listview in flutter?

ListView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return ListView(
shrinkWrap: true,
physics: const ScrollPhysics(),
scrollDirection: Axis.vertical,
children: [
...carLogic.carsList.map((element) {
return carViewWidget(element, element.number);
}).toList(),
...melkLogic.melksList.map((element) {
return melkViewWidget(element, element.number);
}).toList()
],
);
},
),
You can add sort() function to your list:
ListView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return ListView(
shrinkWrap: true,
physics: const ScrollPhysics(),
scrollDirection: Axis.vertical,
children: [
...(carLogic.carsList..sort((prevCar, nextCar) => prevCar.id.compareTo(nextCar.id))).map((element) {
return carViewWidget(element, element.number);
}).toList(),
...(melkLogic.melksList..sort((prevMelk, nextMelk) => prevMelk.id.compareTo(nextMelk.id))).map((element) {
return melkViewWidget(element, element.number);
}).toList()
],
);
},
),
You can sort by any field in your classes, id here is just for example.
Also read documentration on sort() function

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');
}),
)

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.');
},
),

App crashes when load a lot of data inside a gridview

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];
},
),
);
},
);