Implementing flutter ui - flutter

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

Related

How to use future builder in slivers in flutter

I want to display data from the api in the slivers using future builder with grid layouts. I tried but i could not do that.
Here is the code
slivers: [
SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 10,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 2.0,
),
)
],
I tried this way. but child count is the problem
SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, index) {
return FutureBuilder(
future: getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container(
child: Text(
'Hello',
),
);
},
);
},
childCount: 10,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 2.0,
),
)
get that future and build the delegate inside your FutureBuilder
FutureBuilder(
future:YourApi(),
builder:(_,snap){
if(snap.hasData){
//get your data , if its json, decode and make it into a class
List<T> data = snap.data .......
return ....(
slivers:[
SliverGrid(
......
,childCount: data.lenght
)
]
)
} else {}
}
)
You can directly use FutureBuilder inside slivers. just make sure the return widget is needed to be a sliver widget on every case.
body: CustomScrollView(
slivers: [
FutureBuilder<List<int>>(
/// create a future variable on state class
future: Future.delayed(Duration(seconds: 2))
.then((value) => List.generate(11, (i) => i)),
builder: (context, snapshot) {
if (snapshot.hasData) {
return SliverGrid(
delegate: SliverChildBuilderDelegate(
childCount: snapshot.data?.length,
(context, index) => Container(
child: Text("${snapshot.data?[index]}"),
),
),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2));
}
return const SliverToBoxAdapter(
child: CircularProgressIndicator(),
);
},
)
],
),

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

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

Change height of row in GridView builder to fixed height

I've noticed that GridView makes each child a square.. Is there any way to adjust height of each child which means entire row of GridView row in GridView.builder?
In this example I want to have each input next to each other.
List<Map<String, dynamic>> list = [
{'description': 'des1'},
{'description': 'des2'},
{'description': 'des3'},
{'description': 'des4'},
{'description': 'des5'},
{'description': 'des6'}
];
class _MaterialScreenState extends State<MaterialScreen> {
String text = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Text(text),
GridView.builder(
shrinkWrap: true,
itemCount: list.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5),
itemBuilder: (BuildContext context, int index) {
return TextFormField(
textAlign: TextAlign.center,
onTap: () => setState(() {
text = list[index]['description'];
}),
decoration: InputDecoration(border: OutlineInputBorder()),
);
}),
],
));
Problem:
Reason:
How about this?
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3,
),
Yoy can use "childAspectRatio".
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
childAspectRatio: 2,
),