Adding static element to gridview which is constructed by futurebuilder in flutter? - flutter

I am getting images using gridview and using futurebuilder. But I need to add one static photo.I replaced the photos from futurebuilder fine but also I want to add one photo which is static from outside of the futurebuilder.
This is how I want my gridview looks like:
I want to add this picture to gridview:
This is my code:
...
future: future,
builder: (ctx, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: Column(
children: [
Flexible(
flex: 5,
child: Container(
padding: EdgeInsets.only(
top: 40,
bottom: 1,
left: 40,
right: 40),
child: Consumer<Images>(
builder: (ctx, titles, ch) =>
GridView.builder(
physics: ScrollPhysics(),
itemCount: titles.items.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: getSize(
_currentSliderValue),
mainAxisSpacing: 50,
childAspectRatio: 115 / 162.05,
crossAxisSpacing: 5,
),
itemBuilder: (ctx, index) {
saveallimages(titles.items);
return GestureDetector(
onTap: () => add(titles
.items[index].image),
//()=>add(titles.items[index].image),
child: selected.contains(
titles.items[index]
.image.path
.toString())
? Container(
child: selectedimage(
titles
.items[
index]
.image))
: Container(
child: nonselected(
titles
.items[
index]
.image)));
}),
...

Increase itemCount by 1. In itemBuilder check if index == titles.items.length, and display your static item if so.

Related

flutter GridView.builder won't let rest of screen scroll

I have GridView.builder middle of my screen but it does not let my screen to scroll! I must find some white space in screen in order to be able to scroll rest of my screen.
Here is how my screen structure looks like:
Widget build(BuildContext context) {
return Scaffold(
appBar: const TopBarFile(),
drawer: const DrawerFile(),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: FutureBuilder(
future: myCards,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// some widgets...
const SizedBox(height: 15),
// here middle of screen is GridView
SizedBox(
child: GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
shrinkWrap: true,
itemCount: snapshot.data['cards'].length,
itemBuilder: (BuildContext context, int index) {
return InkWell(...);
}
)
),
const SizedBox(height: 15),
// some more widgets...
]
);
} else {...}
return container();
}
),
),
),
),
),
}
Note: this grid view only has 6 items so I don't need it to be scrollable actually I just use it for design purpose but its causing scrolling issue, so I just need to be able to scroll my page even if I'm touching on top of this grid view items.
Any suggestions?
you can define a physics property with NeverScrollableScrollPhysics() value inside GridView, this will solve the issue. Always use physics property When you have nested scrollable widget.
You can give physics: NeverScrollableScrollPhysics() to GridView() or use Wrap() widget instead of GridView().
Use physics and shrinkWrap property as below:
SizedBox(
child: GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.data['cards'].length,
itemBuilder: (BuildContext context, int index) {
return InkWell(...);
}
)
),

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 ---;
}
}

Add a seperator after a fixed number of widgets in a grid

I am displaying over 5000 images using GridView.Builder. I am fetching data from firebase realtime database. Initially I am fetching only 50 records but when the user reaches the bottom of grid list, I fetch another 50 records and so on. The code is working fine.
Now after every 200 images, I want to show a Container widget with height: 250 and width: MediaQuery.of(context).size.width. How do I do that?
StreamBuilder(
stream: listStream,
builder: (context, AsyncSnapshot<List<WatchFace>> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 1,
crossAxisSpacing: 1,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.3),
),
controller: _controller,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding:
const EdgeInsets.symmetric(vertical: 2, horizontal: 3),
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.pinkAccent, width: 0.8),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text('${snapshot.data[index].date}'), // Later I will display network image here.
),
),
);
});
}
},
),
This should work :
Wrap your item with Column(mainAxisSize: MainAxisSize.min)
Put this after the item :
if(index != 0 && index % 200 == 0)
YourContainer(),
EDIT : just remembered the GridView's childAspectRatio thing. It will force the size of every cell, so you can't add space. You might want to take a look at slivers

App crashes when loading networkimage in gridview

I am creating a gridview of images using future but during scrolling of gridview app crashes and there is not error but just
Lost connection to device.
Exited (sigterm)
the images reappear and disappear when scrolling up and down .
i have tried using image.network , cached network image , fadein image but not working . i have also limit my image request to 40 but also it crashes . image size are only 20-100 kb range .
// future function to load subcategory json
Future<subcategory> fetchallsubcategory() async {
final path = (await getApplicationDocumentsDirectory()).path;
final myDataResource = HttpNetworkResource(
url: serverurl +
"classes/subCategory?limit=40",
parser: (contents) => json.decode(contents),
headers: header,
cache: FileResource(File('$path/subcategoryall.json')),
maxAge: Duration(minutes: 10),
strategy: CacheStrategy.cacheFirst,
);
final myData = await myDataResource.get();
return subcategory.fromJson(myData);
}
//grid view
FutureBuilder(
future: fetchallsubcategory(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.hasData ? GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemCount: snapshot.data.results.length,
// padding: EdgeInsets.all(2.0),
// scrollDirection: Axis.horizontal,
itemBuilder: (context, int) {
return Card(
child:
CachedNetworkImage(imageUrl : snapshot.data.results[int].image),
);
}
) :CircularProgressIndicator();
},
)
I have created the same kind of app. I found NeverScrollableScrollPhysics() very helpful for scrollable image gridview. I hope the following code snippet helps you.
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Column(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
minHeight: 10, // Set as you want or you can remove it also.
maxHeight: double.infinity,
),
child: Container(
child: GridView.count(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 3
: 4,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
childAspectRatio: .6,
children: thumbUrls
.map((urlThumb) => Card(
child: Container(
decoration: BoxDecoration(color: Colors.white),
child: GestureDetector(
onTap: () => Navigator.push(context,
new MaterialPageRoute(
builder: (context) {
return new FullScreenImagePage(wallpapers[urlThumb]);//Map wallpaper = {url_thumb : [id, url_image]}
})),
child: new Image.network(
urlThumb,
fit: BoxFit.cover,
),
)),
))
.toList(),
),
),
)
],
),
],
);
}
}

Flutter remove space between GridView row

I am trying to create a gridview of raised buttons but there is a large amount of space between the rows of of the grid like this picture:
I am implementing the GridView with the code at the bottom of the page:
As you can see I set:
SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 150, mainAxisSpacing: 4, crossAxisSpacing: 4),
I would have expected that setting the main axis spacing and cross axis spacing should remove those spaces.
I also tried returning the gridview in a sized box and changing it to SliverGridWithFixedCount, but nothing seems to be changing it.
I am not sure what I have done incorrectly in the layout?
Thanks for your help
body: Column(
children: <Widget>[
Flexible(
child: filtersGridView(),
),
],
),
);
}
}
class filtersGridView extends StatefulWidget {
#override
_filtersGridViewState createState() => _filtersGridViewState();
}
class _filtersGridViewState extends State<filtersGridView> {
final List <DocumentSnapshot> documents;
_filtersGridViewState({this.documents});
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Firestore.instance.collection('categories').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: const Text('Loading events...'));
}
return GridView.builder(
gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 150, mainAxisSpacing: 4, crossAxisSpacing: 4),
itemBuilder: (BuildContext context, int index) {
return Column(children: <Widget>[
InkWell(
onTap: () {
},
child: SizedBox(
height: 30,
child: RaisedButton(
color: Colors.white,
child: Row(
children: <Widget>[
Text(snapshot.data.documents[index]['name'].toString(), textAlign: TextAlign.center, style: TextStyle(fontSize: 15, color: Colors.black,),),
],
),
If you are concerned about the padding inside of the buttons - it happens due to the minimum width setting of the material buttons being set to 88.
Also, in my experience I noticed that material buttons have some weird margin around them. I solved that with materialTapTargetSize: MaterialTapTargetSize.shrinkWrap.
ButtonTheme(
minWidth: 0,
height: 30,
child: RaisedButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
// ...
)
)
If you want the buttons to fill the entire maxCrossAxisExtent in height - use RawMaterialButton with custom constraints assigned.
Updated
I assumed the problem is within the buttons, but it just occurred to me that it is in fact about the GridView Delegate.
How SliverGridDelegateWithMaxCrossAxisExtent works as per Flutter docs:
This delegate creates grids with equally sized and spaced tiles.
The default value for childAspectRatio property of the delegate is 1.0, i.e. - a square. You are getting a perfectly logical layout displayed - grid of 1:1 blocks.
To solve this you need to come up with the right childAspectRatio value.
Some pseudocode: cellHeight = cellWidth / childAspectRatio.
e.g.
childAspectRatio: 2 will display cells sized as following:
2
-----------------
| |
| | 1
| |
-----------------
Please let me know if this helped.
Try this hope so it will work,
GridView.builder(
itemCount: 6,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Flex(
direction: Axis.vertical,
children: <Widget>[
Expanded(flex: 5, child: InkWell(
onTap: (){},
)),
Expanded(
flex: 5,
child: RaisedButton(
onPressed: () {},
child: Text('Bt'),
))
],
),
),
);
},
),
increase the childAspectRatio value to 2,
primary: false,
scrollDirection: Axis.vertical,
// padding: const EdgeInsets.all(10),
crossAxisSpacing: 10,
mainAxisSpacing: 10,
maxCrossAxisExtent: 180.0,
shrinkWrap: true,
childAspectRatio: 2,
children: <Widget>[
container(),
container(),
container(),
])